Have a legacy list view, click on a record to open it in a new (WOWL) form view Before this commit, the pager was wrong, as we never passed the list's current resIds to the form. After this commit, the pager of the wowl form view is correct. closes odoo/odoo#96123 Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
777 lines
28 KiB
JavaScript
777 lines
28 KiB
JavaScript
/** @odoo-module **/
|
|
|
|
import { registry } from "@web/core/registry";
|
|
import testUtils from "web.test_utils";
|
|
import ListController from "web.ListController";
|
|
import FormView from "web.FormView";
|
|
import ListView from "web.ListView";
|
|
import {
|
|
click,
|
|
destroy,
|
|
getFixture,
|
|
makeDeferred,
|
|
legacyExtraNextTick,
|
|
patchWithCleanup,
|
|
triggerEvents,
|
|
} from "../../helpers/utils";
|
|
import KanbanView from "web.KanbanView";
|
|
import { registerCleanup } from "../../helpers/cleanup";
|
|
import { makeTestEnv } from "../../helpers/mock_env";
|
|
import { createWebClient, doAction, getActionManagerServerData } from "./../helpers";
|
|
import makeTestEnvironment from "web.test_env";
|
|
|
|
import { ClientActionAdapter, ViewAdapter } from "@web/legacy/action_adapters";
|
|
import { makeLegacyCrashManagerService } from "@web/legacy/utils";
|
|
import { useDebugCategory } from "@web/core/debug/debug_context";
|
|
import { ErrorDialog } from "@web/core/errors/error_dialogs";
|
|
import * as cpHelpers from "@web/../tests/search/helpers";
|
|
|
|
import AbstractView from "web.AbstractView";
|
|
import ControlPanel from "web.ControlPanel";
|
|
import core from "web.core";
|
|
import AbstractAction from "web.AbstractAction";
|
|
import Widget from "web.Widget";
|
|
import SystrayMenu from "web.SystrayMenu";
|
|
import legacyViewRegistry from "web.view_registry";
|
|
|
|
let serverData;
|
|
let target;
|
|
|
|
QUnit.module("ActionManager", (hooks) => {
|
|
hooks.beforeEach(() => {
|
|
registry.category("views").remove("form"); // remove new form from registry
|
|
registry.category("views").remove("kanban"); // remove new kanban from registry
|
|
registry.category("views").remove("list"); // remove new list from registry
|
|
legacyViewRegistry.add("form", FormView); // add legacy form -> will be wrapped and added to new registry
|
|
legacyViewRegistry.add("kanban", KanbanView); // add legacy kanban -> will be wrapped and added to new registry
|
|
legacyViewRegistry.add("list", ListView); // add legacy list -> will be wrapped and added to new registry
|
|
|
|
serverData = getActionManagerServerData();
|
|
target = getFixture();
|
|
});
|
|
|
|
QUnit.module("Legacy tests (to eventually drop)");
|
|
|
|
QUnit.test("display warning as notification", async function (assert) {
|
|
// this test can be removed as soon as the legacy layer is dropped
|
|
assert.expect(5);
|
|
let list;
|
|
patchWithCleanup(ListController.prototype, {
|
|
init() {
|
|
this._super(...arguments);
|
|
list = this;
|
|
},
|
|
});
|
|
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, 3);
|
|
assert.containsOnce(target, ".o_legacy_list_view");
|
|
list.trigger_up("warning", {
|
|
title: "Warning!!!",
|
|
message: "This is a warning...",
|
|
});
|
|
await testUtils.nextTick();
|
|
await legacyExtraNextTick();
|
|
assert.containsOnce(target, ".o_legacy_list_view");
|
|
assert.containsOnce(document.body, ".o_notification.border-warning");
|
|
assert.strictEqual($(".o_notification_title").text(), "Warning!!!");
|
|
assert.strictEqual($(".o_notification_content").text(), "This is a warning...");
|
|
});
|
|
|
|
QUnit.test("display warning as modal", async function (assert) {
|
|
// this test can be removed as soon as the legacy layer is dropped
|
|
assert.expect(5);
|
|
let list;
|
|
patchWithCleanup(ListController.prototype, {
|
|
init() {
|
|
this._super(...arguments);
|
|
list = this;
|
|
},
|
|
});
|
|
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, 3);
|
|
assert.containsOnce(target, ".o_legacy_list_view");
|
|
list.trigger_up("warning", {
|
|
title: "Warning!!!",
|
|
message: "This is a warning...",
|
|
type: "dialog",
|
|
});
|
|
await testUtils.nextTick();
|
|
await legacyExtraNextTick();
|
|
assert.containsOnce(target, ".o_legacy_list_view");
|
|
assert.containsOnce(document.body, ".modal");
|
|
assert.strictEqual($(".modal-title").text(), "Warning!!!");
|
|
assert.strictEqual($(".modal-body").text(), "This is a warning...");
|
|
});
|
|
|
|
QUnit.test("display multiline warning as modal", async function (assert) {
|
|
assert.expect(5);
|
|
let list;
|
|
patchWithCleanup(ListController.prototype, {
|
|
init() {
|
|
this._super(...arguments);
|
|
list = this;
|
|
},
|
|
});
|
|
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, 3);
|
|
assert.containsOnce(target, ".o_legacy_list_view");
|
|
list.trigger_up("warning", {
|
|
title: "Warning!!!",
|
|
message: "This is a warning...\nabc",
|
|
type: "dialog",
|
|
});
|
|
await testUtils.nextTick();
|
|
await legacyExtraNextTick();
|
|
assert.containsOnce(target, ".o_legacy_list_view");
|
|
assert.containsOnce(document.body, ".modal");
|
|
assert.strictEqual($(".modal-title").text(), "Warning!!!");
|
|
assert.strictEqual($(".modal-body")[0].innerText, "This is a warning...\nabc");
|
|
});
|
|
|
|
QUnit.test(
|
|
"legacy crash manager is still properly remapped to error service",
|
|
async function (assert) {
|
|
// this test can be removed as soon as the legacy layer is dropped
|
|
assert.expect(2);
|
|
|
|
const legacyEnv = makeTestEnvironment();
|
|
registry
|
|
.category("services")
|
|
.add("legacy_crash_manager", makeLegacyCrashManagerService(legacyEnv))
|
|
.add("dialog", {
|
|
start() {
|
|
return {
|
|
add(dialogClass, props) {
|
|
assert.strictEqual(dialogClass, ErrorDialog);
|
|
assert.strictEqual(props.traceback, "BOOM");
|
|
},
|
|
};
|
|
},
|
|
});
|
|
await makeTestEnv();
|
|
legacyEnv.services.crash_manager.show_message("BOOM");
|
|
}
|
|
);
|
|
|
|
QUnit.test("redraw a controller and open debugManager does not crash", async (assert) => {
|
|
assert.expect(11);
|
|
|
|
const LegacyAction = AbstractAction.extend({
|
|
start() {
|
|
const ret = this._super(...arguments);
|
|
const el = document.createElement("div");
|
|
el.classList.add("custom-action");
|
|
this.el.append(el);
|
|
return ret;
|
|
},
|
|
});
|
|
core.action_registry.add("customLegacy", LegacyAction);
|
|
|
|
patchWithCleanup(ClientActionAdapter.prototype, {
|
|
setup() {
|
|
useDebugCategory("custom", { widget: this });
|
|
this._super();
|
|
},
|
|
});
|
|
|
|
registry
|
|
.category("debug")
|
|
.category("custom")
|
|
.add("item1", ({ widget }) => {
|
|
assert.step("debugItems executed");
|
|
assert.ok(widget);
|
|
return {};
|
|
});
|
|
patchWithCleanup(odoo, { debug: true });
|
|
|
|
const mockRPC = (route) => {
|
|
if (route.includes("check_access_rights")) {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
const webClient = await createWebClient({ serverData, mockRPC });
|
|
await doAction(webClient, "customLegacy");
|
|
assert.containsOnce(target, ".custom-action");
|
|
assert.verifySteps([]);
|
|
|
|
await click(target, ".o_debug_manager button");
|
|
assert.verifySteps(["debugItems executed"]);
|
|
|
|
await doAction(webClient, 5); // action in Dialog
|
|
await click(target, ".modal .o_form_button_cancel");
|
|
assert.containsNone(target, ".modal");
|
|
assert.containsOnce(target, ".custom-action");
|
|
assert.verifySteps([]);
|
|
|
|
// close debug menu
|
|
await click(target, ".o_debug_manager button");
|
|
// open debug menu
|
|
await click(target, ".o_debug_manager button");
|
|
assert.verifySteps(["debugItems executed"]);
|
|
delete core.action_registry.map.customLegacy;
|
|
});
|
|
|
|
QUnit.test("willUnmount is called down the legacy layers", async (assert) => {
|
|
assert.expect(7);
|
|
|
|
let mountCount = 0;
|
|
patchWithCleanup(ControlPanel.prototype, {
|
|
setup() {
|
|
this._super();
|
|
owl.onMounted(() => {
|
|
mountCount = mountCount + 1;
|
|
this.__uniqueId = mountCount;
|
|
assert.step(`mounted ${this.__uniqueId}`);
|
|
});
|
|
owl.onWillUnmount(() => {
|
|
assert.step(`willUnmount ${this.__uniqueId}`);
|
|
});
|
|
},
|
|
});
|
|
|
|
const LegacyAction = AbstractAction.extend({
|
|
hasControlPanel: true,
|
|
start() {
|
|
const ret = this._super(...arguments);
|
|
const el = document.createElement("div");
|
|
el.classList.add("custom-action");
|
|
this.el.append(el);
|
|
return ret;
|
|
},
|
|
});
|
|
core.action_registry.add("customLegacy", LegacyAction);
|
|
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, 1);
|
|
await doAction(webClient, "customLegacy");
|
|
await click(target.querySelectorAll(".breadcrumb-item")[0]);
|
|
await legacyExtraNextTick();
|
|
|
|
destroy(webClient);
|
|
|
|
assert.verifySteps([
|
|
"mounted 1",
|
|
"willUnmount 1",
|
|
"mounted 2",
|
|
"willUnmount 2",
|
|
"mounted 3",
|
|
"willUnmount 3",
|
|
]);
|
|
|
|
delete core.action_registry.map.customLegacy;
|
|
});
|
|
|
|
QUnit.test("Checks the availability of all views in the action", async (assert) => {
|
|
assert.expect(2);
|
|
patchWithCleanup(ListView.prototype, {
|
|
init(viewInfo, params) {
|
|
const action = params.action;
|
|
const views = action.views.map((view) => [view.viewID, view.type]);
|
|
assert.deepEqual(views, [
|
|
[1, "list"],
|
|
[2, "kanban"],
|
|
[3, "form"],
|
|
]);
|
|
assert.deepEqual(action._views, [
|
|
[1, "list"],
|
|
[2, "kanban"],
|
|
[3, "form"],
|
|
[false, "search"],
|
|
]);
|
|
this._super(...arguments);
|
|
},
|
|
});
|
|
const models = {
|
|
partner: {
|
|
fields: {
|
|
display_name: { string: "Displayed name", type: "char", searchable: true },
|
|
foo: {
|
|
string: "Foo",
|
|
type: "char",
|
|
default: "My little Foo Value",
|
|
searchable: true,
|
|
},
|
|
bar: { string: "Bar", type: "boolean" },
|
|
int_field: { string: "Integer field", type: "integer", group_operator: "sum" },
|
|
},
|
|
records: [
|
|
{
|
|
id: 1,
|
|
display_name: "first record",
|
|
foo: "yop",
|
|
int_field: 3,
|
|
},
|
|
{
|
|
id: 2,
|
|
display_name: "second record",
|
|
foo: "lalala",
|
|
int_field: 5,
|
|
},
|
|
{
|
|
id: 4,
|
|
display_name: "aaa",
|
|
foo: "abc",
|
|
int_field: 2,
|
|
},
|
|
],
|
|
},
|
|
};
|
|
const views = {
|
|
"partner,1,list": '<list><field name="foo"/></list>',
|
|
"partner,2,kanban": "<kanban></kanban>",
|
|
"partner,3,form": `<form></form>`,
|
|
"partner,false,search": "<search></search>",
|
|
};
|
|
const serverData = { models, views };
|
|
|
|
const webClient = await createWebClient({ serverData });
|
|
|
|
await doAction(webClient, {
|
|
id: 1,
|
|
res_model: "partner",
|
|
type: "ir.actions.act_window",
|
|
views: [
|
|
[1, "list"],
|
|
[2, "kanban"],
|
|
[3, "form"],
|
|
],
|
|
});
|
|
});
|
|
|
|
QUnit.test("client actions may take and push their params", async function (assert) {
|
|
assert.expect(2);
|
|
|
|
const ClientAction = AbstractAction.extend({
|
|
init(parent, action) {
|
|
this._super(...arguments);
|
|
assert.deepEqual(action.params, {
|
|
active_id: 99,
|
|
take: "five",
|
|
active_ids: "1,2",
|
|
list: [9, 10],
|
|
});
|
|
},
|
|
});
|
|
core.action_registry.add("clientAction", ClientAction);
|
|
registerCleanup(() => delete core.action_registry.map.clientAction);
|
|
const webClient = await createWebClient({});
|
|
|
|
await doAction(webClient, {
|
|
type: "ir.actions.client",
|
|
tag: "clientAction",
|
|
params: {
|
|
active_id: 99,
|
|
take: "five",
|
|
active_ids: "1,2",
|
|
list: [9, 10],
|
|
},
|
|
});
|
|
|
|
assert.deepEqual(webClient.env.services.router.current.hash, {
|
|
action: "clientAction",
|
|
active_id: 99,
|
|
take: "five",
|
|
active_ids: "1,2",
|
|
});
|
|
});
|
|
|
|
QUnit.test("client actions honour do_push_state", async function (assert) {
|
|
assert.expect(2);
|
|
|
|
const ClientAction = AbstractAction.extend({
|
|
init(parent) {
|
|
this._super(...arguments);
|
|
this.parent = parent;
|
|
this.parent.do_push_state({ pinball: "wizard" });
|
|
},
|
|
|
|
async start() {
|
|
await this._super(...arguments);
|
|
const btn = document.createElement("button");
|
|
btn.classList.add("tommy");
|
|
btn.addEventListener("click", () => {
|
|
this.parent.do_push_state({ gipsy: "the acid queen" });
|
|
});
|
|
this.el.append(btn);
|
|
},
|
|
|
|
getState() {
|
|
return {
|
|
doctor: "quackson",
|
|
};
|
|
},
|
|
});
|
|
core.action_registry.add("clientAction", ClientAction);
|
|
registerCleanup(() => delete core.action_registry.map.clientAction);
|
|
const webClient = await createWebClient({});
|
|
|
|
await doAction(webClient, {
|
|
type: "ir.actions.client",
|
|
tag: "clientAction",
|
|
});
|
|
|
|
assert.deepEqual(webClient.env.services.router.current.hash, {
|
|
action: "clientAction",
|
|
pinball: "wizard",
|
|
doctor: "quackson",
|
|
});
|
|
|
|
await click(target, ".tommy");
|
|
assert.deepEqual(webClient.env.services.router.current.hash, {
|
|
action: "clientAction",
|
|
pinball: "wizard",
|
|
gipsy: "the acid queen",
|
|
doctor: "quackson",
|
|
});
|
|
});
|
|
|
|
QUnit.test("Systray item triggers do action on legacy service provider", async (assert) => {
|
|
assert.expect(3);
|
|
function createMockActionService(assert) {
|
|
return {
|
|
dependencies: [],
|
|
start() {
|
|
return {
|
|
doAction(params) {
|
|
assert.step("do action");
|
|
assert.strictEqual(params, 128, "The doAction parameters are invalid.");
|
|
},
|
|
loadState() {},
|
|
};
|
|
},
|
|
};
|
|
}
|
|
registry.category("services").add("action", createMockActionService(assert));
|
|
const FakeSystrayItemWidget = Widget.extend({
|
|
on_attach_callback() {
|
|
this.do_action(128);
|
|
},
|
|
});
|
|
SystrayMenu.Items.push(FakeSystrayItemWidget);
|
|
await createWebClient({ serverData });
|
|
assert.verifySteps(["do action"]);
|
|
delete SystrayMenu.Items.FakeSystrayItemWidget;
|
|
});
|
|
|
|
QUnit.test("usercontext always added to legacy actions", async (assert) => {
|
|
assert.expect(8);
|
|
core.action_registry.add("testClientAction", AbstractAction);
|
|
registerCleanup(() => delete core.action_registry.map.testClientAction);
|
|
patchWithCleanup(ClientActionAdapter.prototype, {
|
|
setup() {
|
|
assert.step("ClientActionAdapter");
|
|
const action = { ...this.props.widgetArgs[0] };
|
|
const originalAction = JSON.parse(action._originalAction);
|
|
assert.deepEqual(originalAction.context, undefined);
|
|
assert.deepEqual(action.context, this.env.services.user.context);
|
|
this._super();
|
|
},
|
|
});
|
|
patchWithCleanup(ViewAdapter.prototype, {
|
|
setup() {
|
|
assert.step("ViewAdapter");
|
|
const action = { ...this.props.viewParams.action };
|
|
const originalAction = JSON.parse(action._originalAction);
|
|
assert.deepEqual(originalAction.context, undefined);
|
|
assert.deepEqual(action.context, this.env.services.user.context);
|
|
this._super();
|
|
},
|
|
});
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, "testClientAction");
|
|
assert.verifySteps(["ClientActionAdapter"]);
|
|
await doAction(webClient, 1);
|
|
assert.verifySteps(["ViewAdapter"]);
|
|
});
|
|
|
|
QUnit.test("correctly transports legacy Props for doAction", async (assert) => {
|
|
assert.expect(4);
|
|
|
|
let ID = 0;
|
|
const MyAction = AbstractAction.extend({
|
|
init() {
|
|
this._super(...arguments);
|
|
this.ID = ID++;
|
|
assert.step(`id: ${this.ID} props: ${JSON.stringify(arguments[2])}`);
|
|
},
|
|
async start() {
|
|
const res = await this._super(...arguments);
|
|
const link = document.createElement("a");
|
|
link.innerText = "some link";
|
|
link.setAttribute("id", `client_${this.ID}`);
|
|
link.addEventListener("click", () => {
|
|
this.do_action("testClientAction", {
|
|
clear_breadcrumbs: true,
|
|
props: { chain: "never break" },
|
|
});
|
|
});
|
|
|
|
this.el.appendChild(link);
|
|
return res;
|
|
},
|
|
});
|
|
core.action_registry.add("testClientAction", MyAction);
|
|
registerCleanup(() => delete core.action_registry.map.testClientAction);
|
|
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, "testClientAction");
|
|
assert.verifySteps(['id: 0 props: {"className":"o_action","breadcrumbs":[]}']);
|
|
|
|
await click(document.getElementById("client_0"));
|
|
assert.verifySteps([
|
|
'id: 1 props: {"chain":"never break","className":"o_action","breadcrumbs":[]}',
|
|
]);
|
|
});
|
|
|
|
QUnit.test("bootstrap tooltip in dialog action auto destroy", async (assert) => {
|
|
assert.expect(2);
|
|
|
|
const mockRPC = (route) => {
|
|
if (route === "/web/dataset/call_button") {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
serverData.views["partner,3,form"] = /*xml*/ `
|
|
<form>
|
|
<field name="display_name" />
|
|
<footer>
|
|
<button name="echoes" type="object" string="Echoes" help="echoes"/>
|
|
</footer>
|
|
</form>
|
|
`;
|
|
const webClient = await createWebClient({ serverData, mockRPC });
|
|
|
|
await doAction(webClient, 25);
|
|
|
|
const tooltipProm = makeDeferred();
|
|
$(target).one("shown.bs.tooltip", () => {
|
|
tooltipProm.resolve();
|
|
});
|
|
|
|
triggerEvents(target, ".modal footer button", ["mouseover", "focusin"]);
|
|
await tooltipProm;
|
|
// check on webClient dom
|
|
assert.containsOnce(document.body, ".tooltip");
|
|
await doAction(webClient, {
|
|
type: "ir.actions.act_window_close",
|
|
});
|
|
// check on the whole DOM
|
|
assert.containsNone(document.body, ".tooltip");
|
|
});
|
|
|
|
QUnit.test("bootstrap tooltip destroyed on click", async (assert) => {
|
|
assert.expect(2);
|
|
|
|
const mockRPC = (route) => {
|
|
if (route === "/web/dataset/call_button") {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
serverData.views["partner,666,form"] = /*xml*/ `
|
|
<form>
|
|
<header>
|
|
<button name="echoes" type="object" string="Echoes" help="echoes"/>
|
|
</header>
|
|
<field name="display_name" />
|
|
</form>
|
|
`;
|
|
const webClient = await createWebClient({ serverData, mockRPC });
|
|
|
|
await doAction(webClient, 24);
|
|
|
|
const tooltipProm = makeDeferred();
|
|
$(target).one("shown.bs.tooltip", () => {
|
|
tooltipProm.resolve();
|
|
});
|
|
|
|
triggerEvents(target, ".o_form_statusbar button", ["mouseover", "focusin"]);
|
|
await tooltipProm;
|
|
// check on webClient DOM
|
|
assert.containsOnce(document.body, ".tooltip");
|
|
await click(target, ".o_content");
|
|
// check on the whole DOM
|
|
assert.containsNone(document.body, ".tooltip");
|
|
});
|
|
|
|
QUnit.test("breadcrumbs are correct in stacked legacy client actions", async function (assert) {
|
|
const ClientAction = AbstractAction.extend({
|
|
hasControlPanel: true,
|
|
async start() {
|
|
this.$el.addClass("client_action");
|
|
return this._super(...arguments);
|
|
},
|
|
getTitle() {
|
|
return "Blabla";
|
|
},
|
|
});
|
|
core.action_registry.add("clientAction", ClientAction);
|
|
registerCleanup(() => delete core.action_registry.map.clientAction);
|
|
|
|
const webClient = await createWebClient({ serverData });
|
|
|
|
await doAction(webClient, 3);
|
|
assert.containsOnce(target, ".o_legacy_list_view");
|
|
assert.strictEqual($(target).find(".breadcrumb-item").text(), "Partners");
|
|
|
|
await doAction(webClient, {
|
|
type: "ir.actions.client",
|
|
tag: "clientAction",
|
|
});
|
|
assert.containsOnce(target, ".client_action");
|
|
assert.strictEqual($(target).find(".breadcrumb-item").text(), "PartnersBlabla");
|
|
});
|
|
|
|
QUnit.test("view with js_class attribute (legacy)", async function (assert) {
|
|
assert.expect(2);
|
|
const TestView = AbstractView.extend({
|
|
viewType: "test_view",
|
|
});
|
|
const TestJsClassView = TestView.extend({
|
|
init() {
|
|
this._super.call(this, ...arguments);
|
|
assert.step("init js class");
|
|
},
|
|
});
|
|
serverData.views["partner,false,test_view"] = `<div js_class="test_jsClass"></div>`;
|
|
serverData.actions[9999] = {
|
|
id: 1,
|
|
name: "Partners Action 1",
|
|
res_model: "partner",
|
|
type: "ir.actions.act_window",
|
|
views: [[false, "test_view"]],
|
|
};
|
|
legacyViewRegistry.add("test_view", TestView);
|
|
legacyViewRegistry.add("test_jsClass", TestJsClassView);
|
|
const webClient = await createWebClient({ serverData });
|
|
await doAction(webClient, 9999);
|
|
assert.verifySteps(["init js class"]);
|
|
delete legacyViewRegistry.map.test_view;
|
|
delete legacyViewRegistry.map.test_jsClass;
|
|
});
|
|
|
|
QUnit.test(
|
|
"execute action without modal closes bootstrap tooltips anyway",
|
|
async function (assert) {
|
|
assert.expect(12);
|
|
Object.assign(serverData.views, {
|
|
"partner,666,form": `<form>
|
|
<header>
|
|
<button name="object" string="Call method" type="object" help="need somebody"/>
|
|
</header>
|
|
<field name="display_name"/>
|
|
</form>`,
|
|
});
|
|
const mockRPC = async (route) => {
|
|
assert.step(route);
|
|
if (route === "/web/dataset/call_button") {
|
|
// Some business stuff server side, then return an implicit close action
|
|
return Promise.resolve(false);
|
|
}
|
|
};
|
|
|
|
const webClient = await createWebClient({ serverData, mockRPC });
|
|
await doAction(webClient, 24);
|
|
assert.verifySteps([
|
|
"/web/webclient/load_menus",
|
|
"/web/action/load",
|
|
"/web/dataset/call_kw/partner/get_views",
|
|
"/web/dataset/call_kw/partner/read",
|
|
]);
|
|
assert.containsN(target, ".o_form_buttons_view button:not([disabled])", 2);
|
|
const actionButton = target.querySelector("button[name=object]");
|
|
const tooltipProm = new Promise((resolve) => {
|
|
document.body.addEventListener(
|
|
"shown.bs.tooltip",
|
|
() => {
|
|
actionButton.dispatchEvent(new Event("mouseout"));
|
|
resolve();
|
|
},
|
|
{
|
|
once: true,
|
|
}
|
|
);
|
|
});
|
|
actionButton.dispatchEvent(new Event("mouseover"));
|
|
await tooltipProm;
|
|
assert.containsOnce(document.body, ".tooltip");
|
|
await click(actionButton);
|
|
await legacyExtraNextTick();
|
|
assert.verifySteps(["/web/dataset/call_button", "/web/dataset/call_kw/partner/read"]);
|
|
assert.containsNone(document.body, ".tooltip"); // body different from webClient in tests !
|
|
assert.containsN(target, ".o_form_buttons_view button:not([disabled])", 2);
|
|
}
|
|
);
|
|
|
|
QUnit.test("click multiple times to open a record", async function (assert) {
|
|
assert.expect(5);
|
|
|
|
const def = testUtils.makeTestPromise();
|
|
const defs = [null, def];
|
|
const mockRPC = async (route, args) => {
|
|
if (args.method === "read") {
|
|
await Promise.resolve(defs.shift());
|
|
}
|
|
};
|
|
|
|
const webClient = await createWebClient({ serverData, mockRPC });
|
|
await doAction(webClient, 3);
|
|
|
|
assert.containsOnce(target, ".o_legacy_list_view");
|
|
|
|
await testUtils.dom.click(target.querySelector(".o_legacy_list_view .o_data_row"));
|
|
await legacyExtraNextTick();
|
|
assert.containsOnce(target, ".o_legacy_form_view");
|
|
|
|
await testUtils.dom.click(target.querySelector(".o_back_button"));
|
|
await legacyExtraNextTick();
|
|
|
|
assert.containsOnce(target, ".o_legacy_list_view");
|
|
|
|
await testUtils.dom.click(target.querySelector(".o_legacy_list_view .o_data_row"));
|
|
await testUtils.dom.click(target.querySelector(".o_legacy_list_view .o_data_row"));
|
|
await legacyExtraNextTick();
|
|
assert.containsOnce(target, ".o_legacy_list_view");
|
|
|
|
def.resolve();
|
|
await testUtils.nextTick();
|
|
await legacyExtraNextTick();
|
|
assert.containsOnce(target, ".o_legacy_form_view");
|
|
});
|
|
|
|
QUnit.test("correct pager when coming from list (legacy)", async (assert) => {
|
|
assert.expect(4);
|
|
|
|
registry.category("views").remove("list");
|
|
legacyViewRegistry.add("list", ListView);
|
|
serverData.views = {
|
|
"partner,false,search": `<search />`,
|
|
"partner,99,list": `<list limit="4"><field name="display_name" /></list>`,
|
|
"partner,100,form": `<form><field name="display_name" /></form>`,
|
|
};
|
|
|
|
const wc = await createWebClient({ serverData });
|
|
await doAction(wc, {
|
|
res_model: "partner",
|
|
type: "ir.actions.act_window",
|
|
views: [
|
|
[99, "list"],
|
|
[100, "form"],
|
|
],
|
|
});
|
|
|
|
assert.deepEqual(cpHelpers.getPagerValue(target), [1, 4]);
|
|
assert.deepEqual(cpHelpers.getPagerLimit(target), 5);
|
|
|
|
await click(target, ".o_data_row:nth-child(2) .o_data_cell");
|
|
await legacyExtraNextTick();
|
|
assert.deepEqual(cpHelpers.getPagerValue(target), [2]);
|
|
assert.deepEqual(cpHelpers.getPagerLimit(target), 4);
|
|
});
|
|
});
|