Files
jikimo_sf/web_studio/static/tests/studio_home_menu_tests.js
2023-04-14 17:42:23 +08:00

340 lines
12 KiB
JavaScript

/** @odoo-module **/
import { IconCreator } from "@web_studio/client_action/icon_creator/icon_creator";
import { StudioHomeMenu } from "@web_studio/client_action/studio_home_menu/studio_home_menu";
import { MODES } from "@web_studio/studio_service";
import { ormService } from "@web/core/orm_service";
import { enterpriseSubscriptionService } from "@web_enterprise/webclient/home_menu/enterprise_subscription_service";
import {
fakeCommandService,
makeFakeNotificationService,
makeFakeRPCService,
} from "@web/../tests/helpers/mock_services";
import { userService } from "@web/core/user_service";
import { uiService } from "@web/core/ui/ui_service";
import { hotkeyService } from "@web/core/hotkeys/hotkey_service";
import { registerCleanup } from "@web/../tests/helpers/cleanup";
import { makeTestEnv } from "@web/../tests/helpers/mock_env";
import { click, getFixture, mount } from "@web/../tests/helpers/utils";
import { dialogService } from "@web/core/dialog/dialog_service";
import { registry } from "@web/core/registry";
const { Component, EventBus, xml } = owl;
const serviceRegistry = registry.category("services");
const genericHomeMenuProps = {
apps: [
{
actionID: 121,
id: 1,
appID: 1,
label: "Discuss",
parents: "",
webIcon: "mail,static/description/icon.png",
webIconData: "/web_enterprise/static/img/default_icon_app.png",
xmlid: "app.1",
},
{
actionID: 122,
id: 2,
appID: 2,
label: "Calendar",
parents: "",
webIcon: {
backgroundColor: "#C6572A",
color: "#FFFFFF",
iconClass: "fa fa-diamond",
},
xmlid: "app.2",
},
{
actionID: 123,
id: 3,
appID: 3,
label: "Contacts",
parents: "",
webIcon: false,
webIconData: "/web_enterprise/static/img/default_icon_app.png",
xmlid: "app.3",
},
],
};
// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
const createStudioHomeMenu = async () => {
class Parent extends Component {
get DialogContainer() {
return registry.category("main_components").get("DialogContainer");
}
}
Parent.components = { StudioHomeMenu };
Parent.template = xml`
<div>
<StudioHomeMenu t-props="props.homeMenuProps" />
<div class="o_dialog_container" />
<t t-component="DialogContainer.Component" t-props="DialogContainer.props" />
</div>`;
const env = await makeTestEnv();
const target = getFixture();
await mount(Parent, target, { env, props: { homeMenuProps: { ...genericHomeMenuProps } } });
return target;
};
// -----------------------------------------------------------------------------
// Tests
// -----------------------------------------------------------------------------
let bus;
QUnit.module("Studio", (hooks) => {
hooks.beforeEach(() => {
IconCreator.enableTransitions = false;
registerCleanup(() => {
IconCreator.enableTransitions = true;
});
bus = new EventBus();
const fakeNotificationService = makeFakeNotificationService();
const fakeHomeMenuService = {
start() {
return {
toggle() {},
};
},
};
const fakeMenuService = {
start() {
return {
setCurrentMenu(menu) {
bus.trigger("menu:setCurrentMenu", menu.id);
},
reload() {
bus.trigger("menu:reload");
},
getMenu() {
return {};
},
};
},
};
const fakeStudioService = {
start() {
return {
MODES,
open(...args) {
bus.trigger("studio:open", args);
},
};
},
};
const fakeHTTPService = {
start() {
return {};
},
};
serviceRegistry.add("orm", ormService);
serviceRegistry.add("enterprise_subscription", enterpriseSubscriptionService);
serviceRegistry.add("home_menu", fakeHomeMenuService);
serviceRegistry.add("http", fakeHTTPService);
serviceRegistry.add("menu", fakeMenuService);
serviceRegistry.add("notification", fakeNotificationService);
serviceRegistry.add("user", userService);
serviceRegistry.add("studio", fakeStudioService);
serviceRegistry.add("hotkey", hotkeyService);
serviceRegistry.add("dialog", dialogService);
serviceRegistry.add("ui", uiService);
serviceRegistry.add("command", fakeCommandService);
});
QUnit.module("StudioHomeMenu");
QUnit.test("simple rendering", async (assert) => {
assert.expect(20);
const target = await createStudioHomeMenu();
// Main div
assert.containsOnce(target, ".o_home_menu");
// Hidden elements
assert.isNotVisible(
target.querySelector(".database_expiration_panel"),
"Expiration panel should not be visible"
);
// App list
assert.containsOnce(target, "div.o_apps");
assert.containsN(
target,
"div.o_apps > a.o_app.o_menuitem",
4,
"should contain 3 normal app icons + the new app button"
);
// App with image
const firstApp = target.querySelector("div.o_apps > a.o_app.o_menuitem");
assert.strictEqual(firstApp.dataset.menuXmlid, "app.1");
assert.containsOnce(firstApp, "img.o_app_icon");
assert.strictEqual(
firstApp.querySelector("img.o_app_icon").dataset.src,
"/web_enterprise/static/img/default_icon_app.png"
);
assert.containsOnce(firstApp, "div.o_caption");
assert.strictEqual(firstApp.querySelector("div.o_caption").innerText, "Discuss");
assert.containsOnce(firstApp, ".o_web_studio_edit_icon i");
// App with custom icon
const secondApp = target.querySelectorAll("div.o_apps > a.o_app.o_menuitem")[1];
assert.strictEqual(secondApp.dataset.menuXmlid, "app.2");
assert.containsOnce(secondApp, "div.o_app_icon");
assert.strictEqual(
secondApp.querySelector("div.o_app_icon").style.backgroundColor,
"rgb(198, 87, 42)",
"Icon background color should be #C6572A"
);
assert.containsOnce(secondApp, "i.fa.fa-diamond");
assert.strictEqual(
secondApp.querySelector("i.fa.fa-diamond").style.color,
"rgb(255, 255, 255)",
"Icon color should be #FFFFFF"
);
assert.containsOnce(secondApp, ".o_web_studio_edit_icon i");
// New app button
assert.containsOnce(
target,
"div.o_apps > a.o_app.o_web_studio_new_app",
'should contain a "New App icon"'
);
const newApp = target.querySelector("a.o_app.o_web_studio_new_app");
assert.strictEqual(
newApp.querySelector("img.o_app_icon").dataset.src,
"/web_studio/static/src/img/default_icon_app.png",
"Image source URL should end with '/web_studio/static/src/img/default_icon_app.png'"
);
assert.containsOnce(newApp, "div.o_caption");
assert.strictEqual(newApp.querySelector("div.o_caption").innerText, "New App");
});
QUnit.test("Click on a normal App", async (assert) => {
assert.expect(2);
bus.on("studio:open", null, (modeAndActionId) => {
assert.deepEqual(modeAndActionId, [MODES.EDITOR, 121]);
});
bus.on("menu:setCurrentMenu", null, (menuId) => {
assert.strictEqual(menuId, 1);
});
const target = await createStudioHomeMenu();
await click(target.querySelector(".o_menuitem"));
});
QUnit.test("Click on new App", async (assert) => {
assert.expect(1);
bus.on("studio:open", null, ([mode]) => {
assert.strictEqual(mode, MODES.APP_CREATOR);
});
bus.on("menu:setCurrentMenu", null, () => {
throw new Error("should not update the current menu");
});
const target = await createStudioHomeMenu();
await click(target, "a.o_app.o_web_studio_new_app");
});
QUnit.test("Click on edit icon button", async (assert) => {
assert.expect(11);
const target = await createStudioHomeMenu();
// TODO: we should maybe check icon visibility comes on mouse over
const firstEditIconButton = target.querySelector(".o_web_studio_edit_icon i");
await click(firstEditIconButton);
const dialog = document.querySelector("div.modal");
assert.containsOnce(dialog, "header.modal-header");
assert.strictEqual(
dialog.querySelector("header.modal-header h4").innerText,
"Edit Application Icon"
);
assert.containsOnce(
dialog,
".modal-content.o_web_studio_edit_menu_icon_modal .o_web_studio_icon_creator"
);
assert.containsOnce(dialog, "footer.modal-footer");
assert.containsN(dialog, "footer button", 2);
const buttons = dialog.querySelectorAll("footer button");
const firstButton = buttons[0];
const secondButton = buttons[1];
assert.strictEqual(firstButton.innerText, "CONFIRM");
assert.hasClass(firstButton, "btn-primary");
assert.strictEqual(secondButton.innerText, "CANCEL");
assert.hasClass(secondButton, "btn-secondary");
await click(secondButton);
assert.strictEqual(document.querySelector("div.modal"), null);
await click(firstEditIconButton);
await click(document.querySelector("footer button"));
assert.strictEqual(document.querySelector("div.modal"), null);
});
QUnit.test("edit an icon", async (assert) => {
assert.expect(3);
const mockRPC = (route, args) => {
if (route === "/web_studio/edit_menu_icon") {
assert.deepEqual(args, {
context: {
lang: "en",
tz: "taht",
uid: 7,
},
icon: ["fa fa-balance-scale", "#f1c40f", "#34495e"],
menu_id: 1,
});
}
};
registry.category("services").add("rpc", makeFakeRPCService(mockRPC), { force: true });
const target = await createStudioHomeMenu();
await click(target.querySelector(".o_web_studio_edit_icon i"));
const dialog = document.querySelector("div.modal");
await click(dialog.querySelector(".o_web_studio_upload a"));
assert.doesNotHaveClass(
dialog.querySelector(".o_web_studio_icon .o_app_icon i"),
"fa-balance-scale"
);
// Change the icon's pictogram
await click(dialog.querySelectorAll(".o_web_studio_selector")[2]);
await click(dialog, ".o_web_studio_selector .fa.fa-balance-scale");
assert.hasClass(
dialog.querySelector(".o_web_studio_icon .o_app_icon i"),
"fa-balance-scale"
);
await click(dialog.querySelector("footer button")); // trigger save
});
});