1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/timesheet_grid/static/tests/timesheet_grid_tests.js
2024-12-10 09:04:09 +07:00

667 lines
24 KiB
JavaScript

/** @odoo-module **/
import { click, getFixture, patchDate } from "@web/../tests/helpers/utils";
import { removeFacet } from "@web/../tests/search/helpers";
import { setupViewRegistries } from "@web/../tests/views/helpers";
import { start } from "@mail/../tests/helpers/test_utils";
import { addModelNamesToFetch } from "@bus/../tests/helpers/model_definitions_helpers";
import { TimesheetGridSetupHelper } from "./helpers";
let serverData, target, timesheetGridSetup;
addModelNamesToFetch(["project.project", "project.task"]);
QUnit.module("Views", (hooks) => {
hooks.beforeEach(async () => {
timesheetGridSetup = new TimesheetGridSetupHelper();
const result = await timesheetGridSetup.setupTimesheetGrid();
serverData = result.serverData;
target = getFixture();
setupViewRegistries();
});
QUnit.module("TimesheetGridView");
QUnit.test("basic timesheet - no groupby", async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[false, "grid"]],
context: { group_by: [] },
});
assert.containsN(
target,
".o_grid_component_timesheet_many2one_avatar_employee",
6,
"should have 6 employee avatars"
);
assert.containsN(
target,
".o_grid_component_timesheet_many2one",
11,
"should have 11 many2one widgets in total"
);
assert.containsN(
target,
".o_grid_row_title",
6,
"should have 6 rows displayed in the grid"
);
});
QUnit.test("basic timesheet - groupby employees", async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[false, "grid"]],
context: { group_by: ["employee_id"] },
});
assert.containsN(
target,
".o_grid_component_timesheet_many2one_avatar_employee",
4,
"should have 4 employee avatars"
);
assert.containsN(
target,
".o_grid_row_title",
4,
"should have 4 rows displayed in the grid"
);
});
QUnit.test("basic timesheet - groupby employees>task", async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[false, "grid"]],
context: { group_by: ["employee_id", "task_id"] },
});
assert.containsN(
target,
".o_grid_component_timesheet_many2one_avatar_employee",
6,
"should have 6 employee avatars"
);
assert.containsN(
target,
".o_grid_row_title",
6,
"should have 6 rows displayed in the grid"
);
assert.containsN(
target,
".o_grid_component_timesheet_many2one",
5,
"should have 5 many2one widgets in total"
);
assert.containsN(target, ".o_grid_component", 11, "should have 11 widgets in total");
});
QUnit.test("basic timesheet - groupby task>employees", async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[false, "grid"]],
context: { group_by: ["task_id", "employee_id"] },
});
assert.containsN(
target,
".o_grid_component_timesheet_many2one_avatar_employee",
6,
"should have 6 employee avatars"
);
assert.containsN(
target,
".o_grid_row_title",
6,
"should have 4 rows displayed in the grid"
);
assert.containsN(
target,
".o_grid_component_timesheet_many2one",
6,
"should have 6 many2one widgets in total"
);
assert.containsOnce(
target,
".o_grid_component_timesheet_many2one .o_grid_no_data",
"We should have one many2one widget with no data"
);
assert.containsN(target, ".o_grid_component", 12, "should have 12 widgets in total");
assert.containsOnce(
target,
".o_grid_component_timesheet_many2one .o_grid_no_data",
"should have 1 widget with no data"
);
});
QUnit.test("timesheet with employee section - no groupby", async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[1, "grid"]],
context: { group_by: [] },
});
assert.containsN(
target,
".o_grid_section_title .o_grid_component_timesheet_many2one_avatar_employee",
4,
"should have 4 sections with employee avatar"
);
assert.containsN(
target,
".o_grid_component_timesheet_many2one",
11,
"should have 11 many2one widgets in total"
);
assert.containsNone(
target,
".o_grid_row_title .o_grid_component_timesheet_many2one_avatar_employee",
"No employee avatar should be displayed in the rows"
);
assert.containsN(
target,
".o_grid_row_title .o_grid_component_timesheet_many2one",
11,
"The 11 many2one widgets should be displayed in the rows"
);
assert.containsNone(
target,
".o_grid_section_title .o_grid_component_timesheet_many2one",
"No many2one widgets should be displayed in the sections"
);
assert.containsN(
target,
".o_grid_section_title",
4,
"4 sections should be rendered in the grid view"
);
assert.containsN(
target,
".o_grid_row_title",
6,
"should have 6 rows displayed in the grid"
);
assert.containsN(
target,
".o_grid_add_line .btn-link",
2,
"should have 2 Add a line button"
);
});
QUnit.test("timesheet with employee section - groupby employees", async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[1, "grid"]],
context: { group_by: ["employee_id"] },
});
assert.containsNone(
target,
".o_grid_section_title .o_grid_component_timesheet_many2one_avatar_employee",
"No employee avatar should be displayed in the sections"
);
assert.containsN(
target,
".o_grid_row_title .o_grid_component_timesheet_many2one_avatar_employee",
4,
"should have 4 rows with employee avatar"
);
assert.containsNone(
target,
".o_grid_component_timesheet_many2one",
"No many2one widgets should be rendered"
);
assert.containsNone(
target,
".o_grid_section_title",
"No sections should be displayed in the grid"
);
assert.containsN(
target,
".o_grid_row_title",
4,
"4 rows should be rendered in the grid view"
);
});
QUnit.test("timesheet with employee section - groupby employee>task", async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[1, "grid"]],
context: { group_by: ["employee_id", "task_id"] },
});
assert.containsN(
target,
".o_grid_section_title .o_grid_component_timesheet_many2one_avatar_employee",
4,
"should have 4 sections with employee avatar"
);
assert.containsN(
target,
".o_grid_component_timesheet_many2one",
6,
"should have 6 many2one widgets in total"
);
assert.containsOnce(
target,
".o_grid_component_timesheet_many2one .o_grid_no_data",
"We should have one many2one widget with no data"
);
assert.containsNone(
target,
".o_grid_row_title .o_grid_component_timesheet_many2one_avatar_employee",
"No employee avatar should be displayed in the rows"
);
assert.containsN(
target,
".o_grid_row_title .o_grid_component_timesheet_many2one",
6,
"The 6 many2one widgets should be displayed in the rows"
);
assert.containsOnce(
target,
".o_grid_row_title .o_grid_component_timesheet_many2one .o_grid_no_data",
"We should have one many2one widget with no data"
);
assert.containsNone(
target,
".o_grid_section_title .o_grid_component_timesheet_many2one",
"No many2one widgets should be displayed in the sections"
);
assert.containsN(
target,
".o_grid_section_title",
4,
"4 sections should be rendered in the grid view"
);
assert.containsN(
target,
".o_grid_row_title",
6,
"should have 6 rows displayed in the grid"
);
});
QUnit.test("timesheet with employee section - groupby task>employees", async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[1, "grid"]],
context: { group_by: ["task_id", "employee_id"] },
});
assert.containsNone(
target,
".o_grid_section_title .o_grid_component_timesheet_many2one_avatar_employee",
"No employee avatar should be displayed in the sections"
);
assert.containsN(
target,
".o_grid_row_title .o_grid_component_timesheet_many2one_avatar_employee",
6,
"should have 4 rows with employee avatar"
);
assert.containsN(
target,
".o_grid_component_timesheet_many2one",
6,
"5 many2one widgets should be rendered"
);
assert.containsOnce(
target,
".o_grid_component_timesheet_many2one .o_grid_no_data",
"We should have one many2one widget with no data"
);
assert.containsNone(
target,
".o_grid_section_title",
"No sections should be displayed in the grid"
);
assert.containsN(
target,
".o_grid_row_title",
6,
"6 rows should be rendered in the grid view"
);
});
QUnit.test(
"timesheet avatar widget should not display overtime if in the view show the current period (today is displayed in the period)",
async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[1, "grid"]],
context: { group_by: [] },
});
assert.containsN(
target,
".o_grid_section_title .o_grid_component_timesheet_many2one_avatar_employee",
4,
"should have 4 sections with employee avatar"
);
assert.containsNone(
target,
".o_grid_section_title .o_timesheet_overtime_indication",
"No overtime indication should be displayed"
);
}
);
QUnit.test(
"timesheet avatar widget should display hours in gray if all the hours were performed",
async function (assert) {
patchDate(2017, 0, 31, 0, 0, 0);
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[1, "grid"]],
context: { group_by: [], grid_anchor: "2017-01-25" },
});
assert.containsN(
target,
".o_grid_section_title .o_grid_component_timesheet_many2one_avatar_employee",
4,
"should have 4 sections with employee avatar"
);
assert.containsN(
target,
".o_grid_section_title .o_timesheet_overtime_indication",
3,
"All the avatar should have a timesheet overtime indication displayed except one since he did his working hours without any overtime in the grid"
);
const sectionsTitleNodes = target.querySelectorAll(".o_grid_section_title");
const sectionWithDangerOvertimeTextContents = [];
const sectionWithSuccessOvertimeTextContents = [];
const sectionWithoutOvertimeTextContents = [];
for (const node of sectionsTitleNodes) {
const overtimeNode = node.querySelector(".o_timesheet_overtime_indication");
if (overtimeNode) {
if (overtimeNode.classList.contains("text-danger")) {
sectionWithDangerOvertimeTextContents.push(node.textContent);
} else {
sectionWithSuccessOvertimeTextContents.push(node.textContent);
}
} else {
sectionWithoutOvertimeTextContents.push(node.textContent);
}
}
assert.deepEqual(
sectionWithDangerOvertimeTextContents,
["Mario-198:00", "Toad-1.00"],
"Mario and Toad have not done all his working hours (the overtime indication for Toad is formatted in float since uom is Days and not hours)"
);
assert.deepEqual(
sectionWithSuccessOvertimeTextContents,
["Yoshi+04:00"],
"Yoshi should have done his working hours and even more."
);
assert.deepEqual(
sectionWithoutOvertimeTextContents,
["Luigi"],
"Luigi should have done his working hours without doing extra hours"
);
}
);
QUnit.test(
"employee overtime indication should be displayed in non-working days if timesheet recorded",
async function (assert) {
patchDate(2017, 0, 31, 0, 0, 0);
const { openView } = await start({
serverData: {
...serverData,
views: {
...serverData.views,
"analytic.line,2,grid": `<grid js_class="timesheet_grid" barchart_total="1" create_inline="1">
<field name="employee_id" type="row" section="1" widget="timesheet_many2one_avatar_employee"/>
<field name="project_id" type="row" widget="timesheet_many2one"/>
<field name="task_id" type="row" widget="timesheet_many2one"/>
<field name="date" type="col">
<range name="day" string="Day" span="day" step="day"/>
</field>
<field name="unit_amount" type="measure" widget="float_time"/>
</grid>`,
},
},
async mockRPC(route, args) {
if (args.method === "get_timesheet_and_working_hours_for_employees") {
return {
1: { units_to_work: 0, uom: "hours", worked_hours: 2 },
3: { units_to_work: 8, uom: "hours", worked_hours: 5.5 },
};
}
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[2, "grid"]],
context: { group_by: [], grid_anchor: "2017-01-25" },
});
assert.containsN(
target,
".o_grid_section_title .o_grid_component_timesheet_many2one_avatar_employee",
2,
"should have 4 sections with employee avatar"
);
assert.containsN(
target,
".o_grid_section_title .o_timesheet_overtime_indication",
2,
"All the avatar should have a timesheet overtime indication displayed except one since he did his working hours without any overtime in the grid"
);
const sectionsTitleNodes = target.querySelectorAll(".o_grid_section_title");
const sectionWithDangerOvertimeTextContents = [];
const sectionWithSuccessOvertimeTextContents = [];
const sectionWithoutOvertimeTextContents = [];
for (const node of sectionsTitleNodes) {
const overtimeNode = node.querySelector(".o_timesheet_overtime_indication");
if (overtimeNode) {
if (overtimeNode.classList.contains("text-danger")) {
sectionWithDangerOvertimeTextContents.push(node.textContent);
} else {
sectionWithSuccessOvertimeTextContents.push(node.textContent);
}
} else {
sectionWithoutOvertimeTextContents.push(node.textContent);
}
}
assert.deepEqual(
sectionWithDangerOvertimeTextContents,
["Yoshi-02:30"],
"Mario and Toad have not done all his working hours (the overtime indication for Toad is formatted in float since uom is Days and not hours)"
);
assert.deepEqual(
sectionWithSuccessOvertimeTextContents,
["Mario+02:00"],
"Yoshi should have done his working hours and even more."
);
}
);
QUnit.test("when in Next week date should be first working day", async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[false, "grid"]],
context: { group_by: [] },
});
await click(target, ".o_grid_navigation_buttons > div > button > span.oi-arrow-right");
await click(target, ".o_control_panel_main_buttons .d-none.d-xl-inline-flex .o_grid_button_add");
assert.containsOnce(target, ".modal");
assert.strictEqual(
target.querySelector(".modal .o_field_widget[name=date] input").value,
"01/30/2017"
);
});
QUnit.test("when in Previous week date should be first working day", async function (assert) {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[false, "grid"]],
context: { group_by: [] },
});
await click(target, ".o_grid_navigation_buttons > div > button > span.oi-arrow-left");
await click(target, ".o_control_panel_main_buttons .d-none.d-xl-inline-flex .o_grid_button_add");
assert.containsOnce(target, ".modal");
assert.strictEqual(
target.querySelector(".modal .o_field_widget[name=date] input").value,
"01/16/2017"
);
});
QUnit.test("display sample data and then data + fetch last validate timesheet date", async (assert) => {
serverData.views["analytic.line,1,grid"] = serverData.views["analytic.line,1,grid"].replace("<grid", "<grid sample='1'");
const { openView } = await start({
serverData,
async mockRPC(route, args) {
if (args.method === "get_last_validated_timesheet_date") {
assert.step("get_last_validated_timesheet_date");
}
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[1, "grid"]],
context: { search_default_nothing: 1 },
});
assert.containsOnce(target, ".o_view_sample_data");
await removeFacet(target);
assert.containsNone(target, ".o_grid_sample_data");
assert.containsN(target, ".o_grid_section_title", 4);
assert.verifySteps(["get_last_validated_timesheet_date"]); // the rpc should be called only once
});
QUnit.test("test grid unavailibility", async (assert) => {
const { openView } = await start({
serverData,
async mockRPC(route, args) {
if (args.method === "grid_unavailability") {
return {
1: ["2017-01-22", "2017-01-24", "2017-01-28"],
2: ["2017-01-22", "2017-01-28"],
3: ["2017-01-22", "2017-01-28"],
4: ["2017-01-22", "2017-01-28"],
false: ["2017-01-22", "2017-01-28"],
};
}
return await timesheetGridSetup.mockTimesheetGridRPC(route, args);
},
});
await openView({
res_model: "analytic.line",
views: [[1, "grid"]],
context: { group_by: [] },
});
assert.containsN(target, ".o_grid_section_title", 4);
assert.containsN(target, ".o_grid_row_title", 6);
assert.containsN(target, ".o_grid_add_line_first_cell", 2);
assert.containsN(
target,
".o_grid_unavailable",
(1 + 4 + 6 + 2 + 1) * 2 + 3,
"2 whole columns and 3 cells for employee Mario in 2017-01-24 column."
);
});
});