mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 04:52:02 +02:00
19.0 vanilla
This commit is contained in:
parent
d1963a3c3a
commit
2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions
|
|
@ -116,7 +116,7 @@ test("can display client actions in Dialog and close the dialog", async () => {
|
|||
|
||||
expect(".modal .test_client_action").toHaveCount(1);
|
||||
expect(".modal-title").toHaveText("Dialog Test");
|
||||
await contains(".modal footer .btn.btn-primary").click();
|
||||
await contains(".modal .btn-close").click();
|
||||
expect(".modal .test_client_action").toHaveCount(0);
|
||||
});
|
||||
|
||||
|
|
@ -498,3 +498,27 @@ test("test home client action", async () => {
|
|||
await animationFrame();
|
||||
expect.verifySteps(["/web/webclient/version_info", "assign /"]);
|
||||
});
|
||||
|
||||
test("test display_exception client action", async () => {
|
||||
expect.errors(1);
|
||||
await mountWithCleanup(WebClient);
|
||||
getService("action").doAction({
|
||||
type: "ir.actions.client",
|
||||
tag: "display_exception",
|
||||
params: {
|
||||
code: 0,
|
||||
message: "Odoo Server Error",
|
||||
data: {
|
||||
name: `odoo.exceptions.UserError`,
|
||||
debug: "traceback",
|
||||
arguments: [],
|
||||
context: {},
|
||||
message: "This is an error",
|
||||
},
|
||||
},
|
||||
});
|
||||
await animationFrame();
|
||||
expect(".o_dialog").toHaveCount(1);
|
||||
expect("header .modal-title").toHaveText("Invalid Operation");
|
||||
expect.verifyErrors([/RPC_ERROR/]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,9 +15,10 @@ import {
|
|||
getKwArgs,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
|
||||
import { mockTouch, runAllTimers } from "@odoo/hoot-mock";
|
||||
import { animationFrame, mockTouch, runAllTimers } from "@odoo/hoot-mock";
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
import { router } from "@web/core/browser/router";
|
||||
import { router, routerBus } from "@web/core/browser/router";
|
||||
import { rpcBus } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
import { WebClient } from "@web/webclient/webclient";
|
||||
|
||||
|
|
@ -147,7 +148,6 @@ class ResUsersSettings extends WebResUsersSettings {
|
|||
} else {
|
||||
ResUsersSettingsEmbeddedAction.write(embeddedSettings.id, vals);
|
||||
}
|
||||
return embeddedSettings;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ defineModels([
|
|||
IrActionsAct_Window,
|
||||
]);
|
||||
|
||||
defineActions([
|
||||
const actions = [
|
||||
{
|
||||
id: 1,
|
||||
xml_id: "action_1",
|
||||
|
|
@ -264,10 +264,13 @@ defineActions([
|
|||
parent_action_id: 4,
|
||||
action_id: 4,
|
||||
},
|
||||
]);
|
||||
];
|
||||
|
||||
defineActions(actions);
|
||||
|
||||
beforeEach(() => {
|
||||
user.updateUserSettings("id", 1); // workaround to populate the user settings
|
||||
user.updateUserSettings("embedded_actions_config_ids", {}); // workaround to populate the embedded user settings
|
||||
});
|
||||
|
||||
test("can display embedded actions linked to the current action", async () => {
|
||||
|
|
@ -311,6 +314,14 @@ test("can toggle visibility of embedded actions", async () => {
|
|||
expect(".o_embedded_actions > button").toHaveCount(3, {
|
||||
message: "Should have 2 embedded actions in the embedded + the dropdown button",
|
||||
});
|
||||
expect(user.settings.embedded_actions_config_ids).toEqual({
|
||||
"1+": {
|
||||
embedded_actions_order: [],
|
||||
embedded_actions_visibility: [false, 102],
|
||||
embedded_visibility: true,
|
||||
res_model: "partner",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("can click on a embedded action and execute the corresponding action (with xml_id)", async () => {
|
||||
|
|
@ -441,6 +452,14 @@ test("a view coming from a embedded can be saved in the embedded actions", async
|
|||
expect(".o_embedded_actions > button").toHaveCount(4, {
|
||||
message: "Should have 2 embedded actions in the embedded + the dropdown button",
|
||||
});
|
||||
expect(user.settings.embedded_actions_config_ids).toEqual({
|
||||
"1+": {
|
||||
embedded_actions_order: [false, 102, 103, 4],
|
||||
embedded_actions_visibility: [false, 102, 4],
|
||||
embedded_visibility: true,
|
||||
res_model: "partner",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("a view coming from a embedded with python_method can be saved in the embedded actions", async () => {
|
||||
|
|
@ -499,6 +518,14 @@ test("a view coming from a embedded with python_method can be saved in the embed
|
|||
expect(".o_embedded_actions > button").toHaveCount(4, {
|
||||
message: "Should have 2 embedded actions in the embedded + the dropdown button",
|
||||
});
|
||||
expect(user.settings.embedded_actions_config_ids).toEqual({
|
||||
"1+": {
|
||||
embedded_actions_order: [false, 102, 103, 4],
|
||||
embedded_actions_visibility: [false, 103, 4],
|
||||
embedded_visibility: true,
|
||||
res_model: "partner",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("the embedded actions should not be displayed when switching view", async () => {
|
||||
|
|
@ -532,6 +559,14 @@ test("User can move the main (first) embedded action", async () => {
|
|||
expect(".o_embedded_actions > button:nth-child(2) > span").toHaveText("Partners Action 1", {
|
||||
message: "Main embedded action should've been moved to 2nd position",
|
||||
});
|
||||
expect(user.settings.embedded_actions_config_ids).toEqual({
|
||||
"1+": {
|
||||
embedded_actions_order: [102, false, 103],
|
||||
embedded_actions_visibility: [false, 102],
|
||||
embedded_visibility: true,
|
||||
res_model: "partner",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("User can unselect the main (first) embedded action", async () => {
|
||||
|
|
@ -548,6 +583,14 @@ test("User can unselect the main (first) embedded action", async () => {
|
|||
expect(dropdownItem).not.toHaveClass("selected", {
|
||||
message: "Main embedded action should be unselected",
|
||||
});
|
||||
expect(user.settings.embedded_actions_config_ids).toEqual({
|
||||
"1+": {
|
||||
embedded_actions_order: [],
|
||||
embedded_actions_visibility: [],
|
||||
embedded_visibility: true,
|
||||
res_model: "partner",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("User should be redirected to the first embedded action set in user settings", async () => {
|
||||
|
|
@ -636,3 +679,72 @@ test("custom embedded action loaded first", async () => {
|
|||
message: "'Favorite Ponies' view should be loaded",
|
||||
});
|
||||
});
|
||||
|
||||
test("test get_embedded_actions_settings rpc args", async () => {
|
||||
onRpc("res.users.settings", "get_embedded_actions_settings", ({ args, kwargs }) => {
|
||||
expect(args.length).toBe(1, {
|
||||
message: "Should have one positional argument, which is the id of the user setting.",
|
||||
});
|
||||
expect(args[0]).toBe(1, { message: "The id of the user setting should be 1." });
|
||||
expect(kwargs.context.res_id).toBe(5, {
|
||||
message: "The context should contain the res_id passed to the action.",
|
||||
});
|
||||
expect(kwargs.context.res_model).toBe("partner", {
|
||||
message: "The context should contain the res_model passed to the action.",
|
||||
});
|
||||
expect.step("get_embedded_actions_settings");
|
||||
});
|
||||
await mountWithCleanup(WebClient);
|
||||
await getService("action").doAction(1, {
|
||||
additionalContext: { active_id: 5 },
|
||||
});
|
||||
await contains(".o_control_panel_navigation > button > i.fa-sliders").click();
|
||||
expect.verifySteps(["get_embedded_actions_settings"]);
|
||||
});
|
||||
|
||||
test("an action containing embedded actions should reload if the page is refreshed", async () => {
|
||||
onRpc("create", ({ args }) => {
|
||||
const values = args[0][0];
|
||||
expect(values.name).toBe("Custom Partners Action 1");
|
||||
expect(values.action_id).toBe(1);
|
||||
// Add the created embedded action to the actions list so that the mock server knows it when reloading (/web/action/load)
|
||||
defineActions([
|
||||
...actions,
|
||||
{
|
||||
id: 4,
|
||||
name: "Custom Partners Action 1",
|
||||
parent_res_model: values.parent_res_model,
|
||||
type: "ir.embedded.actions",
|
||||
parent_action_id: 1,
|
||||
action_id: values.action_id,
|
||||
},
|
||||
]);
|
||||
return [4, values.name]; // Fake new embedded action id
|
||||
});
|
||||
onRpc(
|
||||
"create_filter",
|
||||
() => [5] // Fake new filter id
|
||||
);
|
||||
|
||||
await mountWithCleanup(WebClient);
|
||||
await getService("action").doAction(1);
|
||||
// First, we create a new (custom) embedded action based on the current one
|
||||
await contains(".o_control_panel_navigation > button > i.fa-sliders").click();
|
||||
await waitFor(".o_popover.dropdown-menu");
|
||||
await contains(".o_save_current_view ").click();
|
||||
await contains(".o_save_favorite ").click();
|
||||
expect(".o_embedded_actions > button").toHaveCount(3, {
|
||||
message: "Should have 2 embedded actions in the embedded + the dropdown button",
|
||||
});
|
||||
|
||||
// Emulate a hard refresh of the page
|
||||
rpcBus.trigger("CLEAR-CACHES", "/web/action/load");
|
||||
routerBus.trigger("ROUTE_CHANGE");
|
||||
await animationFrame();
|
||||
|
||||
// Check that the created embedded action is still there, as the reload should be done
|
||||
expect(".o_embedded_actions > button").toHaveCount(3, {
|
||||
message:
|
||||
"After refresh, we should still have 2 embedded actions in the embedded + the dropdown button",
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1869,7 +1869,9 @@ describe(`new urls`, () => {
|
|||
|
||||
await mountWebClient();
|
||||
await getService("action").doAction(100);
|
||||
await runAllTimers(); // wait for the router to be updated
|
||||
await contains(".o_data_cell").click();
|
||||
await runAllTimers(); // wait for the router to be updated
|
||||
await getService("action").doAction(200);
|
||||
expect.verifySteps(["/web/action/load", "/web/action/load"]);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import {
|
|||
import { animationFrame } from "@odoo/hoot-dom";
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
import { FormViewDialog } from "@web/views/view_dialogs/form_view_dialog";
|
||||
import { router } from "@web/core/browser/router";
|
||||
|
||||
class Partner extends models.Model {
|
||||
_name = "res.partner";
|
||||
|
|
@ -81,6 +82,17 @@ test("open record withtout the correct company (doAction)", async () => {
|
|||
});
|
||||
});
|
||||
|
||||
const _pushState = router.pushState;
|
||||
patchWithCleanup(router, {
|
||||
pushState: (state, options) => {
|
||||
expect(browser.location.href).toBe("https://www.hoot.test/");
|
||||
const res = _pushState(state, options);
|
||||
expect.step("pushState");
|
||||
expect(browser.location.href).toBe("http://example.com/odoo/res.partner/1");
|
||||
return res;
|
||||
},
|
||||
});
|
||||
|
||||
await mountWebClient();
|
||||
getService("action").doAction({
|
||||
type: "ir.actions.act_window",
|
||||
|
|
@ -90,7 +102,7 @@ test("open record withtout the correct company (doAction)", async () => {
|
|||
});
|
||||
await animationFrame();
|
||||
expect(cookie.get("cids")).toBe("1-2");
|
||||
expect.verifySteps(["reload"]);
|
||||
expect.verifySteps(["pushState", "reload"]);
|
||||
expect(browser.location.href).toBe("http://example.com/odoo/res.partner/1", {
|
||||
message: "url should contain the information of the doAction",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { afterEach, expect, test } from "@odoo/hoot";
|
||||
import { animationFrame, runAllTimers } from "@odoo/hoot-mock";
|
||||
import { waitFor } from "@odoo/hoot-dom";
|
||||
import {
|
||||
contains,
|
||||
defineActions,
|
||||
|
|
@ -349,6 +350,54 @@ test("can use custom handlers for report actions", async () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test("custom handlers can close modals", async () => {
|
||||
defineActions([
|
||||
{
|
||||
id: 5,
|
||||
name: "Create a Partner",
|
||||
res_model: "partner",
|
||||
target: "new",
|
||||
views: [[false, "form"]],
|
||||
},
|
||||
]);
|
||||
|
||||
patchWithCleanup(download, {
|
||||
_download: (options) => {
|
||||
expect.step(options.url);
|
||||
return Promise.resolve();
|
||||
},
|
||||
});
|
||||
|
||||
onRpc("/report/check_wkhtmltopdf", () => "ok");
|
||||
|
||||
await mountWithCleanup(WebClient);
|
||||
registry.category("ir.actions.report handlers").add("custom_handler", async (action) => {
|
||||
expect.step("calling custom handler for action " + action.id);
|
||||
return true;
|
||||
});
|
||||
|
||||
await getService("action").doAction(5);
|
||||
await waitFor(".o_technical_modal .o_form_view");
|
||||
expect(".o_technical_modal .o_form_view").toHaveCount(1, {
|
||||
message: "should have rendered a form view in a modal",
|
||||
});
|
||||
|
||||
await getService("action").doAction(7);
|
||||
expect(".o_technical_modal .o_form_view").toHaveCount(1, {
|
||||
message: "The modal should still exist",
|
||||
});
|
||||
|
||||
await getService("action").doAction(11);
|
||||
await animationFrame();
|
||||
expect(".o_technical_modal .o_form_view").toHaveCount(0, {
|
||||
message: "the modal should have been closed after the custom handler",
|
||||
});
|
||||
expect.verifySteps([
|
||||
"calling custom handler for action 7",
|
||||
"calling custom handler for action 11",
|
||||
]);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("context is correctly passed to the client action report", async (assert) => {
|
||||
patchWithCleanup(download, {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { expect, test } from "@odoo/hoot";
|
||||
import { animationFrame, press } from "@odoo/hoot-dom";
|
||||
import { Deferred } from "@odoo/hoot-mock";
|
||||
import {
|
||||
contains,
|
||||
|
|
@ -62,8 +63,9 @@ test("Barcode scanner crop overlay", async () => {
|
|||
|
||||
patchWithCleanup(BarcodeVideoScanner.prototype, {
|
||||
async isVideoReady() {
|
||||
await super.isVideoReady(...arguments);
|
||||
const result = await super.isVideoReady(...arguments);
|
||||
videoReady.resolve();
|
||||
return result;
|
||||
},
|
||||
onResize(overlayInfo) {
|
||||
expect.step(overlayInfo);
|
||||
|
|
@ -73,6 +75,7 @@ test("Barcode scanner crop overlay", async () => {
|
|||
|
||||
const firstBarcodeFound = scanBarcode(env);
|
||||
await videoReady;
|
||||
await animationFrame();
|
||||
await contains(".o_crop_icon").dragAndDrop(".o_crop_container", {
|
||||
relative: true,
|
||||
position: {
|
||||
|
|
@ -93,6 +96,7 @@ test("Barcode scanner crop overlay", async () => {
|
|||
|
||||
const secondBarcodeFound = scanBarcode(env);
|
||||
await videoReady;
|
||||
await animationFrame();
|
||||
const secondValueScanned = await secondBarcodeFound;
|
||||
expect(secondValueScanned).toBe(secondBarcodeValue, {
|
||||
message: `The detected barcode (${secondValueScanned}) should be the same as generated (${secondBarcodeValue})`,
|
||||
|
|
@ -135,3 +139,61 @@ test("BarcodeVideoScanner onReady props", async () => {
|
|||
});
|
||||
expect(await resolvedOnReadyPromise).toBe(true);
|
||||
});
|
||||
|
||||
test("Closing barcode scanner before camera loads should not throw an error", async () => {
|
||||
const env = await makeMockEnv();
|
||||
await mountWithCleanup(WebClient, { env });
|
||||
const cameraReady = new Deferred();
|
||||
|
||||
patchWithCleanup(browser.navigator, {
|
||||
mediaDevices: {
|
||||
async getUserMedia() {
|
||||
await cameraReady;
|
||||
const canvas = document.createElement("canvas");
|
||||
return canvas.captureStream();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
scanBarcode(env);
|
||||
|
||||
await animationFrame();
|
||||
expect(".o-barcode-modal").toHaveCount(1)
|
||||
|
||||
await press("escape");
|
||||
|
||||
await animationFrame();
|
||||
expect(".o-barcode-modal").toHaveCount(0)
|
||||
|
||||
cameraReady.resolve();
|
||||
|
||||
await animationFrame()
|
||||
expect(".o_error_dialog").toHaveCount(0)
|
||||
});
|
||||
|
||||
test("Closing barcode scanner while video is loading should not cause errors", async () => {
|
||||
const env = await makeMockEnv();
|
||||
await mountWithCleanup(WebClient, { env });
|
||||
|
||||
patchWithCleanup(browser.navigator, {
|
||||
mediaDevices: {
|
||||
async getUserMedia() {
|
||||
const canvas = document.createElement("canvas");
|
||||
return canvas.captureStream();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
scanBarcode(env);
|
||||
|
||||
await animationFrame();
|
||||
expect(".o-barcode-modal").toHaveCount(1)
|
||||
|
||||
await press("escape");
|
||||
|
||||
await animationFrame();
|
||||
expect(".o-barcode-modal").toHaveCount(0)
|
||||
|
||||
await animationFrame()
|
||||
expect(".o_error_dialog").toHaveCount(0)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -180,6 +180,87 @@ test("clickbot clickeverywhere test", async () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test("only one app", async () => {
|
||||
onRpc("has_group", () => true);
|
||||
mockDate("2017-10-08T15:35:11.000");
|
||||
const clickEverywhereDef = new Deferred();
|
||||
patchWithCleanup(browser.localStorage, {
|
||||
removeItem(key) {
|
||||
const savedState = super.getItem(key);
|
||||
expect.step("savedState: " + savedState);
|
||||
return super.removeItem(key);
|
||||
},
|
||||
});
|
||||
patchWithCleanup(browser, {
|
||||
console: {
|
||||
log: (msg) => {
|
||||
expect.step(msg);
|
||||
if (msg === SUCCESS_SIGNAL) {
|
||||
clickEverywhereDef.resolve();
|
||||
}
|
||||
},
|
||||
error: (msg) => {
|
||||
expect.step(msg);
|
||||
clickEverywhereDef.resolve();
|
||||
},
|
||||
},
|
||||
});
|
||||
defineMenus([
|
||||
{ id: 1, name: "App1", appID: 1, actionID: 1001, xmlid: "app1" },
|
||||
{
|
||||
id: 2,
|
||||
children: [
|
||||
{
|
||||
id: 3,
|
||||
name: "menu 1",
|
||||
appID: 2,
|
||||
actionID: 1002,
|
||||
xmlid: "app2_menu1",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "menu 2",
|
||||
appID: 2,
|
||||
actionID: 1022,
|
||||
xmlid: "app2_menu2",
|
||||
},
|
||||
],
|
||||
name: "App2",
|
||||
appID: 2,
|
||||
actionID: 1002,
|
||||
xmlid: "app2",
|
||||
},
|
||||
]);
|
||||
const webClient = await mountWithCleanup(WebClient);
|
||||
patchWithCleanup(odoo, {
|
||||
__WOWL_DEBUG__: { root: webClient },
|
||||
});
|
||||
window.clickEverywhere("app1");
|
||||
await clickEverywhereDef;
|
||||
expect.verifySteps([
|
||||
"Clicking on: apps menu toggle button",
|
||||
"Testing app menu: app1",
|
||||
"Testing menu App1 app1",
|
||||
'Clicking on: menu item "App1"',
|
||||
"Testing 2 filters",
|
||||
'Clicking on: filter "Not Bar"',
|
||||
'Clicking on: filter "Date"',
|
||||
'Clicking on: filter option "October"',
|
||||
"Testing view switch: kanban",
|
||||
"Clicking on: kanban view switcher",
|
||||
"Testing 2 filters",
|
||||
'Clicking on: filter "Not Bar"',
|
||||
'Clicking on: filter "Date"',
|
||||
'Clicking on: filter option "October"',
|
||||
"Successfully tested 1 apps",
|
||||
"Successfully tested 0 menus",
|
||||
"Successfully tested 0 modals",
|
||||
"Successfully tested 4 filters",
|
||||
SUCCESS_SIGNAL,
|
||||
'savedState: {"light":false,"studioCount":0,"testedApps":["app1"],"testedMenus":["app1"],"testedFilters":4,"testedModals":0,"appIndex":0,"menuIndex":0,"subMenuIndex":0,"xmlId":"app1","app":"app1"}',
|
||||
]);
|
||||
});
|
||||
|
||||
test("clickbot clickeverywhere test (with dropdown menu)", async () => {
|
||||
onRpc("has_group", () => true);
|
||||
mockDate("2017-10-08T15:35:11.000");
|
||||
|
|
@ -438,6 +519,7 @@ test("clickbot show rpc error when an error dialog is detected", async () => {
|
|||
debug: "traceback",
|
||||
arguments: [],
|
||||
context: {},
|
||||
message: "This is a server Error, it should be displayed in an error dialog",
|
||||
},
|
||||
exceptionName: "odoo.exceptions.Programming error",
|
||||
subType: "server",
|
||||
|
|
@ -457,7 +539,7 @@ test("clickbot show rpc error when an error dialog is detected", async () => {
|
|||
<button class="btn btn-link p-0">See technical details</button>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="modal-footer justify-content-around justify-content-md-start flex-wrap gap-1 w-100">
|
||||
<footer class="modal-footer d-empty-none justify-content-around justify-content-md-start flex-wrap gap-1 w-100">
|
||||
<button class="btn btn-primary o-default-button">Close</button>
|
||||
</footer>`
|
||||
.trim()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
contains,
|
||||
defineModels,
|
||||
editSelectMenu,
|
||||
getMockEnv,
|
||||
mountView,
|
||||
onRpc,
|
||||
serverState,
|
||||
|
|
@ -191,6 +192,7 @@ beforeEach(() => {
|
|||
description: false,
|
||||
group_ids: [1, 2],
|
||||
category_id: 121,
|
||||
placeholder: "No",
|
||||
},
|
||||
222: {
|
||||
id: 222,
|
||||
|
|
@ -198,6 +200,7 @@ beforeEach(() => {
|
|||
description: "Project access rights description",
|
||||
group_ids: [11, 12, 13],
|
||||
category_id: 221,
|
||||
placeholder: "View",
|
||||
},
|
||||
223: {
|
||||
id: 223,
|
||||
|
|
@ -273,6 +276,27 @@ test("simple rendering", async () => {
|
|||
expect(".o_group_info_button").toHaveCount(0); // not displayed in non debug mode
|
||||
});
|
||||
|
||||
test("simple rendering in readonly", async () => {
|
||||
await mountView({
|
||||
type: "form",
|
||||
arch: `
|
||||
<form edit="0">
|
||||
<sheet>
|
||||
<field name="group_ids" widget="res_user_group_ids"/>
|
||||
</sheet>
|
||||
</form>`,
|
||||
resModel: "res.users",
|
||||
resId: 1,
|
||||
});
|
||||
|
||||
expect(".o_field_widget[name=group_ids] input").toHaveCount(0);
|
||||
expect(queryAllTexts(".o_field_res_user_group_ids_privilege span")).toEqual([
|
||||
"Access Rights",
|
||||
"Project User",
|
||||
"",
|
||||
]);
|
||||
});
|
||||
|
||||
test("simple rendering (debug)", async () => {
|
||||
serverState.debug = "1";
|
||||
await mountView({
|
||||
|
|
@ -359,6 +383,34 @@ test("editing groups doesn't remove groups (debug)", async () => {
|
|||
expect.verifySteps(["web_save"]);
|
||||
});
|
||||
|
||||
test(`Click on "?" should not trigger a focus`, async () => {
|
||||
await mountView({
|
||||
type: "form",
|
||||
arch: `
|
||||
<form>
|
||||
<sheet>
|
||||
<field name="group_ids" widget="res_user_group_ids"/>
|
||||
</sheet>
|
||||
</form>`,
|
||||
resModel: "res.users",
|
||||
resId: 1,
|
||||
});
|
||||
|
||||
expect(`.o_form_label[for="field_222_0"] :contains("?")`).toHaveCount(1);
|
||||
await contains(`.o_form_label[for="field_222_0"] :contains("?")`).click();
|
||||
await runAllTimers();
|
||||
expect(".o-overlay-container .o-dropdown-item").toHaveCount(0);
|
||||
if (getMockEnv().isSmall) {
|
||||
expect(".o-overlay-container .o-tooltip").toHaveCount(1);
|
||||
} else {
|
||||
expect(".o-overlay-container .o-tooltip").toHaveCount(0);
|
||||
}
|
||||
await contains(`.o_form_label[for="field_222_0"]`).click();
|
||||
await runAllTimers();
|
||||
expect(".o-overlay-container .o-dropdown-item").toHaveCount(4);
|
||||
expect(".o-overlay-container .o-tooltip").toHaveCount(0);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test(`privilege tooltips`, async () => {
|
||||
await mountView({
|
||||
|
|
@ -522,7 +574,7 @@ test("implied groups: lower level groups no longer available", async () => {
|
|||
expect(".o_inner_group:eq(1) .o_select_menu").toHaveCount(2);
|
||||
await contains(queryFirst(".o_inner_group:eq(1) .o_wrap_input input")).click();
|
||||
expect(queryFirst(".o_inner_group:eq(1) .o_wrap_input input")).toHaveValue("Project User");
|
||||
expect(".o_select_menu_item").toHaveCount(3);
|
||||
expect(".o_select_menu_item").toHaveCount(4);
|
||||
expect(".o_inner_group:eq(1) .o_wrap_input:last-child input").toHaveValue("");
|
||||
await editSelectMenu(
|
||||
".o_field_widget[name='group_ids'] .o_inner_group:nth-child(2) .o_wrap_input:last-child input",
|
||||
|
|
@ -543,7 +595,7 @@ test("implied groups: lower level groups no longer available", async () => {
|
|||
|
||||
expect(queryFirst(".o_inner_group:eq(1) .o_wrap_input input")).toHaveValue("Project User");
|
||||
await contains(queryFirst(".o_inner_group:eq(1) .o_wrap_input input")).click();
|
||||
expect(".o_select_menu_item").toHaveCount(3);
|
||||
expect(".o_select_menu_item").toHaveCount(4);
|
||||
});
|
||||
|
||||
test("implied groups: lower level groups of same privilege still available", async () => {
|
||||
|
|
@ -560,7 +612,7 @@ test("implied groups: lower level groups of same privilege still available", asy
|
|||
resId: 1,
|
||||
});
|
||||
await contains(queryFirst(".o_inner_group:eq(1) .o_wrap_input input")).click();
|
||||
expect(".o_select_menu_item").toHaveCount(3);
|
||||
expect(".o_select_menu_item").toHaveCount(4);
|
||||
});
|
||||
|
||||
test("do not lose shadowed groups when editing", async () => {
|
||||
|
|
@ -738,3 +790,46 @@ test("privileges without category", async () => {
|
|||
await contains(`.o_form_button_save`).click();
|
||||
expect.verifySteps(["web_save"]);
|
||||
});
|
||||
|
||||
test("privileges with placeholder", async () => {
|
||||
ResUsers._records[0].group_ids = [];
|
||||
await mountView({
|
||||
type: "form",
|
||||
arch: `
|
||||
<form>
|
||||
<sheet>
|
||||
<field name="group_ids" widget="res_user_group_ids"/>
|
||||
</sheet>
|
||||
</form>`,
|
||||
resModel: "res.users",
|
||||
resId: 1,
|
||||
});
|
||||
|
||||
expect(queryAllValues(".o_select_menu_input")).toEqual(["No", "View", ""]);
|
||||
|
||||
await contains(".o_field_widget[name=group_ids] .o_inner_group:eq(1) input").click();
|
||||
expect(queryAllTexts(".o_select_menu_item")).toEqual([
|
||||
"View",
|
||||
"Project User",
|
||||
"Project Manager",
|
||||
"Project Administrator",
|
||||
]);
|
||||
|
||||
await contains(".o_field_widget[name=group_ids] .o_inner_group:eq(1) input:eq(1)").click();
|
||||
expect(`.o_select_menu_item`).toHaveCount(2);
|
||||
|
||||
await editSelectMenu(".o_field_widget[name=group_ids] .o_inner_group:eq(1) input:eq(1)", {
|
||||
value: "Helpdesk Administrator",
|
||||
});
|
||||
expect(queryAllValues(".o_select_menu_input")).toEqual(["No", "", "Helpdesk Administrator"]);
|
||||
expect(queryFirst(".o_inner_group:eq(1) .o_wrap_input input")).toHaveAttribute(
|
||||
"placeholder",
|
||||
"Project Manager"
|
||||
);
|
||||
|
||||
await contains(".o_field_widget[name=group_ids] .o_inner_group:eq(1) input").click();
|
||||
expect(queryAllTexts(".o_select_menu_item")).toEqual([
|
||||
"Project Manager",
|
||||
"Project Administrator",
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2083,7 +2083,7 @@ test("server actions are called with the correct context", async () => {
|
|||
|
||||
test("BinaryField is correctly rendered in Settings form view", async () => {
|
||||
onRpc("/web/content", async (request) => {
|
||||
const body = await request.text();
|
||||
const body = await request.formData();
|
||||
expect(body).toBeInstanceOf(FormData);
|
||||
expect(body.get("field")).toBe("file", {
|
||||
message: "we should download the field document",
|
||||
|
|
@ -2369,3 +2369,27 @@ test("settings search is accent-insensitive", async () => {
|
|||
await editSearch("àz");
|
||||
expect(queryAllTexts(".highlighter")).toEqual(["ÄZ", "áz"]);
|
||||
});
|
||||
|
||||
test("settings search does not highlight escaped characters when highlighting the searched text", async () => {
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "res.config.settings",
|
||||
arch: /* xml */ `
|
||||
<form string="Settings" class="oe_form_configuration o_base_settings" js_class="base_settings">
|
||||
<app string="CRM" name="crm">
|
||||
<block title="Research & Development">
|
||||
<setting help="This is Research & Development Settings">
|
||||
<field name="bar"/>
|
||||
<div>This test is to check whether & gets escaped during search or not.</div>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
</form>
|
||||
`,
|
||||
});
|
||||
|
||||
await editSearch("a");
|
||||
expect(queryAllTexts(".highlighter")).toEqual(["a", "a", "a", "a", "a"]);
|
||||
await editSearch("&");
|
||||
expect(queryAllTexts(".highlighter")).toEqual(["&", "&", "&"]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -644,3 +644,41 @@ test("de-select only changes visible companies", async () => {
|
|||
1
|
||||
);
|
||||
});
|
||||
|
||||
test("disallowed companies in between allowed companies are not enabled", async () => {
|
||||
cookie.set("cids", "3");
|
||||
serverState.companies = [
|
||||
{ id: 1, name: "Parent", sequence: 1, parent_id: false, child_ids: [2] },
|
||||
{ id: 2, name: "Child A", sequence: 2, parent_id: 1, child_ids: [3] },
|
||||
{ id: 3, name: "Child B", sequence: 3, parent_id: 2, child_ids: [] },
|
||||
];
|
||||
|
||||
patchWithCleanup(user.allowedCompanies, [serverState.companies[0], serverState.companies[2]]);
|
||||
|
||||
await createSwitchCompanyMenu();
|
||||
|
||||
/**
|
||||
* [ ] Parent
|
||||
* [ ] Child A
|
||||
* [x] Child B
|
||||
*/
|
||||
expect(user.activeCompanies.map((c) => c.id)).toEqual([3]);
|
||||
expect(user.activeCompany.id).toBe(3);
|
||||
await openCompanyMenu();
|
||||
expect("[data-company-id]").toHaveCount(3);
|
||||
expect("[data-company-id] .fa-check-square").toHaveCount(1);
|
||||
expect("[data-company-id] .fa-square-o").toHaveCount(2);
|
||||
|
||||
/**
|
||||
* [x] Parent -> toggle
|
||||
* [ ] Child A
|
||||
* [x] Child B
|
||||
*/
|
||||
await contains(".log_into:eq(0)").click();
|
||||
expect(cookie.get("cids")).toEqual("1-3");
|
||||
|
||||
await openCompanyMenu();
|
||||
await toggleCompany(0);
|
||||
expect("[data-company-id] .fa-check-square").toHaveCount(0);
|
||||
expect("[data-company-id] .fa-square-o").toHaveCount(3);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue