+1








0573acae23
This commit is the first phase of the conversion of the web/ JS codebase to the owl framework. The impact of this commit is two-fold. First, it rewrites the framework part of web with a new system of services and registries. Services allow to execute code (e.g. do rpcs, setup things) before launching the application. They can also expose an API to be used by other parts of the application (e.g. a notification service would expose a function to display notifications). Services are often a good extension point for external modules that want to execute code at webclient startup. Registries offer another way to extend the application. They provide well designed extension points to add elements/behaviors from the outside (for instance, to add a systray item, an error handler...). Second, this commit initiates the conversion of the webclient to owl with a top-down approach, around those notions of services and registries. The root of the web application is now an owl application. Among others, the WebClient, ActionManager, Navbar, UserMenu, DebugManager, Dialogs, services (e.g. notification, ajax...) have been converted to the new framework/architecture. Legacy views and client actions are still supported (and used). They will be converted in the next months, and at some point, the support will be dropped. Co-authored-by: Aaron Bohy <aab@odoo.com> Co-authored-by: Bruno Boi <boi@odoo.com> Co-authored-by: Géry Debongnie <ged@odoo.com> Co-authored-by: Samuel Degueldre <sad@odoo.com> Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com> Co-authored-by: Simon Genin (ges) <ges@odoo.com> Co-authored-by: Francois (fge) <fge@odoo.com> Co-authored-by: Michael Mattiello (mcm) <mcm@odoo.com> Co-authored-by: Julien Mougenot <jum@odoo.com> Co-authored-by: Lucas Perais (lpe) <lpe@odoo.com> Co-authored-by: Jorge Pinna Puissant <jpp@odoo.com>
131 lines
5.5 KiB
JavaScript
131 lines
5.5 KiB
JavaScript
/** @odoo-module **/
|
|
|
|
import { registry } from "@web/core/registry";
|
|
import { NotificationContainer } from "@web/core/notifications/notification_container";
|
|
import { EffectContainer } from "@web/webclient/effects/effect_container";
|
|
import testUtils from "web.test_utils";
|
|
import { clearRegistryWithCleanup } from "../../helpers/mock_env";
|
|
import { makeFakeUserService } from "../../helpers/mock_services";
|
|
import { click, legacyExtraNextTick, nextTick } from "../../helpers/utils";
|
|
import { createWebClient, doAction, getActionManagerTestConfig } from "./helpers";
|
|
|
|
let testConfig;
|
|
|
|
const mainComponentRegistry = registry.category("main_components");
|
|
const serviceRegistry = registry.category("services");
|
|
|
|
QUnit.module("ActionManager", (hooks) => {
|
|
hooks.beforeEach(() => {
|
|
testConfig = getActionManagerTestConfig();
|
|
});
|
|
|
|
QUnit.module("Effects");
|
|
|
|
QUnit.test("rainbowman integrated to webClient", async function (assert) {
|
|
assert.expect(10);
|
|
serviceRegistry.add("user", makeFakeUserService({ showEffect: true }), {
|
|
force: true,
|
|
});
|
|
clearRegistryWithCleanup(mainComponentRegistry);
|
|
mainComponentRegistry.add("EffectContainer", EffectContainer);
|
|
const webClient = await createWebClient({ testConfig });
|
|
await doAction(webClient, 1);
|
|
assert.containsOnce(webClient.el, ".o_kanban_view");
|
|
assert.containsNone(webClient.el, ".o_reward");
|
|
webClient.env.services.effect.rainbowMan({ message: "", fadeout: "no" });
|
|
await nextTick();
|
|
await legacyExtraNextTick();
|
|
assert.containsOnce(webClient.el, ".o_reward");
|
|
assert.containsOnce(webClient.el, ".o_kanban_view");
|
|
await testUtils.dom.click(webClient.el.querySelector(".o_kanban_record"));
|
|
await legacyExtraNextTick();
|
|
assert.containsNone(webClient.el, ".o_reward");
|
|
assert.containsOnce(webClient.el, ".o_kanban_view");
|
|
webClient.env.services.effect.rainbowMan({ message: "", fadeout: "no" });
|
|
await nextTick();
|
|
await legacyExtraNextTick();
|
|
assert.containsOnce(webClient.el, ".o_reward");
|
|
assert.containsOnce(webClient.el, ".o_kanban_view");
|
|
// Do not force rainbow man to destroy on doAction
|
|
// we let it die either after its animation or on user click
|
|
await doAction(webClient, 3);
|
|
assert.containsOnce(webClient.el, ".o_reward");
|
|
assert.containsOnce(webClient.el, ".o_list_view");
|
|
});
|
|
|
|
QUnit.test("show effect notification instead of rainbow man", async function (assert) {
|
|
assert.expect(6);
|
|
clearRegistryWithCleanup(mainComponentRegistry);
|
|
mainComponentRegistry.add("NotificationContainer", NotificationContainer);
|
|
|
|
const webClient = await createWebClient({ testConfig });
|
|
await doAction(webClient, 1);
|
|
assert.containsOnce(webClient.el, ".o_kanban_view");
|
|
assert.containsNone(webClient.el, ".o_reward");
|
|
assert.containsNone(webClient.el, ".o_notification");
|
|
webClient.env.services.effect.rainbowMan({ message: "", fadeout: "no" });
|
|
await nextTick();
|
|
await legacyExtraNextTick();
|
|
assert.containsOnce(webClient.el, ".o_kanban_view");
|
|
assert.containsNone(webClient.el, ".o_reward");
|
|
assert.containsOnce(webClient.el, ".o_notification");
|
|
});
|
|
|
|
QUnit.test("on close with effect from server", async function (assert) {
|
|
assert.expect(1);
|
|
serviceRegistry.add("user", makeFakeUserService({ showEffect: true }), {
|
|
force: true,
|
|
});
|
|
const mockRPC = async (route, args) => {
|
|
if (route === "/web/dataset/call_button") {
|
|
return Promise.resolve({
|
|
type: "ir.actions.act_window_close",
|
|
effect: {
|
|
type: "rainbow_man",
|
|
message: "button called",
|
|
},
|
|
});
|
|
}
|
|
};
|
|
clearRegistryWithCleanup(mainComponentRegistry);
|
|
mainComponentRegistry.add("EffectContainer", EffectContainer);
|
|
const webClient = await createWebClient({ testConfig, mockRPC });
|
|
await doAction(webClient, 6);
|
|
await click(webClient.el.querySelector('button[name="object"]'));
|
|
assert.containsOnce(webClient, ".o_reward");
|
|
});
|
|
|
|
QUnit.test("on close with effect in xml", async function (assert) {
|
|
assert.expect(2);
|
|
testConfig.serverData.views["partner,false,form"] = `
|
|
<form>
|
|
<header>
|
|
<button string="Call method" name="object" type="object"
|
|
effect="{'type': 'rainbow_man', 'message': 'rainBowInXML'}"
|
|
/>
|
|
</header>
|
|
<field name="display_name"/>
|
|
</form>`;
|
|
serviceRegistry.add("user", makeFakeUserService({ showEffect: true }), {
|
|
force: true,
|
|
});
|
|
const mockRPC = async (route, args) => {
|
|
if (route === "/web/dataset/call_button") {
|
|
return Promise.resolve(false);
|
|
}
|
|
};
|
|
clearRegistryWithCleanup(mainComponentRegistry);
|
|
mainComponentRegistry.add("EffectContainer", EffectContainer);
|
|
|
|
const webClient = await createWebClient({ testConfig, mockRPC });
|
|
await doAction(webClient, 6);
|
|
await click(webClient.el.querySelector('button[name="object"]'));
|
|
await legacyExtraNextTick();
|
|
assert.containsOnce(webClient.el, ".o_reward");
|
|
assert.strictEqual(
|
|
webClient.el.querySelector(".o_reward .o_reward_msg_content").textContent,
|
|
"rainBowInXML"
|
|
);
|
|
});
|
|
});
|