合并企业版代码(未测试,先提交到测试分支)
This commit is contained in:
784
web_enterprise/static/tests/webclient/expiration_panel_tests.js
Normal file
784
web_enterprise/static/tests/webclient/expiration_panel_tests.js
Normal file
@@ -0,0 +1,784 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { createWebClient, doAction } from "@web/../tests/webclient/helpers";
|
||||
import { click, getFixture, patchDate, patchWithCleanup } from "@web/../tests/helpers/utils";
|
||||
import { makeFakeNotificationService } from "@web/../tests/helpers/mock_services";
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
import { ormService } from "@web/core/orm_service";
|
||||
import testUtils from "web.test_utils";
|
||||
import { enterpriseSubscriptionService } from "@web_enterprise/webclient/home_menu/enterprise_subscription_service";
|
||||
import { homeMenuService } from "@web_enterprise/webclient/home_menu/home_menu_service";
|
||||
import { session } from "@web/session";
|
||||
|
||||
const serviceRegistry = registry.category("services");
|
||||
|
||||
let target;
|
||||
|
||||
async function createExpirationPanel(params = {}) {
|
||||
const mockedCookieService = {
|
||||
name: "cookie",
|
||||
start() {
|
||||
return Object.assign(
|
||||
{
|
||||
current: {},
|
||||
setCookie() {},
|
||||
deleteCookie() {},
|
||||
},
|
||||
params.cookie
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
serviceRegistry.add(mockedCookieService.name, mockedCookieService);
|
||||
serviceRegistry.add("orm", ormService);
|
||||
serviceRegistry.add("home_menu", homeMenuService);
|
||||
serviceRegistry.add(
|
||||
"notification",
|
||||
makeFakeNotificationService(params.mockNotification || (() => {}))
|
||||
);
|
||||
patchWithCleanup(session, { ...params.session });
|
||||
serviceRegistry.add("enterprise_subscription", enterpriseSubscriptionService);
|
||||
patchWithCleanup(browser, params.browser);
|
||||
|
||||
const webclient = await createWebClient({
|
||||
mockRPC: params.mockRPC,
|
||||
});
|
||||
await doAction(webclient, "menu");
|
||||
return webclient;
|
||||
}
|
||||
|
||||
QUnit.module("web_enterprise", function ({ beforeEach }) {
|
||||
beforeEach(() => {
|
||||
target = getFixture();
|
||||
});
|
||||
|
||||
QUnit.module("Expiration Panel");
|
||||
|
||||
QUnit.test("Expiration Panel one app installed", async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
patchDate(2019, 9, 10, 12, 0, 0);
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-11-09 12:00:00",
|
||||
expiration_reason: "",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"This database will expire in 1 month."
|
||||
);
|
||||
|
||||
// Color should be grey
|
||||
assert.hasClass(target.querySelector(".database_expiration_panel"), "alert-info");
|
||||
|
||||
// Close the expiration panel
|
||||
await click(target.querySelector(".oe_instance_hide_panel"));
|
||||
|
||||
assert.containsNone(target, ".database_expiration_panel");
|
||||
});
|
||||
|
||||
QUnit.test("Expiration Panel one app installed, buy subscription", async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
patchDate(2019, 9, 10, 12, 0, 0);
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-10-24 12:00:00",
|
||||
expiration_reason: "demo",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
mockRPC(route) {
|
||||
if (route === "/web/dataset/call_kw/res.users/search_count") {
|
||||
return 7;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"This demo database will expire in 14 days. Register your subscription or buy a subscription."
|
||||
);
|
||||
|
||||
assert.hasClass(
|
||||
target.querySelector(".database_expiration_panel"),
|
||||
"alert-warning",
|
||||
"Color should be orange"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".oe_instance_register_show",
|
||||
"Part 'Register your subscription'"
|
||||
);
|
||||
assert.containsOnce(target, ".oe_instance_buy", "Part 'buy a subscription'");
|
||||
assert.containsNone(
|
||||
target,
|
||||
".oe_instance_register_form",
|
||||
"There should be no registration form"
|
||||
);
|
||||
|
||||
// Click on 'buy subscription'
|
||||
await click(target.querySelector(".oe_instance_buy"));
|
||||
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Expiration Panel one app installed, try several times to register subscription",
|
||||
async function (assert) {
|
||||
assert.expect(44);
|
||||
|
||||
patchDate(2019, 9, 10, 12, 0, 0);
|
||||
|
||||
let callToGetParamCount = 0;
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-10-15 12:00:00",
|
||||
expiration_reason: "trial",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
mockNotification(message, options) {
|
||||
assert.step(JSON.stringify({ message, options }));
|
||||
},
|
||||
mockRPC(route, { args }) {
|
||||
if (route === "/web/dataset/call_kw/ir.config_parameter/get_param") {
|
||||
assert.step("get_param");
|
||||
if (args[0] === "database.already_linked_subscription_url") {
|
||||
return false;
|
||||
}
|
||||
if (args[0] === "database.already_linked_email") {
|
||||
return "super_company_admin@gmail.com";
|
||||
}
|
||||
assert.strictEqual(args[0], "database.expiration_date");
|
||||
callToGetParamCount++;
|
||||
if (callToGetParamCount <= 3) {
|
||||
return "2019-10-15 12:00:00";
|
||||
} else {
|
||||
return "2019-11-15 12:00:00";
|
||||
}
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/ir.config_parameter/set_param") {
|
||||
assert.step("set_param");
|
||||
assert.strictEqual(args[0], "database.enterprise_code");
|
||||
if (callToGetParamCount === 1) {
|
||||
assert.strictEqual(args[1], "ABCDEF");
|
||||
} else {
|
||||
assert.strictEqual(args[1], "ABC");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
route ===
|
||||
"/web/dataset/call_kw/publisher_warranty.contract/update_notification"
|
||||
) {
|
||||
assert.step("update_notification");
|
||||
assert.ok(args[0] instanceof Array && args[0].length === 0);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"This database will expire in 5 days. Register your subscription or buy a subscription."
|
||||
);
|
||||
|
||||
assert.hasClass(
|
||||
target.querySelector(".database_expiration_panel"),
|
||||
"alert-danger",
|
||||
"Color should be red"
|
||||
);
|
||||
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".oe_instance_register_show",
|
||||
"Part 'Register your subscription'"
|
||||
);
|
||||
assert.containsOnce(target, ".oe_instance_buy", "Part 'buy a subscription'");
|
||||
assert.containsNone(
|
||||
target,
|
||||
".oe_instance_register_form",
|
||||
"There should be no registration form"
|
||||
);
|
||||
|
||||
// Click on 'register your subscription'
|
||||
await click(target.querySelector(".oe_instance_register_show"));
|
||||
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".oe_instance_register_form",
|
||||
"there should be a registration form"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
'.oe_instance_register_form input[placeholder="Paste code here"]',
|
||||
"with an input with place holder 'Paste code here'"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".oe_instance_register_form button",
|
||||
"and a button 'REGISTER'"
|
||||
);
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register_form button").innerText,
|
||||
"REGISTER"
|
||||
);
|
||||
|
||||
await click(target.querySelector(".oe_instance_register_form button"));
|
||||
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".oe_instance_register_form",
|
||||
"there should be a registration form"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
'.oe_instance_register_form input[placeholder="Paste code here"]',
|
||||
"with an input with place holder 'Paste code here'"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".oe_instance_register_form button",
|
||||
"and a button 'REGISTER'"
|
||||
);
|
||||
|
||||
await testUtils.fields.editInput(
|
||||
target.querySelector(".oe_instance_register_form input"),
|
||||
"ABCDEF"
|
||||
);
|
||||
await click(target.querySelector(".oe_instance_register_form button"));
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"Something went wrong while registering your database. You can try again or contact Odoo Support."
|
||||
);
|
||||
assert.hasClass(
|
||||
target.querySelector(".database_expiration_panel"),
|
||||
"alert-danger",
|
||||
"Color should be red"
|
||||
);
|
||||
assert.containsOnce(target, "span.oe_instance_error");
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".oe_instance_register_form",
|
||||
"there should be a registration form"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
'.oe_instance_register_form input[placeholder="Paste code here"]',
|
||||
"with an input with place holder 'Paste code here'"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".oe_instance_register_form button",
|
||||
"and a button 'REGISTER'"
|
||||
);
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register_form button").innerText,
|
||||
"RETRY"
|
||||
);
|
||||
|
||||
await testUtils.fields.editInput(
|
||||
target.querySelector(".oe_instance_register_form input"),
|
||||
"ABC"
|
||||
);
|
||||
await click(target.querySelector(".oe_instance_register_form button"));
|
||||
|
||||
assert.containsNone(
|
||||
target,
|
||||
".database_expiration_panel",
|
||||
"expiration panel should be gone"
|
||||
);
|
||||
|
||||
assert.verifySteps([
|
||||
// second try to submit
|
||||
"get_param",
|
||||
"set_param",
|
||||
"get_param",
|
||||
"get_param",
|
||||
"update_notification",
|
||||
"get_param",
|
||||
// third try
|
||||
"get_param",
|
||||
"set_param",
|
||||
"get_param",
|
||||
"get_param",
|
||||
"update_notification",
|
||||
"get_param",
|
||||
`{"message":"Thank you, your registration was successful! Your database is valid until November 15, 2019.","options":{"type":"success"}}`,
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"Expiration Panel one app installed, subscription already linked",
|
||||
async function (assert) {
|
||||
assert.expect(12);
|
||||
|
||||
patchDate(2019, 9, 10, 12, 0, 0);
|
||||
|
||||
// There are some line breaks mismatches between local and runbot test instances.
|
||||
// Since they don't affect the layout and we're only interested in the text itself,
|
||||
// we normalize whitespaces and line breaks from both the expected and end result
|
||||
const formatWhiteSpaces = (text) =>
|
||||
text
|
||||
.split(/[\n\s]/)
|
||||
.filter((w) => w !== "")
|
||||
.join(" ");
|
||||
|
||||
let getExpirationDateCount = 0;
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-10-15 12:00:00",
|
||||
expiration_reason: "trial",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
mockRPC(route, { method, args }) {
|
||||
if (route === "/web/webclient/load_menus") {
|
||||
return;
|
||||
}
|
||||
if (route === "/already/linked/send/mail/url") {
|
||||
return {
|
||||
result: false,
|
||||
reason: "By design",
|
||||
};
|
||||
}
|
||||
assert.step(method);
|
||||
if (args[0] === "database.expiration_date") {
|
||||
getExpirationDateCount++;
|
||||
if (getExpirationDateCount === 1) {
|
||||
return "2019-10-15 12:00:00";
|
||||
} else {
|
||||
return "2019-11-17 12:00:00";
|
||||
}
|
||||
}
|
||||
if (args[0] === "database.already_linked_subscription_url") {
|
||||
return "www.super_company.com";
|
||||
}
|
||||
if (args[0] === "database.already_linked_send_mail_url") {
|
||||
return "/already/linked/send/mail/url";
|
||||
}
|
||||
if (args[0] === "database.already_linked_email") {
|
||||
return "super_company_admin@gmail.com";
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"This database will expire in 5 days. Register your subscription or buy a subscription."
|
||||
);
|
||||
|
||||
// Click on 'register your subscription'
|
||||
await click(target.querySelector(".oe_instance_register_show"));
|
||||
await testUtils.fields.editInput(
|
||||
target.querySelector(".oe_instance_register_form input"),
|
||||
"ABC"
|
||||
);
|
||||
await click(target.querySelector(".oe_instance_register_form button"));
|
||||
|
||||
assert.strictEqual(
|
||||
formatWhiteSpaces(
|
||||
target.querySelector(".oe_instance_register.oe_database_already_linked")
|
||||
.innerText
|
||||
),
|
||||
formatWhiteSpaces(
|
||||
`Your subscription is already linked to a database.
|
||||
To unlink it you can either:
|
||||
Login to your Odoo.com dashboard then unlink your previous database: www.super_company.com
|
||||
Click here to send an email to the subscription owner (email: super_company_admin@gmail.com) with the instructions to follow`
|
||||
)
|
||||
);
|
||||
|
||||
await click(target.querySelector("a.oe_contract_send_mail"));
|
||||
|
||||
assert.hasClass(
|
||||
target.querySelector(".database_expiration_panel"),
|
||||
"alert-danger",
|
||||
"Color should be red"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
formatWhiteSpaces(
|
||||
target.querySelector(".oe_instance_register.oe_database_already_linked")
|
||||
.innerText
|
||||
),
|
||||
formatWhiteSpaces(
|
||||
`Your subscription is already linked to a database.
|
||||
To unlink it you can either:
|
||||
Login to your Odoo.com dashboard then unlink your previous database: www.super_company.com
|
||||
Click here to send an email to the subscription owner (email: super_company_admin@gmail.com) with the instructions to follow
|
||||
Unable to send the instructions by email, please contact the Odoo Support
|
||||
Error reason: By design`
|
||||
)
|
||||
);
|
||||
|
||||
assert.verifySteps([
|
||||
"get_param",
|
||||
"set_param",
|
||||
"get_param",
|
||||
"get_param",
|
||||
"update_notification",
|
||||
"get_param",
|
||||
"get_param",
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("One app installed, database expired", async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
patchDate(2019, 9, 10, 12, 0, 0);
|
||||
|
||||
let callToGetParamCount = 0;
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-10-08 12:00:00",
|
||||
expiration_reason: "trial",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
mockRPC(route, { args, method }) {
|
||||
if (route === "/web/webclient/load_menus") {
|
||||
return;
|
||||
}
|
||||
if (method === "get_param") {
|
||||
if (args[0] === "database.already_linked_subscription_url") {
|
||||
return false;
|
||||
}
|
||||
callToGetParamCount++;
|
||||
if (callToGetParamCount === 1) {
|
||||
return "2019-10-09 12:00:00";
|
||||
} else {
|
||||
return "2019-11-09 12:00:00";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"This database has expired. Register your subscription or buy a subscription."
|
||||
);
|
||||
assert.containsOnce(target, ".o_blockUI", "UI should be blocked");
|
||||
|
||||
assert.hasClass(
|
||||
target.querySelector(".database_expiration_panel"),
|
||||
"alert-danger",
|
||||
"Color should be red"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".oe_instance_register_show",
|
||||
"Part 'Register your subscription'"
|
||||
);
|
||||
assert.containsOnce(target, ".oe_instance_buy", "Part 'buy a subscription'");
|
||||
|
||||
assert.containsNone(target, ".oe_instance_register_form");
|
||||
|
||||
// Click on 'Register your subscription'
|
||||
await click(target.querySelector(".oe_instance_register_show"));
|
||||
await testUtils.fields.editInput(
|
||||
target.querySelector(".oe_instance_register_form input"),
|
||||
"ABC"
|
||||
);
|
||||
await click(target.querySelector(".oe_instance_register_form button"));
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"Thank you, your registration was successful! Your database is valid until November 9, 2019."
|
||||
);
|
||||
assert.containsNone(target, ".o_blockUI", "UI should no longer be blocked");
|
||||
});
|
||||
|
||||
QUnit.test("One app installed, renew", async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
patchDate(2019, 9, 10, 12, 0, 0);
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-10-20 12:00:00",
|
||||
expiration_reason: "renewal",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
mockRPC(route, { args, method }) {
|
||||
if (route === "/web/webclient/load_menus") {
|
||||
return;
|
||||
}
|
||||
if (method === "get_param") {
|
||||
assert.step("get_param");
|
||||
assert.strictEqual(args[0], "database.enterprise_code");
|
||||
return "ABC";
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"This database will expire in 10 days. Renew your subscription "
|
||||
);
|
||||
|
||||
assert.hasClass(
|
||||
target.querySelector(".database_expiration_panel"),
|
||||
"alert-warning",
|
||||
"Color should be red"
|
||||
);
|
||||
assert.containsOnce(target, ".oe_instance_renew", "Part 'Register your subscription'");
|
||||
assert.containsOnce(
|
||||
target,
|
||||
"a.check_enterprise_status",
|
||||
"there should be a button for status checking"
|
||||
);
|
||||
|
||||
assert.containsNone(target, ".oe_instance_register_form");
|
||||
|
||||
// Click on 'Renew your subscription'
|
||||
await click(target.querySelector(".oe_instance_renew"));
|
||||
|
||||
assert.verifySteps(["get_param"]);
|
||||
});
|
||||
|
||||
QUnit.test("One app installed, check status and get success", async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
patchDate(2019, 9, 10, 12, 0, 0);
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-10-20 12:00:00",
|
||||
expiration_reason: "renewal",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
mockRPC(route, { args, method }) {
|
||||
if (route === "/web/webclient/load_menus") {
|
||||
return;
|
||||
}
|
||||
if (method === "get_param") {
|
||||
assert.step("get_param");
|
||||
assert.strictEqual(args[0], "database.expiration_date");
|
||||
return "2019-10-24 12:00:00";
|
||||
}
|
||||
if (method === "update_notification") {
|
||||
assert.step("update_notification");
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
// click on "Refresh subscription status"
|
||||
const refreshButton = target.querySelector("a.check_enterprise_status");
|
||||
assert.strictEqual(refreshButton.getAttribute("aria-label"), "Refresh subscription status");
|
||||
await click(refreshButton);
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register.oe_subscription_updated").innerText,
|
||||
"Your subscription was updated and is valid until October 24, 2019."
|
||||
);
|
||||
|
||||
assert.verifySteps(["update_notification", "get_param"]);
|
||||
});
|
||||
|
||||
// Why would we want to reload the page when we check the status and it hasn't changed?
|
||||
QUnit.skip("One app installed, check status and get page reload", async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
patchDate(2019, 9, 10, 12, 0, 0);
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-10-20 12:00:00",
|
||||
expiration_reason: "renewal",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
mockRPC(route, { method }) {
|
||||
if (route === "/web/webclient/load_menus") {
|
||||
return;
|
||||
}
|
||||
if (method === "get_param") {
|
||||
assert.step("get_param");
|
||||
return "2019-10-20 12:00:00";
|
||||
}
|
||||
if (method === "update_notification") {
|
||||
assert.step("update_notification");
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
// click on "Refresh subscription status"
|
||||
await click(target.querySelector("a.check_enterprise_status"));
|
||||
|
||||
assert.verifySteps(["update_notification", "get_param", "reloadPage"]);
|
||||
});
|
||||
|
||||
QUnit.test("One app installed, upgrade database", async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
patchDate(2019, 9, 10, 12, 0, 0);
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-10-20 12:00:00",
|
||||
expiration_reason: "upsell",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
mockRPC(route, { args, method }) {
|
||||
if (route === "/web/webclient/load_menus") {
|
||||
return;
|
||||
}
|
||||
if (method === "get_param") {
|
||||
assert.step("get_param");
|
||||
assert.strictEqual(args[0], "database.enterprise_code");
|
||||
return "ABC";
|
||||
}
|
||||
if (method === "search_count") {
|
||||
assert.step("search_count");
|
||||
return 13;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"This database will expire in 10 days. You have more users or more apps installed than your subscription allows.\n" +
|
||||
"Upgrade your subscription "
|
||||
);
|
||||
|
||||
// click on "Upgrade your subscription"
|
||||
await click(target.querySelector("a.oe_instance_upsell"));
|
||||
|
||||
assert.verifySteps(["get_param", "search_count"]);
|
||||
});
|
||||
|
||||
QUnit.test("One app installed, message for non admin user", async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
patchDate(2019, 9, 10, 12, 0, 0);
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-11-08 12:00:00",
|
||||
expiration_reason: "",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "user",
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"This database will expire in 29 days. Log in as an administrator to correct the issue."
|
||||
);
|
||||
|
||||
assert.hasClass(
|
||||
target.querySelector(".database_expiration_panel"),
|
||||
"alert-info",
|
||||
"Color should be grey"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("One app installed, navigation to renewal page", async function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
patchDate(2019, 11, 10, 0, 0, 0);
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-10-20 12:00:00",
|
||||
expiration_reason: "renewal",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
mockRPC(route, { args, method }) {
|
||||
if (route === "/web/webclient/load_menus") {
|
||||
return;
|
||||
}
|
||||
if (method === "get_param") {
|
||||
assert.step("get_param");
|
||||
assert.strictEqual(args[0], "database.enterprise_code");
|
||||
return "ABC";
|
||||
}
|
||||
if (method === "update_notification") {
|
||||
assert.step("update_notification");
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"This database has expired. Renew your subscription "
|
||||
);
|
||||
|
||||
assert.hasClass(target.querySelector(".database_expiration_panel"), "alert-danger");
|
||||
assert.containsOnce(target, ".oe_instance_renew", "Part 'Register your subscription'");
|
||||
assert.containsOnce(
|
||||
target,
|
||||
"a.check_enterprise_status",
|
||||
"there should be a button for status checking"
|
||||
);
|
||||
|
||||
assert.containsNone(target, ".oe_instance_register_form");
|
||||
|
||||
// Click on 'Renew your subscription'
|
||||
await click(target.querySelector(".oe_instance_renew"));
|
||||
|
||||
|
||||
|
||||
assert.verifySteps(["get_param"]);
|
||||
});
|
||||
|
||||
QUnit.test("One app installed, different locale (arabic)", async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
patchDate(2019, 9, 25, 12, 0, 0);
|
||||
patchWithCleanup(luxon.Settings, {
|
||||
defaultLocale: "ar-001",
|
||||
defaultNumberingSystem: "arab",
|
||||
});
|
||||
|
||||
await createExpirationPanel({
|
||||
session: {
|
||||
expiration_date: "2019-10-20 12:00:00",
|
||||
expiration_reason: "renewal",
|
||||
notification_type: true, // used by subscription service to know whether mail is installed
|
||||
warning: "admin",
|
||||
},
|
||||
async mockRPC(route, { method }) {
|
||||
if (route === "/web/webclient/load_menus") {
|
||||
return;
|
||||
}
|
||||
if (method === "get_param") {
|
||||
return "2019-11-09 12:00:00";
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
await click(target, ".check_enterprise_status");
|
||||
|
||||
assert.strictEqual(
|
||||
target.querySelector(".oe_instance_register").innerText,
|
||||
"Your subscription was updated and is valid until ٩ نوفمبر ٢٠١٩."
|
||||
);
|
||||
});
|
||||
});
|
||||
370
web_enterprise/static/tests/webclient/home_menu_tests.js
Normal file
370
web_enterprise/static/tests/webclient/home_menu_tests.js
Normal file
@@ -0,0 +1,370 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerCleanup } from "@web/../tests/helpers/cleanup";
|
||||
import { makeTestEnv } from "@web/../tests/helpers/mock_env";
|
||||
import { makeFakeLocalizationService } from "@web/../tests/helpers/mock_services";
|
||||
import { getFixture, nextTick, triggerHotkey, patchWithCleanup } from "@web/../tests/helpers/utils";
|
||||
import { commandService } from "@web/core/commands/command_service";
|
||||
import { hotkeyService } from "@web/core/hotkeys/hotkey_service";
|
||||
import { ormService } from "@web/core/orm_service";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { uiService } from "@web/core/ui/ui_service";
|
||||
import { HomeMenu } from "@web_enterprise/webclient/home_menu/home_menu";
|
||||
import testUtils from "web.test_utils";
|
||||
import { enterpriseSubscriptionService } from "@web_enterprise/webclient/home_menu/enterprise_subscription_service";
|
||||
import { session } from "@web/session";
|
||||
import { templates } from "@web/core/assets";
|
||||
|
||||
|
||||
const { App, EventBus } = owl;
|
||||
const patchDate = testUtils.mock.patchDate;
|
||||
const serviceRegistry = registry.category("services");
|
||||
let target;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
async function createHomeMenu(homeMenuProps) {
|
||||
const env = await makeTestEnv();
|
||||
const app = new App(HomeMenu, {
|
||||
env,
|
||||
props: homeMenuProps,
|
||||
templates,
|
||||
test: true,
|
||||
});
|
||||
const homeMenu = await app.mount(target);
|
||||
registerCleanup(() => app.destroy());
|
||||
return homeMenu;
|
||||
}
|
||||
|
||||
async function walkOn(assert, path) {
|
||||
for (const step of path) {
|
||||
triggerHotkey(`${step.shiftKey ? "shift+" : ""}${step.key}`);
|
||||
await nextTick();
|
||||
assert.hasClass(
|
||||
target.querySelectorAll(".o_menuitem")[step.index],
|
||||
"o_focused",
|
||||
`step ${step.number}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Tests
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
let homeMenuProps;
|
||||
let bus;
|
||||
QUnit.module(
|
||||
"web_enterprise",
|
||||
{
|
||||
beforeEach: function () {
|
||||
homeMenuProps = {
|
||||
apps: [
|
||||
{
|
||||
actionID: 121,
|
||||
appID: 1,
|
||||
id: 1,
|
||||
label: "Discuss",
|
||||
parents: "",
|
||||
webIcon: false,
|
||||
xmlid: "app.1",
|
||||
},
|
||||
{
|
||||
actionID: 122,
|
||||
appID: 2,
|
||||
id: 2,
|
||||
label: "Calendar",
|
||||
parents: "",
|
||||
webIcon: false,
|
||||
xmlid: "app.2",
|
||||
},
|
||||
{
|
||||
actionID: 123,
|
||||
appID: 3,
|
||||
id: 3,
|
||||
label: "Contacts",
|
||||
parents: "",
|
||||
webIcon: false,
|
||||
xmlid: "app.3",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
bus = new EventBus();
|
||||
const fakeHomeMenuService = {
|
||||
name: "home_menu",
|
||||
start() {
|
||||
return {
|
||||
toggle(show) {
|
||||
bus.trigger("toggle", show);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
const fakeMenuService = {
|
||||
name: "menu",
|
||||
start() {
|
||||
return {
|
||||
selectMenu(menu) {
|
||||
bus.trigger("selectMenu", menu.id);
|
||||
},
|
||||
getMenu() {
|
||||
return {};
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
serviceRegistry.add("ui", uiService);
|
||||
serviceRegistry.add("hotkey", hotkeyService);
|
||||
serviceRegistry.add("command", commandService);
|
||||
serviceRegistry.add("localization", makeFakeLocalizationService());
|
||||
serviceRegistry.add("orm", ormService);
|
||||
serviceRegistry.add(enterpriseSubscriptionService.name, enterpriseSubscriptionService);
|
||||
serviceRegistry.add(fakeHomeMenuService.name, fakeHomeMenuService);
|
||||
serviceRegistry.add(fakeMenuService.name, fakeMenuService);
|
||||
|
||||
target = getFixture();
|
||||
},
|
||||
},
|
||||
function () {
|
||||
QUnit.module("HomeMenu");
|
||||
|
||||
QUnit.test("ESC Support", async function (assert) {
|
||||
bus.on("toggle", null, (show) => {
|
||||
assert.step(`toggle ${show}`);
|
||||
});
|
||||
await createHomeMenu(homeMenuProps);
|
||||
await testUtils.dom.triggerEvent(window, "keydown", { key: "Escape" });
|
||||
assert.verifySteps(["toggle false"]);
|
||||
});
|
||||
|
||||
QUnit.test("Click on an app", async function (assert) {
|
||||
bus.on("selectMenu", null, (menuId) => {
|
||||
assert.step(`selectMenu ${menuId}`);
|
||||
});
|
||||
await createHomeMenu(homeMenuProps);
|
||||
|
||||
await testUtils.dom.click(target.querySelectorAll(".o_menuitem")[0]);
|
||||
assert.verifySteps(["selectMenu 1"]);
|
||||
});
|
||||
|
||||
QUnit.test("Display Expiration Panel (no module installed)", async function (assert) {
|
||||
const unpatchDate = patchDate(2019, 9, 10, 0, 0, 0);
|
||||
registerCleanup(unpatchDate);
|
||||
|
||||
patchWithCleanup(session, {
|
||||
expiration_date: "2019-11-01 12:00:00",
|
||||
expiration_reason: "",
|
||||
isMailInstalled: false,
|
||||
warning: "admin",
|
||||
});
|
||||
let cookie = false;
|
||||
const mockedCookieService = {
|
||||
name: "cookie",
|
||||
start() {
|
||||
return {
|
||||
get current() {
|
||||
return cookie;
|
||||
},
|
||||
setCookie() {
|
||||
cookie = true;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
serviceRegistry.add(mockedCookieService.name, mockedCookieService);
|
||||
|
||||
await createHomeMenu(homeMenuProps);
|
||||
|
||||
assert.containsOnce(target, ".database_expiration_panel");
|
||||
assert.strictEqual(
|
||||
target.querySelector(".database_expiration_panel .oe_instance_register").innerText,
|
||||
"You will be able to register your database once you have installed your first app.",
|
||||
"There should be an expiration panel displayed"
|
||||
);
|
||||
|
||||
// Close the expiration panel
|
||||
await testUtils.dom.click(
|
||||
target.querySelector(".database_expiration_panel .oe_instance_hide_panel")
|
||||
);
|
||||
assert.containsNone(target, ".database_expiration_panel");
|
||||
});
|
||||
|
||||
QUnit.test("Navigation (only apps, only one line)", async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
homeMenuProps = {
|
||||
apps: new Array(3).fill().map((x, i) => {
|
||||
return {
|
||||
actionID: 120 + i,
|
||||
appID: i + 1,
|
||||
id: i + 1,
|
||||
label: `0${i}`,
|
||||
parents: "",
|
||||
webIcon: false,
|
||||
xmlid: `app.${i}`,
|
||||
};
|
||||
}),
|
||||
};
|
||||
await createHomeMenu(homeMenuProps);
|
||||
|
||||
const path = [
|
||||
{ number: 0, key: "ArrowDown", index: 0 },
|
||||
{ number: 1, key: "ArrowRight", index: 1 },
|
||||
{ number: 2, key: "Tab", index: 2 },
|
||||
{ number: 3, key: "ArrowRight", index: 0 },
|
||||
{ number: 4, key: "Tab", shiftKey: true, index: 2 },
|
||||
{ number: 5, key: "ArrowLeft", index: 1 },
|
||||
{ number: 6, key: "ArrowDown", index: 1 },
|
||||
{ number: 7, key: "ArrowUp", index: 1 },
|
||||
];
|
||||
|
||||
await walkOn(assert, path);
|
||||
});
|
||||
|
||||
QUnit.test("Navigation (only apps, two lines, one incomplete)", async function (assert) {
|
||||
assert.expect(19);
|
||||
|
||||
homeMenuProps = {
|
||||
apps: new Array(8).fill().map((x, i) => {
|
||||
return {
|
||||
actionID: 121,
|
||||
appID: i + 1,
|
||||
id: i + 1,
|
||||
label: `0${i}`,
|
||||
parents: "",
|
||||
webIcon: false,
|
||||
xmlid: `app.${i}`,
|
||||
};
|
||||
}),
|
||||
};
|
||||
await createHomeMenu(homeMenuProps);
|
||||
|
||||
const path = [
|
||||
{ number: 1, key: "ArrowRight", index: 0 },
|
||||
{ number: 2, key: "ArrowUp", index: 6 },
|
||||
{ number: 3, key: "ArrowUp", index: 0 },
|
||||
{ number: 4, key: "ArrowDown", index: 6 },
|
||||
{ number: 5, key: "ArrowDown", index: 0 },
|
||||
{ number: 6, key: "ArrowRight", index: 1 },
|
||||
{ number: 7, key: "ArrowRight", index: 2 },
|
||||
{ number: 8, key: "ArrowUp", index: 7 },
|
||||
{ number: 9, key: "ArrowUp", index: 1 },
|
||||
{ number: 10, key: "ArrowRight", index: 2 },
|
||||
{ number: 11, key: "ArrowDown", index: 7 },
|
||||
{ number: 12, key: "ArrowDown", index: 1 },
|
||||
{ number: 13, key: "ArrowUp", index: 7 },
|
||||
{ number: 14, key: "ArrowRight", index: 6 },
|
||||
{ number: 15, key: "ArrowLeft", index: 7 },
|
||||
{ number: 16, key: "ArrowUp", index: 1 },
|
||||
{ number: 17, key: "ArrowLeft", index: 0 },
|
||||
{ number: 18, key: "ArrowLeft", index: 5 },
|
||||
{ number: 19, key: "ArrowRight", index: 0 },
|
||||
];
|
||||
|
||||
await walkOn(assert, path);
|
||||
});
|
||||
|
||||
QUnit.test("Navigation and open an app in the home menu", async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
bus.on("selectMenu", null, (menuId) => {
|
||||
assert.step(`selectMenu ${menuId}`);
|
||||
});
|
||||
await createHomeMenu(homeMenuProps);
|
||||
|
||||
// No app selected so nothing to open
|
||||
await testUtils.dom.triggerEvent(window, "keydown", { key: "Enter" });
|
||||
assert.verifySteps([]);
|
||||
|
||||
const path = [
|
||||
{ number: 0, key: "ArrowDown", index: 0 },
|
||||
{ number: 1, key: "ArrowRight", index: 1 },
|
||||
{ number: 2, key: "Tab", index: 2 },
|
||||
{ number: 3, key: "shift+Tab", index: 1 },
|
||||
];
|
||||
|
||||
await walkOn(assert, path);
|
||||
|
||||
// open first app (Calendar)
|
||||
await testUtils.dom.triggerEvent(window, "keydown", { key: "Enter" });
|
||||
|
||||
assert.verifySteps(["selectMenu 2"]);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"The HomeMenu input takes the focus when you press a key only if no other element is the activeElement",
|
||||
async function (assert) {
|
||||
const target = getFixture();
|
||||
const homeMenu = await createHomeMenu(homeMenuProps);
|
||||
const input = target.querySelector(".o_search_hidden");
|
||||
assert.strictEqual(document.activeElement, input);
|
||||
|
||||
const activeElement = document.createElement("div");
|
||||
homeMenu.env.services.ui.activateElement(activeElement);
|
||||
// remove the focus from the input
|
||||
const otherInput = document.createElement("input");
|
||||
target.querySelector(".o_home_menu").appendChild(otherInput);
|
||||
otherInput.focus();
|
||||
otherInput.blur();
|
||||
assert.notEqual(document.activeElement, input);
|
||||
|
||||
await testUtils.dom.triggerEvent(window, "keydown", { key: "a" });
|
||||
await nextTick();
|
||||
assert.notEqual(document.activeElement, input);
|
||||
|
||||
homeMenu.env.services.ui.deactivateElement(activeElement);
|
||||
await testUtils.dom.triggerEvent(window, "keydown", { key: "a" });
|
||||
await nextTick();
|
||||
assert.strictEqual(document.activeElement, input);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"The HomeMenu input does not take the focus if it is already on another input",
|
||||
async function (assert) {
|
||||
const target = getFixture();
|
||||
await createHomeMenu(homeMenuProps);
|
||||
const homeMenuInput = target.querySelector(".o_search_hidden");
|
||||
assert.strictEqual(document.activeElement, homeMenuInput);
|
||||
|
||||
const otherInput = document.createElement("input");
|
||||
target.querySelector(".o_home_menu").appendChild(otherInput);
|
||||
otherInput.focus();
|
||||
await testUtils.dom.triggerEvent(window, "keydown", { key: "a" });
|
||||
await nextTick();
|
||||
assert.notEqual(document.activeElement, homeMenuInput);
|
||||
|
||||
otherInput.remove();
|
||||
await testUtils.dom.triggerEvent(window, "keydown", { key: "a" });
|
||||
await nextTick();
|
||||
assert.strictEqual(document.activeElement, homeMenuInput);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"The HomeMenu input does not take the focus if it is already on a textarea",
|
||||
async function (assert) {
|
||||
const target = getFixture();
|
||||
await createHomeMenu(homeMenuProps);
|
||||
const homeMenuInput = target.querySelector(".o_search_hidden");
|
||||
assert.strictEqual(document.activeElement, homeMenuInput);
|
||||
|
||||
const textarea = document.createElement("textarea");
|
||||
target.querySelector(".o_home_menu").appendChild(textarea);
|
||||
textarea.focus();
|
||||
await testUtils.dom.triggerEvent(window, "keydown", { key: "a" });
|
||||
await nextTick();
|
||||
assert.notEqual(document.activeElement, homeMenuInput);
|
||||
|
||||
textarea.remove();
|
||||
await testUtils.dom.triggerEvent(window, "keydown", { key: "a" });
|
||||
await nextTick();
|
||||
assert.strictEqual(document.activeElement, homeMenuInput);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,528 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
click,
|
||||
editInput,
|
||||
getFixture,
|
||||
nextTick,
|
||||
patchWithCleanup,
|
||||
} from "@web/../tests/helpers/utils";
|
||||
import { doAction, getActionManagerServerData, loadState } from "@web/../tests/webclient/helpers";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { editView } from "@web/views/debug_items";
|
||||
import { createEnterpriseWebClient } from "@web_enterprise/../tests/helpers";
|
||||
import { homeMenuService } from "@web_enterprise/webclient/home_menu/home_menu_service";
|
||||
import { ormService } from "@web/core/orm_service";
|
||||
import { enterpriseSubscriptionService } from "@web_enterprise/webclient/home_menu/enterprise_subscription_service";
|
||||
import { registerCleanup } from "@web/../tests/helpers/cleanup";
|
||||
import { errorService } from "@web/core/errors/error_service";
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
|
||||
const { Component, xml } = owl;
|
||||
|
||||
let serverData;
|
||||
let fixture;
|
||||
const serviceRegistry = registry.category("services");
|
||||
|
||||
// Should test ONLY the webClient and features present in Enterprise
|
||||
// Those tests rely on hidden view to be in CSS: display: none
|
||||
QUnit.module("WebClient Enterprise", (hooks) => {
|
||||
hooks.beforeEach(() => {
|
||||
serverData = getActionManagerServerData();
|
||||
fixture = getFixture();
|
||||
serviceRegistry.add("home_menu", homeMenuService);
|
||||
serviceRegistry.add("orm", ormService);
|
||||
serviceRegistry.add("enterprise_subscription", enterpriseSubscriptionService);
|
||||
});
|
||||
|
||||
QUnit.module("basic flow with home menu", (hooks) => {
|
||||
let mockRPC;
|
||||
hooks.beforeEach((assert) => {
|
||||
serverData.menus[1].actionID = 4;
|
||||
serverData.menus.root.children = [1];
|
||||
serverData.views["partner,false,form"] = `
|
||||
<form>
|
||||
<field name="display_name"/>
|
||||
<field name="m2o" open_target="current"/>
|
||||
</form>`;
|
||||
mockRPC = async (route) => {
|
||||
assert.step(route);
|
||||
if (route === "/web/dataset/call_kw/partner/get_formview_action") {
|
||||
return {
|
||||
type: "ir.actions.act_window",
|
||||
res_model: "partner",
|
||||
view_type: "form",
|
||||
view_mode: "form",
|
||||
views: [[false, "form"]],
|
||||
target: "current",
|
||||
res_id: 2,
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
QUnit.test("1 -- start up", async function (assert) {
|
||||
await createEnterpriseWebClient({ fixture, serverData, mockRPC });
|
||||
assert.verifySteps(["/web/webclient/load_menus"]);
|
||||
assert.ok(document.body.classList.contains("o_home_menu_background"));
|
||||
assert.containsOnce(fixture, ".o_home_menu");
|
||||
assert.isNotVisible(fixture.querySelector(".o_menu_toggle"));
|
||||
assert.containsOnce(fixture, ".o_app.o_menuitem");
|
||||
});
|
||||
|
||||
QUnit.test("2 -- navbar updates on displaying an action", async function (assert) {
|
||||
await createEnterpriseWebClient({ fixture, serverData, mockRPC });
|
||||
assert.verifySteps(["/web/webclient/load_menus"]);
|
||||
await click(fixture.querySelector(".o_app.o_menuitem"));
|
||||
assert.verifySteps([
|
||||
"/web/action/load",
|
||||
"/web/dataset/call_kw/partner/get_views",
|
||||
"/web/dataset/call_kw/partner/web_search_read",
|
||||
]);
|
||||
assert.notOk(document.body.classList.contains("o_home_menu_background"));
|
||||
assert.containsNone(fixture, ".o_home_menu");
|
||||
assert.containsOnce(fixture, ".o_kanban_view");
|
||||
const menuToggle = fixture.querySelector(".o_menu_toggle");
|
||||
assert.isVisible(menuToggle);
|
||||
assert.notOk(menuToggle.classList.contains("o_menu_toggle_back"));
|
||||
});
|
||||
|
||||
QUnit.test("3 -- push another action in the breadcrumb", async function (assert) {
|
||||
await createEnterpriseWebClient({ fixture, serverData, mockRPC });
|
||||
assert.verifySteps(["/web/webclient/load_menus"]);
|
||||
await click(fixture.querySelector(".o_app.o_menuitem"));
|
||||
assert.verifySteps([
|
||||
"/web/action/load",
|
||||
"/web/dataset/call_kw/partner/get_views",
|
||||
"/web/dataset/call_kw/partner/web_search_read",
|
||||
]);
|
||||
await click(fixture.querySelector(".o_kanban_record"));
|
||||
await nextTick(); // there is another tick to update navbar and destroy HomeMenu
|
||||
assert.verifySteps(["/web/dataset/call_kw/partner/read"]);
|
||||
assert.isVisible(fixture.querySelector(".o_menu_toggle"));
|
||||
assert.containsOnce(fixture, ".o_form_view");
|
||||
assert.strictEqual(
|
||||
fixture.querySelector(".breadcrumb-item.active").textContent,
|
||||
"First record"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("4 -- push a third action in the breadcrumb", async function (assert) {
|
||||
await createEnterpriseWebClient({ fixture, serverData, mockRPC });
|
||||
assert.verifySteps(["/web/webclient/load_menus"]);
|
||||
await click(fixture.querySelector(".o_app.o_menuitem"));
|
||||
assert.verifySteps([
|
||||
"/web/action/load",
|
||||
"/web/dataset/call_kw/partner/get_views",
|
||||
"/web/dataset/call_kw/partner/web_search_read",
|
||||
]);
|
||||
await click(fixture.querySelector(".o_kanban_record"));
|
||||
assert.verifySteps(["/web/dataset/call_kw/partner/read"]);
|
||||
await click(fixture, '.o_field_widget[name="m2o"] .o_external_button', true);
|
||||
assert.verifySteps([
|
||||
"/web/dataset/call_kw/partner/get_formview_action",
|
||||
"/web/dataset/call_kw/partner/get_views",
|
||||
"/web/dataset/call_kw/partner/read",
|
||||
]);
|
||||
assert.containsOnce(fixture, ".o_form_view");
|
||||
assert.strictEqual(
|
||||
fixture.querySelector(".breadcrumb-item.active").textContent,
|
||||
"Second record"
|
||||
);
|
||||
assert.containsN(fixture, ".breadcrumb-item", 3);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"5 -- switch to HomeMenu from an action with 2 breadcrumbs",
|
||||
async function (assert) {
|
||||
await createEnterpriseWebClient({ fixture, serverData, mockRPC });
|
||||
assert.verifySteps(["/web/webclient/load_menus"]);
|
||||
await click(fixture.querySelector(".o_app.o_menuitem"));
|
||||
assert.verifySteps([
|
||||
"/web/action/load",
|
||||
"/web/dataset/call_kw/partner/get_views",
|
||||
"/web/dataset/call_kw/partner/web_search_read",
|
||||
]);
|
||||
await click(fixture.querySelector(".o_kanban_record"));
|
||||
assert.verifySteps(["/web/dataset/call_kw/partner/read"]);
|
||||
await click(fixture, '.o_field_widget[name="m2o"] .o_external_button', true);
|
||||
assert.verifySteps([
|
||||
"/web/dataset/call_kw/partner/get_formview_action",
|
||||
"/web/dataset/call_kw/partner/get_views",
|
||||
"/web/dataset/call_kw/partner/read",
|
||||
]);
|
||||
const menuToggle = fixture.querySelector(".o_menu_toggle");
|
||||
await click(menuToggle);
|
||||
assert.verifySteps([]);
|
||||
assert.ok(menuToggle.classList.contains("o_menu_toggle_back"));
|
||||
assert.containsOnce(fixture, ".o_home_menu");
|
||||
assert.isNotVisible(fixture.querySelector(".o_form_view"));
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("6 -- back to underlying action with many breadcrumbs", async function (assert) {
|
||||
await createEnterpriseWebClient({ fixture, serverData, mockRPC });
|
||||
assert.verifySteps(["/web/webclient/load_menus"]);
|
||||
await click(fixture.querySelector(".o_app.o_menuitem"));
|
||||
assert.verifySteps([
|
||||
"/web/action/load",
|
||||
"/web/dataset/call_kw/partner/get_views",
|
||||
"/web/dataset/call_kw/partner/web_search_read",
|
||||
]);
|
||||
await click(fixture.querySelector(".o_kanban_record"));
|
||||
assert.verifySteps(["/web/dataset/call_kw/partner/read"]);
|
||||
await click(fixture, '.o_field_widget[name="m2o"] .o_external_button', true);
|
||||
assert.verifySteps([
|
||||
"/web/dataset/call_kw/partner/get_formview_action",
|
||||
"/web/dataset/call_kw/partner/get_views",
|
||||
"/web/dataset/call_kw/partner/read",
|
||||
]);
|
||||
const menuToggle = fixture.querySelector(".o_menu_toggle");
|
||||
await click(menuToggle);
|
||||
await click(menuToggle);
|
||||
// if we don't reload on going back to underlying action
|
||||
// assert.verifySteps(
|
||||
// [],
|
||||
// "the underlying view should not reload when toggling the HomeMenu to off"
|
||||
// );
|
||||
// endif
|
||||
// if we reload on going back to underlying action
|
||||
assert.verifySteps(
|
||||
["/web/dataset/call_kw/partner/read"],
|
||||
"the underlying view should reload when toggling the HomeMenu to off"
|
||||
);
|
||||
// endif
|
||||
assert.containsNone(fixture, ".o_home_menu");
|
||||
assert.containsOnce(fixture, ".o_form_view");
|
||||
assert.notOk(menuToggle.classList.contains("o_menu_toggle_back"));
|
||||
assert.strictEqual(
|
||||
fixture.querySelector(".breadcrumb-item.active").textContent,
|
||||
"Second record"
|
||||
);
|
||||
assert.containsN(fixture, ".breadcrumb-item", 3);
|
||||
});
|
||||
|
||||
QUnit.test("restore the newly created record in form view (legacy)", async (assert) => {
|
||||
const action = serverData.actions[6];
|
||||
delete action.res_id;
|
||||
action.target = "current";
|
||||
const webClient = await createEnterpriseWebClient({ fixture, serverData });
|
||||
|
||||
await doAction(webClient, 6);
|
||||
assert.containsOnce(fixture, ".o_form_view");
|
||||
assert.containsOnce(fixture, ".o_form_view .o_form_editable");
|
||||
await editInput(fixture, ".o_field_widget[name=display_name] input", "red right hand");
|
||||
await click(fixture.querySelector(".o_form_button_save"));
|
||||
assert.strictEqual(
|
||||
fixture.querySelector(".breadcrumb-item.active").textContent,
|
||||
"red right hand"
|
||||
);
|
||||
await click(fixture.querySelector(".o_menu_toggle"));
|
||||
assert.isNotVisible(fixture.querySelector(".o_form_view"));
|
||||
|
||||
await click(fixture.querySelector(".o_menu_toggle"));
|
||||
assert.containsOnce(fixture, ".o_form_view");
|
||||
assert.containsOnce(fixture, ".o_form_view .o_form_saved");
|
||||
assert.strictEqual(
|
||||
fixture.querySelector(".breadcrumb-item.active").textContent,
|
||||
"red right hand"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.skip("fast clicking on restore (implementation detail)", async (assert) => {
|
||||
assert.expect(6);
|
||||
|
||||
let doVeryFastClick = false;
|
||||
|
||||
class DelayedClientAction extends Component {
|
||||
setup() {
|
||||
owl.onMounted(() => {
|
||||
if (doVeryFastClick) {
|
||||
doVeryFastClick = false;
|
||||
click(fixture.querySelector(".o_menu_toggle"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
DelayedClientAction.template = xml`<div class='delayed_client_action'>
|
||||
<button t-on-click="resolve">RESOLVE</button>
|
||||
</div>`;
|
||||
|
||||
registry.category("actions").add("DelayedClientAction", DelayedClientAction);
|
||||
const webClient = await createEnterpriseWebClient({ fixture, serverData });
|
||||
await doAction(webClient, "DelayedClientAction");
|
||||
await nextTick();
|
||||
await click(fixture.querySelector(".o_menu_toggle"));
|
||||
assert.isVisible(fixture.querySelector(".o_home_menu"));
|
||||
assert.isNotVisible(fixture.querySelector(".delayed_client_action"));
|
||||
|
||||
doVeryFastClick = true;
|
||||
await click(fixture.querySelector(".o_menu_toggle"));
|
||||
await nextTick();
|
||||
// off homemenu
|
||||
assert.isVisible(fixture.querySelector(".o_home_menu"));
|
||||
assert.isNotVisible(fixture.querySelector(".delayed_client_action"));
|
||||
|
||||
await click(fixture.querySelector(".o_menu_toggle"));
|
||||
await nextTick();
|
||||
assert.containsNone(fixture, ".o_home_menu");
|
||||
assert.containsOnce(fixture, ".delayed_client_action");
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("clear unCommittedChanges when toggling home menu", async function (assert) {
|
||||
assert.expect(6);
|
||||
// Edit a form view, don't save, toggle home menu
|
||||
// the autosave feature of the Form view is activated
|
||||
// and relied upon by this test
|
||||
|
||||
const mockRPC = (route, args) => {
|
||||
if (args.method === "create") {
|
||||
assert.strictEqual(args.model, "partner");
|
||||
assert.deepEqual(args.args, [
|
||||
{
|
||||
display_name: "red right hand",
|
||||
foo: false,
|
||||
},
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
const webClient = await createEnterpriseWebClient({ fixture, serverData, mockRPC });
|
||||
await doAction(webClient, 3, { viewType: "form" });
|
||||
assert.containsOnce(fixture, ".o_form_view .o_form_editable");
|
||||
await editInput(fixture, ".o_field_widget[name=display_name] input", "red right hand");
|
||||
|
||||
await click(fixture.querySelector(".o_menu_toggle"));
|
||||
assert.containsNone(fixture, ".o_form_view");
|
||||
assert.containsNone(fixture, ".modal");
|
||||
assert.containsOnce(fixture, ".o_home_menu");
|
||||
});
|
||||
|
||||
QUnit.test("can have HomeMenu and dialog action", async function (assert) {
|
||||
const webClient = await createEnterpriseWebClient({ fixture, serverData });
|
||||
assert.containsOnce(fixture, ".o_home_menu");
|
||||
assert.containsNone(fixture, ".modal .o_form_view");
|
||||
await doAction(webClient, 5);
|
||||
assert.containsOnce(fixture, ".modal .o_form_view");
|
||||
assert.isVisible(fixture.querySelector(".modal .o_form_view"));
|
||||
assert.containsOnce(fixture, ".o_home_menu");
|
||||
});
|
||||
|
||||
QUnit.test("supports attachments of apps deleted", async function (assert) {
|
||||
// When doing a pg_restore without the filestore
|
||||
// LPE fixme: may not be necessary anymore since menus are not HomeMenu props anymore
|
||||
serverData.menus = {
|
||||
root: { id: "root", children: [1], name: "root", appID: "root" },
|
||||
1: {
|
||||
id: 1,
|
||||
appID: 1,
|
||||
actionID: 1,
|
||||
xmlid: "",
|
||||
name: "Partners",
|
||||
children: [],
|
||||
webIconData: "",
|
||||
webIcon: "bloop,bloop",
|
||||
},
|
||||
};
|
||||
patchWithCleanup(odoo, { debug: "1" });
|
||||
await createEnterpriseWebClient({ fixture, serverData });
|
||||
assert.containsOnce(fixture, ".o_home_menu");
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"debug manager resets to global items when home menu is displayed",
|
||||
async function (assert) {
|
||||
const debugRegistry = registry.category("debug");
|
||||
debugRegistry.category("view").add("editView", editView);
|
||||
debugRegistry.category("default").add("item_1", () => {
|
||||
return {
|
||||
type: "item",
|
||||
description: "globalItem",
|
||||
callback: () => {},
|
||||
sequence: 10,
|
||||
};
|
||||
});
|
||||
const mockRPC = async (route) => {
|
||||
if (route.includes("check_access_rights")) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
patchWithCleanup(odoo, { debug: "1" });
|
||||
const webClient = await createEnterpriseWebClient({ fixture, serverData, mockRPC });
|
||||
await click(fixture.querySelector(".o_debug_manager .dropdown-toggle"));
|
||||
assert.containsOnce(fixture, ".o_debug_manager .dropdown-item:contains('globalItem')");
|
||||
assert.containsNone(
|
||||
fixture,
|
||||
".o_debug_manager .dropdown-item:contains('Edit View: Kanban')"
|
||||
);
|
||||
await click(fixture.querySelector(".o_debug_manager .dropdown-toggle"));
|
||||
await doAction(webClient, 1);
|
||||
await click(fixture.querySelector(".o_debug_manager .dropdown-toggle"));
|
||||
assert.containsOnce(fixture, ".o_debug_manager .dropdown-item:contains('globalItem')");
|
||||
assert.containsOnce(
|
||||
fixture,
|
||||
".o_debug_manager .dropdown-item:contains('Edit View: Kanban')"
|
||||
);
|
||||
await click(fixture.querySelector(".o_menu_toggle"));
|
||||
await click(fixture.querySelector(".o_debug_manager .dropdown-toggle"));
|
||||
assert.containsOnce(fixture, ".o_debug_manager .dropdown-item:contains('globalItem')");
|
||||
assert.containsNone(
|
||||
fixture,
|
||||
".o_debug_manager .dropdown-item:contains('Edit View: Kanban')"
|
||||
);
|
||||
await click(fixture.querySelector(".o_debug_manager .dropdown-toggle"));
|
||||
await doAction(webClient, 3);
|
||||
await click(fixture.querySelector(".o_debug_manager .dropdown-toggle"));
|
||||
assert.containsOnce(fixture, ".o_debug_manager .dropdown-item:contains('globalItem')");
|
||||
assert.containsOnce(
|
||||
fixture,
|
||||
".o_debug_manager .dropdown-item:contains('Edit View: List')"
|
||||
);
|
||||
assert.containsNone(
|
||||
fixture,
|
||||
".o_debug_manager .dropdown-item:contains('Edit View: Kanban')"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"url state is well handled when going in and out of the HomeMenu",
|
||||
async function (assert) {
|
||||
const webClient = await createEnterpriseWebClient({ fixture, serverData });
|
||||
await nextTick();
|
||||
assert.deepEqual(webClient.env.services.router.current.hash, { action: "menu" });
|
||||
|
||||
await click(fixture.querySelector(".o_app.o_menuitem:nth-child(2)"));
|
||||
await nextTick();
|
||||
assert.deepEqual(webClient.env.services.router.current.hash, {
|
||||
action: 1002,
|
||||
menu_id: 2,
|
||||
});
|
||||
|
||||
await click(fixture.querySelector(".o_menu_toggle"));
|
||||
await nextTick();
|
||||
assert.deepEqual(webClient.env.services.router.current.hash, { action: "menu" });
|
||||
|
||||
await click(fixture.querySelector(".o_menu_toggle"));
|
||||
await nextTick();
|
||||
// if we reload on going back to underlying action
|
||||
// end if
|
||||
assert.deepEqual(webClient.env.services.router.current.hash, {
|
||||
action: 1002,
|
||||
menu_id: 2,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"underlying action's menu items are invisible when HomeMenu is displayed",
|
||||
async function (assert) {
|
||||
serverData.menus[1].children = [99];
|
||||
serverData.menus[99] = {
|
||||
id: 99,
|
||||
children: [],
|
||||
name: "SubMenu",
|
||||
appID: 1,
|
||||
actionID: 1002,
|
||||
xmlid: "",
|
||||
webIconData: undefined,
|
||||
webIcon: false,
|
||||
};
|
||||
await createEnterpriseWebClient({ fixture, serverData });
|
||||
assert.containsNone(fixture, "nav .o_menu_sections");
|
||||
assert.containsNone(fixture, "nav .o_menu_brand");
|
||||
await click(fixture.querySelector(".o_app.o_menuitem:nth-child(1)"));
|
||||
await nextTick();
|
||||
assert.containsOnce(fixture, "nav .o_menu_sections");
|
||||
assert.containsOnce(fixture, "nav .o_menu_brand");
|
||||
assert.isVisible(fixture.querySelector(".o_menu_sections"));
|
||||
assert.isVisible(fixture.querySelector(".o_menu_brand"));
|
||||
await click(fixture.querySelector(".o_menu_toggle"));
|
||||
assert.containsOnce(fixture, "nav .o_menu_sections");
|
||||
assert.containsOnce(fixture, "nav .o_menu_brand");
|
||||
assert.isNotVisible(fixture.querySelector(".o_menu_sections"));
|
||||
assert.isNotVisible(fixture.querySelector(".o_menu_brand"));
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("loadState back and forth keeps relevant keys in state", async function (assert) {
|
||||
const webClient = await createEnterpriseWebClient({ fixture, serverData });
|
||||
|
||||
await click(fixture.querySelector(".o_app.o_menuitem:nth-child(2)"));
|
||||
await nextTick();
|
||||
assert.containsOnce(fixture, ".test_client_action");
|
||||
assert.containsNone(fixture, ".o_home_menu");
|
||||
const state = webClient.env.services.router.current.hash;
|
||||
assert.deepEqual(state, {
|
||||
action: 1002,
|
||||
menu_id: 2,
|
||||
});
|
||||
|
||||
await loadState(webClient, {});
|
||||
assert.containsNone(fixture, ".test_client_action");
|
||||
assert.containsOnce(fixture, ".o_home_menu");
|
||||
assert.deepEqual(webClient.env.services.router.current.hash, {
|
||||
action: "menu",
|
||||
});
|
||||
|
||||
await loadState(webClient, state);
|
||||
assert.containsOnce(fixture, ".test_client_action");
|
||||
assert.containsNone(fixture, ".o_home_menu");
|
||||
assert.deepEqual(webClient.env.services.router.current.hash, state);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"go back to home menu using browser back button (i.e. loadState)",
|
||||
async function (assert) {
|
||||
const webClient = await createEnterpriseWebClient({ fixture, serverData });
|
||||
assert.containsOnce(fixture, ".o_home_menu");
|
||||
assert.isNotVisible(fixture.querySelector(".o_main_navbar .o_menu_toggle"));
|
||||
|
||||
await click(fixture.querySelector(".o_app.o_menuitem:nth-child(2)"));
|
||||
assert.containsOnce(fixture, ".test_client_action");
|
||||
assert.containsNone(fixture, ".o_home_menu");
|
||||
|
||||
await loadState(webClient, { action: "menu" }); // FIXME: this might need to be changed
|
||||
assert.containsNone(fixture, ".test_client_action");
|
||||
assert.containsOnce(fixture, ".o_home_menu");
|
||||
assert.isNotVisible(fixture.querySelector(".o_main_navbar .o_menu_toggle"));
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("initial action crashes", async (assert) => {
|
||||
const handler = (ev) => {
|
||||
// need to preventDefault to remove error from console (so python test pass)
|
||||
ev.preventDefault();
|
||||
};
|
||||
window.addEventListener("unhandledrejection", handler);
|
||||
registerCleanup(() => window.removeEventListener("unhandledrejection", handler));
|
||||
|
||||
patchWithCleanup(QUnit, {
|
||||
onUnhandledRejection: () => {},
|
||||
});
|
||||
|
||||
browser.location.hash = "#action=__test__client__action__&menu_id=1";
|
||||
const ClientAction = registry.category("actions").get("__test__client__action__");
|
||||
class Override extends ClientAction {
|
||||
setup() {
|
||||
super.setup();
|
||||
assert.step("clientAction setup");
|
||||
throw new Error("my error");
|
||||
}
|
||||
}
|
||||
registry.category("actions").add("__test__client__action__", Override, { force: true });
|
||||
|
||||
registry.category("services").add("error", errorService);
|
||||
|
||||
const webClient = await createEnterpriseWebClient({ fixture, serverData });
|
||||
assert.verifySteps(["clientAction setup"]);
|
||||
assert.containsOnce(fixture, "nav .o_menu_toggle");
|
||||
assert.isVisible(fixture.querySelector("nav .o_menu_toggle"));
|
||||
assert.strictEqual(fixture.querySelector(".o_action_manager").innerHTML, "");
|
||||
assert.deepEqual(webClient.env.services.router.current.hash, {
|
||||
action: "__test__client__action__",
|
||||
menu_id: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user