917 lines
30 KiB
JavaScript
917 lines
30 KiB
JavaScript
import { describe, expect, test } from "@odoo/hoot";
|
|
import { click, press, waitFor, delay } from "@odoo/hoot-dom";
|
|
import { animationFrame, Deferred } from "@odoo/hoot-mock";
|
|
import { Component, xml } from "@odoo/owl";
|
|
import {
|
|
contains,
|
|
defineActions,
|
|
defineMenus,
|
|
defineModels,
|
|
fields,
|
|
models,
|
|
getService,
|
|
mountWithCleanup,
|
|
onRpc,
|
|
patchWithCleanup,
|
|
serverState,
|
|
stepAllNetworkCalls,
|
|
} from "@web/../tests/web_test_helpers";
|
|
import { browser } from "@web/core/browser/browser";
|
|
import { user } from "@web/core/user";
|
|
import { WebClientEnterprise } from "@web_enterprise/webclient/webclient";
|
|
import { StudioClientAction } from "@web_studio/client_action/studio_client_action";
|
|
import { FormEditorCompiler } from "@web_studio/client_action/view_editor/editors/form/form_editor_compiler";
|
|
import { FormEditorRenderer } from "@web_studio/client_action/view_editor/editors/form/form_editor_renderer/form_editor_renderer";
|
|
import { ListEditorRenderer } from "@web_studio/client_action/view_editor/editors/list/list_editor_renderer";
|
|
import { ViewEditor } from "@web_studio/client_action/view_editor/view_editor";
|
|
import { defineStudioEnvironment } from "./studio_tests_context";
|
|
import { redirect } from "@web/core/utils/urls";
|
|
|
|
describe.current.tags("desktop");
|
|
|
|
serverState.debug = "1";
|
|
|
|
defineStudioEnvironment();
|
|
|
|
test("Studio not available for non system users", async () => {
|
|
patchWithCleanup(user, { isSystem: false });
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
expect(".o_main_navbar").toHaveCount(1);
|
|
expect(".o_main_navbar .o_web_studio_navbar_item button").toHaveCount(0);
|
|
});
|
|
|
|
test("Studio icon matches the clickbot selector", async () => {
|
|
// This test looks stupid, but if you ever need to adapt the selector,
|
|
// you must adapt it as well in the clickbot (in web), otherwise Studio
|
|
// might not be tested anymore by the click_everywhere test.
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
expect(".o_web_studio_navbar_item:not(.o_disabled) i").toHaveCount(1);
|
|
});
|
|
|
|
test("open Studio with act_window and viewType", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await contains(".o_menu_sections .o_nav_entry:nth-child(2)").click();
|
|
await animationFrame();
|
|
|
|
expect(".o_list_view").toHaveCount(1);
|
|
|
|
await click(".o_data_row .o_data_cell");
|
|
await animationFrame();
|
|
expect(".o_form_view").toHaveCount(1);
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_web_studio_editor_manager .o_web_studio_form_view_editor");
|
|
|
|
expect('.o_field_widget[name="name"]').toHaveText("Yop");
|
|
});
|
|
|
|
test("reload the studio view", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await waitFor(".o_kanban_view");
|
|
expect(".o_kanban_record:contains(Yop)").toHaveCount(1);
|
|
|
|
await click(".o_kanban_record");
|
|
await waitFor(".o_form_view");
|
|
expect(".o_field_char input").toHaveValue("Yop");
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
|
|
await getService("studio").reload();
|
|
await animationFrame();
|
|
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
expect(".o_form_view span:contains(Yop)").toHaveCount(1);
|
|
});
|
|
|
|
test("switch view and close Studio", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await waitFor(".o_kanban_record:contains(Yop)");
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
|
|
await click(".o_web_studio_menu .o_menu_sections button");
|
|
await waitFor(".o_web_studio_action_editor");
|
|
|
|
await click(".o_web_studio_views .o_web_studio_thumbnail_item.o_web_studio_thumbnail_list");
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
expect(".o_web_studio_list_view_editor").toHaveCount(1);
|
|
|
|
await click(".o_web_studio_leave");
|
|
await waitFor(".o_action_manager:first:not(:has(.o_studio))");
|
|
await waitFor(".o_list_view");
|
|
expect(".o_web_studio_editor_manager").toHaveCount(0);
|
|
});
|
|
|
|
test("navigation in Studio with act_window", async () => {
|
|
stepAllNetworkCalls();
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
expect(".o_home_menu").toHaveCount(1);
|
|
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await waitFor(".o_kanban_view");
|
|
|
|
expect.verifySteps([
|
|
"/web/webclient/translations",
|
|
"/web/webclient/load_menus",
|
|
"/mail/data",
|
|
"/web/action/load",
|
|
"get_views",
|
|
"web_search_read",
|
|
"has_group",
|
|
]);
|
|
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
await waitFor(".o_web_studio_editor_manager .o_web_studio_kanban_view_editor");
|
|
|
|
expect.verifySteps([
|
|
"studio_model_infos",
|
|
"get_views",
|
|
"/web_studio/get_studio_view_arch",
|
|
"web_search_read",
|
|
]);
|
|
|
|
expect(".o_kanban_record:contains(Yop)").toHaveCount(1);
|
|
|
|
await click(".o_studio_navbar .o_menu_toggle");
|
|
await waitFor(".o_studio_home_menu");
|
|
await click(".o_app[data-menu-xmlid=app_2]");
|
|
await waitFor(".o_list_view");
|
|
|
|
expect.verifySteps([
|
|
"/web/action/load",
|
|
"/web/action/load_breadcrumbs",
|
|
"studio_model_infos",
|
|
"get_views",
|
|
"/web_studio/get_studio_view_arch",
|
|
"web_search_read",
|
|
]);
|
|
|
|
await click(".o_web_studio_leave");
|
|
await waitFor(".o_action_manager:first:not(:has(.o_studio))");
|
|
await waitFor(".o_list_view");
|
|
expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]);
|
|
|
|
expect(".o_web_studio_editor_manager").toHaveCount(0);
|
|
});
|
|
|
|
test("keep action context when leaving Studio", async () => {
|
|
expect.assertions(2);
|
|
let nbLoadAction = 0;
|
|
onRpc("/web/action/load", async (request) => {
|
|
nbLoadAction++;
|
|
if (nbLoadAction === 3) {
|
|
const res = await request.json();
|
|
expect(res.params.context.active_id).toBe(1);
|
|
}
|
|
});
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await waitFor(".o_kanban_view");
|
|
|
|
await click(".o_nav_entry[data-menu-xmlid=menu_12]");
|
|
await waitFor(".o_list_view");
|
|
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
await waitFor(".o_web_studio_editor_manager .o_web_studio_list_view_editor");
|
|
|
|
await click(".o_web_studio_leave");
|
|
await waitFor(".o_action_manager:first:not(:has(.o_studio))");
|
|
await waitFor(".o_list_view");
|
|
|
|
expect(nbLoadAction).toBe(3);
|
|
});
|
|
|
|
test("user context is unpolluted when entering studio in error", async () => {
|
|
expect.errors(1);
|
|
patchWithCleanup(StudioClientAction.prototype, {
|
|
setup() {
|
|
throw new Error("Boom");
|
|
},
|
|
});
|
|
|
|
onRpc("partner", "get_views", ({ kwargs }) => {
|
|
const context = kwargs.context;
|
|
const options = kwargs.options;
|
|
expect.step(
|
|
`get_views, context studio: "${context.studio}", option studio: "${options.studio}"`
|
|
);
|
|
});
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await waitFor(".o_kanban_view");
|
|
expect.verifySteps([`get_views, context studio: "undefined", option studio: "undefined"`]);
|
|
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
expect(".o_web_studio_kanban_view_editor").toHaveCount(0);
|
|
expect(".o_kanban_view").toHaveCount(1);
|
|
expect.verifyErrors(["Boom"]);
|
|
|
|
await click(".o_nav_entry[data-menu-xmlid=menu_12]");
|
|
await waitFor(".o_list_view");
|
|
expect.verifySteps([`get_views, context studio: "undefined", option studio: "undefined"`]);
|
|
});
|
|
|
|
test("user context is not polluted when getting views", async () => {
|
|
onRpc("partner", "get_views", ({ kwargs }) => {
|
|
const context = kwargs.context;
|
|
const options = kwargs.options;
|
|
expect.step(
|
|
`get_views, context studio: "${context.studio}", option studio: "${options.studio}"`
|
|
);
|
|
});
|
|
|
|
onRpc("/web_studio/get_studio_action", async () => {
|
|
expect.step("get_studio_action");
|
|
return {
|
|
type: "ir.actions.act_window",
|
|
res_model: "partner",
|
|
views: [[false, "list"]],
|
|
context: { studio: 1 },
|
|
};
|
|
});
|
|
|
|
onRpc("web_search_read", ({ kwargs }) => {
|
|
expect.step(`web_search_read, context studio: "${kwargs.context.studio}"`);
|
|
});
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await waitFor(".o_kanban_view");
|
|
expect.verifySteps([
|
|
`get_views, context studio: "undefined", option studio: "undefined"`,
|
|
`web_search_read, context studio: "undefined"`,
|
|
]);
|
|
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
await waitFor(".o_web_studio_kanban_view_editor");
|
|
expect.verifySteps([
|
|
`get_views, context studio: "undefined", option studio: "true"`,
|
|
`web_search_read, context studio: "1"`,
|
|
]);
|
|
|
|
await contains(".o_menu_sections a[data-menu-xmlid=menu_12]").click();
|
|
await waitFor(".o_list_view");
|
|
expect.verifySteps([
|
|
`get_views, context studio: "undefined", option studio: "true"`,
|
|
`web_search_read, context studio: "1"`,
|
|
]);
|
|
|
|
await contains(".o_web_studio_menu .o_menu_sections button:contains(Automations)").click();
|
|
await waitFor(".o_web_studio_editor :not(.o_web_studio_view_renderer) .o_list_view");
|
|
expect.verifySteps([
|
|
"get_studio_action",
|
|
`get_views, context studio: "undefined", option studio: "undefined"`,
|
|
`web_search_read, context studio: "1"`,
|
|
]);
|
|
});
|
|
|
|
test("error bubbles up if first rendering", async () => {
|
|
expect.errors(1);
|
|
patchWithCleanup(ListEditorRenderer.prototype, {
|
|
setup() {
|
|
throw new Error("Boom");
|
|
},
|
|
});
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await waitFor(".o_kanban_view");
|
|
await contains(".o_menu_sections a[data-menu-xmlid=menu_12]").click();
|
|
await waitFor(".o_list_view");
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
await animationFrame();
|
|
|
|
expect.verifyErrors(["Boom"]);
|
|
});
|
|
|
|
test("error when new app's view is invalid", async () => {
|
|
expect.errors(1);
|
|
|
|
defineActions([
|
|
{
|
|
xmlid: "testAction",
|
|
id: 99,
|
|
type: "ir.actions.act_window",
|
|
res_model: "partner",
|
|
views: [[false, "list"]],
|
|
help: "",
|
|
name: "test action",
|
|
group_ids: [],
|
|
},
|
|
]);
|
|
|
|
defineMenus([
|
|
{
|
|
id: 99,
|
|
children: [],
|
|
actionID: 99,
|
|
xmlid: "testMenu",
|
|
name: "test",
|
|
appID: 99,
|
|
},
|
|
]);
|
|
|
|
onRpc("/web_studio/create_new_app", async () => ({ menu_id: 99, action_id: 99 }));
|
|
|
|
onRpc("/web_studio/get_studio_view_arch", async () => Promise.reject(new Error("Boom")));
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await contains(".o_web_studio_new_app").click();
|
|
await contains(".o_web_studio_app_creator_next").click();
|
|
await contains(".o_web_studio_app_creator_name input").edit("testApp");
|
|
await contains(".o_web_studio_app_creator_next").click();
|
|
await contains(".o_web_studio_menu_creator input").edit("testMenu");
|
|
await contains(".o_web_studio_model_configurator_next").click();
|
|
await waitFor(".o_web_studio_action_editor");
|
|
|
|
expect.verifyErrors(["Boom"]);
|
|
});
|
|
|
|
test("open same record when leaving form", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_2]");
|
|
await waitFor(".o_list_view");
|
|
|
|
await click(".o_data_row .o_data_cell:eq(1)");
|
|
await waitFor(".o_form_view");
|
|
|
|
expect(".o_form_view .o_field_widget[name=name] input").toHaveValue("Applejack");
|
|
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
await waitFor(".o_web_studio_editor_manager .o_web_studio_form_view_editor");
|
|
|
|
expect(".o_form_view .o_field_widget[data-studio-xpath='/form[1]/field[1]'] span").toHaveText(
|
|
"Applejack"
|
|
);
|
|
|
|
await click(".o_web_studio_leave");
|
|
await waitFor(".o_action_manager:first:not(:has(.o_studio))");
|
|
await waitFor(".o_form_view");
|
|
|
|
expect(".o_form_view .o_field_widget[name=name] input").toHaveValue("Applejack");
|
|
});
|
|
|
|
test("open Studio with non editable view", async () => {
|
|
onRpc("grid_unavailability", () => ({}));
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await waitFor(".o_kanban_view");
|
|
|
|
await click(".o_switch_view.o_grid");
|
|
await waitFor(".o_grid_view");
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_web_studio_action_editor");
|
|
});
|
|
|
|
test("open list view with sample data gives empty list view in studio", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_3]");
|
|
await waitFor(".o_list_view");
|
|
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
|
|
expect(".o_list_table .o_data_row").toHaveCount(0);
|
|
});
|
|
|
|
test("kanban in studio should always ignore sample data", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_3]");
|
|
await waitFor(".o_list_view");
|
|
|
|
await click(".o_switch_view.o_kanban");
|
|
await waitFor(".o_kanban_view");
|
|
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
|
|
expect(
|
|
".o_web_studio_kanban_view_editor .o_kanban_record:not(.o_kanban_ghost):not(.o_kanban_demo)"
|
|
).toHaveCount(1);
|
|
expect(".o_web_studio_kanban_view_editor .o_view_nocontent").toHaveCount(0);
|
|
});
|
|
|
|
test("entering a kanban keeps the user's domain", async () => {
|
|
onRpc("web_search_read", ({ kwargs, method }) => {
|
|
expect.step(`${method}: ${JSON.stringify(kwargs.domain)}`);
|
|
});
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
expect.verifySteps([]);
|
|
|
|
await click(".o_app[data-menu-xmlid=app_2]");
|
|
await waitFor(".o_list_view");
|
|
|
|
await click(".o_searchview_dropdown_toggler");
|
|
|
|
expect.verifySteps([`web_search_read: []`]);
|
|
|
|
await contains(".o_filter_menu .o_menu_item:contains(apple)").click();
|
|
await animationFrame();
|
|
|
|
expect.verifySteps([`web_search_read: [["name","ilike","Apple"]]`]);
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
|
|
expect.verifySteps([`web_search_read: [["name","ilike","Apple"]]`]);
|
|
|
|
expect(".o_list_table .o_data_row").toHaveCount(1);
|
|
});
|
|
|
|
test("open Studio with editable form view and check context propagation", async () => {
|
|
expect.assertions(4);
|
|
onRpc("pony", "onchange", ({ kwargs }) => {
|
|
expect(kwargs.context.default_name).toBe("foo");
|
|
});
|
|
onRpc("partner", "onchange", ({ kwargs }) => {
|
|
expect(kwargs.context).not.toInclude("default_name");
|
|
});
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_2]");
|
|
await contains(".o_list_button_add").click();
|
|
await waitFor(".o_form_view");
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
|
|
await click(".o_web_studio_form_view_editor .o_field_one2many");
|
|
await animationFrame();
|
|
|
|
await click(
|
|
`.o_web_studio_form_view_editor .o_field_one2many .o_web_studio_editX2Many[data-type="form"]`
|
|
);
|
|
await animationFrame();
|
|
|
|
expect(".o_web_studio_editor_manager .o_web_studio_form_view_editor").toHaveCount(1);
|
|
});
|
|
|
|
test("concurrency: execute a non editable action and try to enter studio", async () => {
|
|
const def = new Deferred();
|
|
|
|
const webClient = await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
expect(".o_home_menu").toHaveCount(1);
|
|
|
|
webClient.env.bus.addEventListener("ACTION_MANAGER:UI-UPDATED", () => {
|
|
expect(".o_list_view").toHaveCount(1);
|
|
expect(".o_web_studio_navbar_item.o_disabled").toHaveCount(1);
|
|
def.resolve();
|
|
});
|
|
|
|
await click(".o_app[data-menu-xmlid=app_4]");
|
|
await def;
|
|
expect(".o_list_view").toHaveCount(1);
|
|
expect(".o_web_studio_navbar_item.o_disabled").toHaveCount(1);
|
|
});
|
|
|
|
test("command palette inside studio", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_studio_home_menu");
|
|
|
|
await press("Space");
|
|
await animationFrame();
|
|
|
|
expect(".o_command_palette").toHaveCount(1);
|
|
await click(".o_command_palette .o_command");
|
|
await animationFrame();
|
|
|
|
expect(".o_studio_home_menu").toHaveCount(0);
|
|
expect(".o_studio .o_web_studio_kanban_view_editor").toHaveCount(1);
|
|
});
|
|
|
|
test("command palette inside studio with error", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_studio_home_menu");
|
|
|
|
await press(["S", "e", "t", "t"]);
|
|
await animationFrame();
|
|
await press("Enter");
|
|
await animationFrame();
|
|
expect("div.o_notification[role=alert]").toHaveCount(1);
|
|
});
|
|
|
|
test("leaving studio with a pending rendering in Studio", async () => {
|
|
const def = new Deferred();
|
|
let makeItWait = false;
|
|
|
|
let dummyclass = "first-pass";
|
|
class Dummy extends Component {
|
|
static template = xml`<div class="dummy" t-att-class="classes" />`;
|
|
static props = {};
|
|
get classes() {
|
|
return dummyclass;
|
|
}
|
|
}
|
|
|
|
patchWithCleanup(FormEditorRenderer, {
|
|
components: { ...FormEditorRenderer.components, Dummy },
|
|
});
|
|
|
|
patchWithCleanup(FormEditorCompiler.prototype, {
|
|
compile() {
|
|
const el = super.compile(...arguments);
|
|
el.querySelector(".o_form_renderer").append(el.ownerDocument.createElement("Dummy"));
|
|
return el;
|
|
},
|
|
});
|
|
|
|
let vem;
|
|
patchWithCleanup(ViewEditor.prototype, {
|
|
setup() {
|
|
super.setup();
|
|
vem = this;
|
|
},
|
|
});
|
|
|
|
onRpc("/web/action/load", async () => {
|
|
if (makeItWait) {
|
|
await def;
|
|
}
|
|
});
|
|
|
|
onRpc("web_read", (params) => {
|
|
if (makeItWait) {
|
|
return [{ id: params.args[0], size: "big" }];
|
|
}
|
|
});
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_2]");
|
|
await waitFor(".o_list_view");
|
|
|
|
await click(".o_data_cell");
|
|
await animationFrame();
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
|
|
expect(".dummy.first-pass").toHaveCount(1);
|
|
|
|
stepAllNetworkCalls();
|
|
makeItWait = true;
|
|
await click(".o_web_studio_leave");
|
|
dummyclass = "second-pass";
|
|
vem.viewEditorModel.fields.size.selection.push(["big", "Big"]);
|
|
await animationFrame();
|
|
expect(".dummy.second-pass").toHaveCount(1);
|
|
|
|
def.resolve();
|
|
await def;
|
|
await animationFrame();
|
|
expect(".o_web_studio_editor_manager").toHaveCount(0);
|
|
expect(".dummy").toHaveCount(0);
|
|
|
|
expect.verifySteps(["/web/action/load", "web_read", "get_views", "web_read"]);
|
|
});
|
|
|
|
test("auto-save feature works in studio (not editing a view)", async () => {
|
|
onRpc("/web_studio/get_studio_action", async () => ({
|
|
name: "Automated Actions",
|
|
type: "ir.actions.act_window",
|
|
res_model: "base.automation",
|
|
views: [
|
|
[false, "list"],
|
|
[false, "form"],
|
|
],
|
|
}));
|
|
|
|
onRpc("web_save", ({ args, model }) => {
|
|
expect.step(`web_save: ${model}: ${JSON.stringify(args)}`);
|
|
});
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await waitFor(".o_kanban_view");
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
|
|
await click(".o_menu_sections button:contains(Automations)");
|
|
await contains(".o_web_studio_editor .o_list_button_add").click();
|
|
await contains(".o_field_widget[name='name'] input").edit("created base automation");
|
|
await animationFrame();
|
|
|
|
await click(".o_web_studio_leave");
|
|
await waitFor(".o_action_manager:first:not(:has(.o_studio))");
|
|
await waitFor(".o_kanban_view");
|
|
|
|
expect.verifySteps(['web_save: base.automation: [[],{"name":"created base automation"}]']);
|
|
});
|
|
|
|
test("load with active_id active_ids", async () => {
|
|
expect.assertions(2);
|
|
onRpc("onchange", ({ kwargs }) => {
|
|
expect.step("onchange");
|
|
expect(kwargs.context).toEqual({
|
|
active_id: 1,
|
|
active_ids: [1],
|
|
allowed_company_ids: [1],
|
|
lang: "en",
|
|
studio: 1,
|
|
tz: "taht",
|
|
uid: 7,
|
|
});
|
|
});
|
|
|
|
browser.location.href = "/odoo/action-1/studio";
|
|
browser.location.search = "?mode=editor&_view_type=form&_tab=views&active_id=1";
|
|
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
expect.verifySteps(["onchange"]);
|
|
});
|
|
|
|
test("entering studio with active_id", async () => {
|
|
class Task extends models.Model {
|
|
project_id = fields.Many2one({ relation: "project" });
|
|
_records = [
|
|
{
|
|
id: 1,
|
|
display_name: "task1",
|
|
project_id: 1,
|
|
},
|
|
{
|
|
id: 2,
|
|
display_name: "task2",
|
|
project_id: 2,
|
|
},
|
|
];
|
|
_views = {
|
|
list: `<list>
|
|
<field name="display_name" />
|
|
<button name="1" type="action" string="somebutton" column_invisible="context.get('active_id') != 1" />
|
|
</list>`,
|
|
};
|
|
}
|
|
class Project extends models.Model {
|
|
task_ids = fields.One2many({ relation: "task" });
|
|
_records = [
|
|
{
|
|
id: 1,
|
|
display_name: "paul bismuth",
|
|
},
|
|
{
|
|
id: 2,
|
|
display_name: "la santé",
|
|
},
|
|
];
|
|
|
|
_views = {
|
|
list: `<list><field name="display_name" /></list>`,
|
|
};
|
|
}
|
|
defineModels([Project, Task]);
|
|
defineActions([
|
|
{
|
|
xml_id: "action_active_id_project",
|
|
id: 1,
|
|
type: "ir.actions.act_window",
|
|
res_model: "project",
|
|
name: "Projects",
|
|
target: "main",
|
|
views: [
|
|
[false, "list"],
|
|
[false, "form"],
|
|
],
|
|
},
|
|
{
|
|
xml_id: "action_active_id_task",
|
|
id: 2,
|
|
type: "ir.actions.act_window",
|
|
res_model: "task",
|
|
name: "Tasks",
|
|
target: "current",
|
|
views: [
|
|
[false, "list"],
|
|
[false, "form"],
|
|
],
|
|
domain: `[["project_id", "=", active_id]]`,
|
|
},
|
|
]);
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await waitFor(".o_home_menu");
|
|
await animationFrame(); // wait for url to be pushed
|
|
expect(browser.location.href).toBe("https://www.hoot.test/odoo");
|
|
|
|
await getService("action").doAction("action_active_id_project");
|
|
await waitFor(".o_list_view .o_last_breadcrumb_item:contains(Projects)");
|
|
expect(".o_list_view button:contains(somebutton)").toHaveCount(0);
|
|
await animationFrame();
|
|
expect(browser.location.href).toBe("https://www.hoot.test/odoo/action-1");
|
|
|
|
await getService("action").doAction("action_active_id_task", {
|
|
additionalContext: { active_id: 1 },
|
|
});
|
|
await waitFor(".o_list_view .o_last_breadcrumb_item:contains(Tasks)");
|
|
expect(".o_list_view button:contains(somebutton)").toHaveCount(1);
|
|
await animationFrame();
|
|
expect(".o_breadcrumb").toHaveText("Projects\nTasks");
|
|
expect(browser.location.href).toBe("https://www.hoot.test/odoo/action-1/1/action-2");
|
|
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
expect(".o_list_view button:contains(somebutton)").toHaveCount(1);
|
|
|
|
await animationFrame();
|
|
expect(browser.location.href).toBe(
|
|
"https://www.hoot.test/odoo/action-1/1/action-2/studio?mode=editor&_tab=views&_view_type=list"
|
|
);
|
|
|
|
redirect("/odoo/action-1/1/action-2");
|
|
browser.dispatchEvent(new PopStateEvent("popstate", { state: {} }));
|
|
await waitFor(".o_list_view:not(.o_studio .o_list_view)");
|
|
expect(".o_list_view button:contains(somebutton)").toHaveCount(1);
|
|
|
|
await animationFrame();
|
|
expect(browser.location.href).toBe("https://www.hoot.test/odoo/action-1/1/action-2");
|
|
|
|
redirect("/odoo/action-1/1/action-2/studio?mode=editor&_tab=views&_view_type=list");
|
|
browser.dispatchEvent(new PopStateEvent("popstate", { state: {} }));
|
|
await waitFor(".o_studio .o_list_view");
|
|
expect(".o_list_view button:contains(somebutton)").toHaveCount(1);
|
|
|
|
await animationFrame();
|
|
expect(browser.location.href).toBe(
|
|
"https://www.hoot.test/odoo/action-1/1/action-2/studio?mode=editor&_tab=views&_view_type=list"
|
|
);
|
|
});
|
|
|
|
test("can edit ir.actions.act_window without id", async () => {
|
|
onRpc("get_formview_action", ({ args }) => ({
|
|
type: "ir.actions.act_window",
|
|
res_model: "pony",
|
|
target: "current",
|
|
views: [[false, "form"]],
|
|
res_id: args[0][0],
|
|
}));
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await click(".o_app[data-menu-xmlid=app_1]");
|
|
await contains(".o_kanban_view .o_kanban_record:not(.o_kanban_ghost)").click();
|
|
await animationFrame();
|
|
await click(".o_form_view .o_field_many2one_selection input");
|
|
await click(".o_form_view .o_field_many2one_selection .o_external_button");
|
|
await animationFrame();
|
|
expect(".breadcrumb-item a:contains(Yop)").toHaveCount(1);
|
|
await click(".o_web_studio_navbar_item button");
|
|
await waitFor(".o_web_studio_editor_manager");
|
|
|
|
expect(".o_field_widget[name='name']").toHaveText("Rainbow Dash");
|
|
expect(browser.location.pathname).toBe("/odoo/action-1/1/m-pony/1/studio");
|
|
expect(browser.location.search).toBe("?mode=editor&_tab=views&_view_type=form");
|
|
|
|
await click(".o_menu_sections button:contains(Views)");
|
|
await animationFrame();
|
|
expect(
|
|
".o_web_studio_thumbnail_item:not(.disabled.pe-none):has(img[alt='View Form'])"
|
|
).toHaveCount(1);
|
|
expect(".o_web_studio_thumbnail_item.pe-none").toHaveCount(10);
|
|
|
|
await click(".o_web_studio_leave");
|
|
await waitFor(".o_action_manager:first:not(:has(.o_studio))");
|
|
await waitFor(".o_form_view");
|
|
// The router pushes its state just after a setTimeout
|
|
await delay(0);
|
|
|
|
expect(".o_form_view .o_field_widget[name='name'] input").toHaveValue("Rainbow Dash");
|
|
expect(".o_breadcrumb").toHaveText("partner Action\nYop\nRainbow Dash");
|
|
expect(browser.location.pathname).toBe("/odoo/action-1/1/m-pony/1");
|
|
expect(browser.location.search).toBe(""); // no view type in search means the default view type of the action is taken
|
|
});
|
|
|
|
test("enter and leave with multirecord view (invalid to load)", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await getService("action").doAction({
|
|
type: "ir.actions.act_window",
|
|
views: [[false, "pivot"]],
|
|
res_model: "partner",
|
|
display_name: "some dynamic action",
|
|
});
|
|
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
expect(".o_web_studio_view_renderer .o_pivot_view").toHaveCount(1);
|
|
|
|
await contains(".o_web_studio_leave").click();
|
|
await waitFor(".o_action_manager:first:not(:has(.o_studio))");
|
|
await waitFor(".o_home_menu");
|
|
expect(".o_main_navbar .o_menu_toggle").toHaveCount(0);
|
|
expect(".o_studio").toHaveCount(0);
|
|
expect(".o_menu_toggle_back").toHaveCount(0);
|
|
});
|
|
|
|
test("enter and leave on home menu with multirecord view (invalid to load)", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await getService("action").doAction({
|
|
type: "ir.actions.act_window",
|
|
views: [[false, "pivot"]],
|
|
res_model: "partner",
|
|
display_name: "some dynamic action",
|
|
});
|
|
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
expect(".o_web_studio_view_renderer .o_pivot_view").toHaveCount(1);
|
|
|
|
await contains(".o_studio_navbar .o_menu_toggle").click();
|
|
expect(".o_studio .o_home_menu").toHaveCount(1);
|
|
|
|
await contains(".o_web_studio_leave").click();
|
|
await waitFor(".o_action_manager:first:not(:has(.o_studio))");
|
|
await waitFor(".o_home_menu");
|
|
expect(".o_main_navbar .o_menu_toggle").toHaveCount(0);
|
|
expect(".o_studio").toHaveCount(0);
|
|
expect(".o_menu_toggle_back").toHaveCount(0);
|
|
});
|
|
|
|
test("enter and leave on home menu with multirecord view (invalid to load) and a valid one", async () => {
|
|
await mountWithCleanup(WebClientEnterprise);
|
|
await animationFrame();
|
|
|
|
await getService("action").doAction({
|
|
type: "ir.actions.act_window",
|
|
views: [[false, "form"]],
|
|
res_model: "partner",
|
|
display_name: "some dynamic action",
|
|
});
|
|
await waitFor(".o_form_view");
|
|
|
|
await getService("action").doAction({
|
|
type: "ir.actions.act_window",
|
|
views: [[false, "pivot"]],
|
|
res_model: "partner",
|
|
display_name: "some dynamic action",
|
|
});
|
|
|
|
await contains(".o_web_studio_navbar_item button").click();
|
|
expect(".o_web_studio_view_renderer .o_pivot_view").toHaveCount(1);
|
|
|
|
await contains(".o_studio_navbar .o_menu_toggle").click();
|
|
expect(".o_studio .o_home_menu").toHaveCount(1);
|
|
|
|
await contains(".o_web_studio_leave").click();
|
|
await waitFor(".o_action_manager:first:not(:has(.o_studio))");
|
|
await waitFor(".o_home_menu");
|
|
expect(".o_studio").toHaveCount(0);
|
|
await contains(".o_menu_toggle_back").click();
|
|
expect(".o_form_view").toHaveCount(1);
|
|
});
|