/** @odoo-module **/ import { getFixture, nextTick, patchDate } from "@web/../tests/helpers/utils"; import { registerCleanup } from "@web/../tests/helpers/cleanup"; import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; import { createWebClient, doAction } from "@web/../tests/webclient/helpers"; import { CLASSES, SELECTORS } from "./helpers"; let serverData; /** @type {HTMLElement} */ let target; QUnit.module("Views > GanttView - Mobile", { beforeEach() { patchDate(2018, 11, 20, 8, 0, 0); setupViewRegistries(); target = getFixture(); serverData = { models: { tasks: { fields: { id: { string: "ID", type: "integer" }, start: { string: "Start Date", type: "datetime" }, stop: { string: "Stop Date", type: "datetime" }, user_id: { string: "Assign To", type: "many2one", relation: "users" }, }, records: [ { id: 1, start: "2018-11-30 18:30:00", stop: "2018-12-31 18:29:59", user_id: 1, }, { id: 2, start: "2018-12-17 11:30:00", stop: "2018-12-22 06:29:59", user_id: 2, }, { id: 3, start: "2018-12-27 06:30:00", stop: "2019-01-03 06:29:59", user_id: 2, }, { id: 4, start: "2018-12-19 22:30:00", stop: "2018-12-20 06:29:59", user_id: 1, }, { id: 5, start: "2018-11-08 01:53:10", stop: "2018-12-04 01:34:34", user_id: 1, }, ], }, users: { fields: { id: { string: "ID", type: "integer" }, name: { string: "Name", type: "char" }, }, records: [ { id: 1, name: "User 1" }, { id: 2, name: "User 2" }, ], }, }, }; }, }); QUnit.test("Progressbar: check the progressbar percentage visibility.", async (assert) => { assert.expect(19); await makeView({ type: "gantt", resModel: "tasks", serverData, arch: ` `, mockRPC(route, { method, model, args }) { if (method === "gantt_progress_bar") { assert.strictEqual(model, "tasks"); assert.deepEqual(args[0], ["user_id"]); assert.deepEqual(args[1], { user_id: [1, 2] }); return { user_id: { 1: { value: 50, max_value: 100 }, 2: { value: 25, max_value: 200 }, }, }; } }, }); assert.containsN(target, SELECTORS.progressBar, 2); const [progressBar1, progressBar2] = target.querySelectorAll(SELECTORS.progressBar); assert.hasClass(progressBar1, "o_gantt_group_success"); assert.hasClass(progressBar2, "o_gantt_group_success"); const [rowHeader1, rowHeader2] = [progressBar1.parentElement, progressBar2.parentElement]; assert.ok(rowHeader1.matches(SELECTORS.rowHeader)); assert.ok(rowHeader2.matches(SELECTORS.rowHeader)); assert.doesNotHaveClass(rowHeader1, CLASSES.group); assert.doesNotHaveClass(rowHeader2, CLASSES.group); assert.deepEqual( [...target.querySelectorAll(SELECTORS.progressBarBackground)].map((el) => el.style.width), ["50%", "12.5%"] ); assert.containsN(target, SELECTORS.progressBarForeground, 2, "foreground is visible in mobile"); assert.deepEqual( [...target.querySelectorAll(SELECTORS.progressBarForeground)].map((el) => el.textContent), ["50h / 100h", "25h / 200h"] ); // Check the style of one of the progress bars assert.strictEqual(rowHeader1.children.length, 2); const rowTitle1 = rowHeader1.children[0]; assert.ok(rowTitle1.matches(SELECTORS.rowTitle)); assert.strictEqual(rowTitle1.nextElementSibling, progressBar1); assert.strictEqual(window.getComputedStyle(rowHeader1).gridTemplateRows, "36px 35px"); assert.strictEqual(window.getComputedStyle(rowTitle1).height, "36px"); assert.strictEqual(window.getComputedStyle(progressBar1).height, "35px"); }); QUnit.test("Progressbar: grouped row", async (assert) => { assert.expect(19); // Here the view is grouped twice on the same field. // This is not a common use case, but it is possible to achieve it // bu saving a default favorite with a groupby then apply it twice // on the same field through the groupby menu. // In this case, the progress bar should be displayed only once, // on the first level of grouping. await makeView({ type: "gantt", resModel: "tasks", serverData, arch: ` `, mockRPC(route, { method, model, args }) { if (method === "gantt_progress_bar") { assert.strictEqual(model, "tasks"); assert.deepEqual(args[0], ["user_id"]); assert.deepEqual(args[1], { user_id: [1, 2] }); return { user_id: { 1: { value: 50, max_value: 100 }, 2: { value: 25, max_value: 200 }, }, }; } }, }); assert.containsN(target, SELECTORS.progressBar, 2); const [progressBar1, progressBar2] = target.querySelectorAll(SELECTORS.progressBar); assert.hasClass(progressBar1, "o_gantt_group_success"); assert.hasClass(progressBar2, "o_gantt_group_success"); const [rowHeader1, rowHeader2] = [progressBar1.parentElement, progressBar2.parentElement]; assert.ok(rowHeader1.matches(SELECTORS.rowHeader)); assert.ok(rowHeader2.matches(SELECTORS.rowHeader)); assert.hasClass(rowHeader1, CLASSES.group); assert.hasClass(rowHeader2, CLASSES.group); assert.deepEqual( [...target.querySelectorAll(SELECTORS.progressBarBackground)].map((el) => el.style.width), ["50%", "12.5%"] ); assert.containsN(target, SELECTORS.progressBarForeground, 2, "foreground is visible in mobile"); assert.deepEqual( [...target.querySelectorAll(SELECTORS.progressBarForeground)].map((el) => el.textContent), ["50h / 100h", "25h / 200h"] ); // Check the style of one of the progress bars assert.strictEqual(rowHeader1.children.length, 2); const rowTitle1 = rowHeader1.children[0]; assert.ok(rowTitle1.matches(SELECTORS.rowTitle)); assert.strictEqual(rowTitle1.nextElementSibling, progressBar1); assert.strictEqual(window.getComputedStyle(rowHeader1).gridTemplateRows, "24px 35px"); assert.strictEqual(window.getComputedStyle(rowTitle1).height, "24px"); assert.strictEqual(window.getComputedStyle(progressBar1).height, "35px"); }); QUnit.test("horizontal scroll applies to the content [SMALL SCREEN]", async (assert) => { // for this test, we need the elements to be visible in the viewport target = document.body; target.classList.add("debug"); registerCleanup(() => target.classList.remove("debug")); serverData.views = { "tasks,false,search": ``, "tasks,false,gantt": ` `, }; const webclient = await createWebClient({ serverData, target }); await doAction(webclient, { res_model: "tasks", type: "ir.actions.act_window", views: [[false, "gantt"]], }); const o_view_controller = target.querySelector(".o_view_controller"); const o_content = target.querySelector(".o_content"); const firstHeaderCell = target.querySelector(SELECTORS.headerCell); const initialXHeaderCell = firstHeaderCell.getBoundingClientRect().x; assert.hasClass( o_view_controller, "o_action_delegate_scroll", "the 'o_view_controller' should be have the 'o_action_delegate_scroll'." ); assert.strictEqual( window.getComputedStyle(o_view_controller).overflow, "hidden", "The view controller should have overflow hidden" ); assert.strictEqual( window.getComputedStyle(o_content).overflow, "auto", "The view content should have the overflow auto" ); assert.strictEqual(o_content.scrollLeft, 0, "Te o_content should not have scroll value"); // Horizontal scroll o_content.scrollLeft = 100; await nextTick(); assert.strictEqual( o_content.scrollLeft, 100, "the o_content should be 100 due to the overflow auto" ); assert.ok( firstHeaderCell.getBoundingClientRect().x === initialXHeaderCell - 100, "the gantt header cell x position value should be lower after the scroll" ); });