358 lines
12 KiB
JavaScript
358 lines
12 KiB
JavaScript
import { beforeEach, describe, expect, test } from "@odoo/hoot";
|
|
import { click, queryAll, queryFirst } from "@odoo/hoot-dom";
|
|
import { animationFrame, mockDate } from "@odoo/hoot-mock";
|
|
|
|
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
|
import { fields, mountView, onRpc } from "@web/../tests/web_test_helpers";
|
|
|
|
import { definePlanningModels, planningModels } from "./planning_mock_models";
|
|
|
|
describe.current.tags("desktop");
|
|
|
|
/* Main Goals of these tests:
|
|
- Tests the change made in planning to avatar card preview for resource:
|
|
- Roles appear as tags on the card
|
|
- Card should be displayed for material resources with at least 2 roles
|
|
- Test the integration of the card in the Gantt view
|
|
*/
|
|
|
|
/* 1. Create data
|
|
4 type of records tested:
|
|
- Planning slot linked to a material resource with only one role
|
|
- clicking the icon should not open any popover
|
|
- Planning slot linked to a material resource with two roles
|
|
- clicking the icon should open a card popover with resource name and roles
|
|
- Planning slot linked to a human resource not linked to a user
|
|
- a card popover should open including the roles of the employee
|
|
- Planning slot linked to a human resource linked to a user
|
|
- a card popover should open including the roles of the employee
|
|
*/
|
|
|
|
class PlanningSlot extends planningModels.PlanningSlot {
|
|
resource_roles = fields.One2many({ relation: "planning.role" });
|
|
|
|
_records = [
|
|
{
|
|
display_name: "Planning Slot tester 1",
|
|
resource_id: 1,
|
|
resource_type: "material",
|
|
resource_roles: [1],
|
|
user_id: false,
|
|
start_datetime: "2023-11-09 00:00:00",
|
|
end_datetime: "2023-11-09 22:00:00",
|
|
},
|
|
{
|
|
display_name: "Planning slot integration tester",
|
|
resource_id: 2,
|
|
resource_type: "material",
|
|
resource_roles: [1, 2],
|
|
user_id: false,
|
|
start_datetime: "2023-11-09 00:00:00",
|
|
end_datetime: "2023-11-09 22:00:00",
|
|
},
|
|
{
|
|
display_name: "Planning slot Marie",
|
|
resource_id: 3,
|
|
resource_type: "user",
|
|
resource_roles: [1],
|
|
user_id: false,
|
|
start_datetime: "2023-11-09 00:00:00",
|
|
end_datetime: "2023-11-09 22:00:00",
|
|
},
|
|
{
|
|
display_name: "Planning Slot Pierre",
|
|
resource_id: 4,
|
|
resource_type: "user",
|
|
resource_roles: [2],
|
|
user_id: 1,
|
|
start_datetime: "2023-11-09 00:00:00",
|
|
end_datetime: "2023-11-09 22:00:00",
|
|
},
|
|
];
|
|
}
|
|
|
|
class PlanningRole extends planningModels.PlanningRole {
|
|
_records = [
|
|
{
|
|
id: 1,
|
|
name: "Tester",
|
|
color: 1,
|
|
},
|
|
{
|
|
id: 2,
|
|
name: "It Specialist",
|
|
color: 2,
|
|
},
|
|
];
|
|
}
|
|
|
|
class ResourceResource extends planningModels.ResourceResource {
|
|
_records = [
|
|
{
|
|
id: 1,
|
|
name: "Continuity testing computer",
|
|
resource_type: "material",
|
|
role_ids: [1],
|
|
},
|
|
{
|
|
id: 2,
|
|
name: "Integration testing computer",
|
|
resource_type: "material",
|
|
role_ids: [1, 2],
|
|
},
|
|
{
|
|
id: 3,
|
|
name: "Marie",
|
|
resource_type: "user",
|
|
role_ids: [1],
|
|
},
|
|
{
|
|
id: 4,
|
|
name: "Pierre",
|
|
resource_type: "user",
|
|
role_ids: [2],
|
|
user_id: 1,
|
|
im_status: "online",
|
|
},
|
|
];
|
|
}
|
|
|
|
class HrEmployee extends planningModels.HrEmployee {
|
|
_records = [
|
|
{
|
|
id: 1,
|
|
name: "Marie",
|
|
resource_id: 3,
|
|
},
|
|
{
|
|
id: 2,
|
|
name: "Pierre",
|
|
resource_id: 4,
|
|
user_id: 1,
|
|
user_partner_id: 1,
|
|
},
|
|
];
|
|
}
|
|
|
|
// Imitating the server behavior by creating an hr.employee.public record with the same data and same id
|
|
class HrEmployeePublic extends planningModels.HrEmployeePublic {
|
|
_records = [
|
|
{
|
|
id: 1,
|
|
name: "Marie",
|
|
},
|
|
{
|
|
id: 2,
|
|
name: "Pierre",
|
|
user_id: 1,
|
|
user_partner_id: 1,
|
|
},
|
|
];
|
|
}
|
|
|
|
planningModels.PlanningSlot = PlanningSlot;
|
|
planningModels.PlanningRole = PlanningRole;
|
|
planningModels.ResourceResource = ResourceResource;
|
|
planningModels.HrEmployee = HrEmployee;
|
|
planningModels.HrEmployeePublic = HrEmployeePublic;
|
|
|
|
definePlanningModels();
|
|
|
|
onRpc("get_avatar_card_data", function ({ args }) {
|
|
const [ids, fields] = args[0];
|
|
return this.env["resource.resource"].read(ids, fields);
|
|
});
|
|
|
|
beforeEach(() => {
|
|
mailModels.ResUsers._records.push({
|
|
id: 1,
|
|
name: "Pierre",
|
|
partner_id: 1,
|
|
});
|
|
});
|
|
|
|
test("many2one_avatar_resource widget in kanban view", async () => {
|
|
await mountView({
|
|
resModel: "planning.slot",
|
|
type: "kanban",
|
|
arch: `<kanban>
|
|
<templates>
|
|
<t t-name="card">
|
|
<field name="display_name"/>
|
|
<field name="resource_id" widget="many2one_avatar_resource"/>
|
|
</t>
|
|
</templates>
|
|
</kanban>
|
|
`,
|
|
});
|
|
|
|
expect(".o_m2o_avatar").toHaveCount(4);
|
|
|
|
// fa-wrench should be displayed for first two planning slots
|
|
expect(".o_m2o_avatar > span.o_material_resource > i.fa-wrench").toHaveCount(2, {
|
|
message:
|
|
"material icon should be displayed for the first two gantt rows (material resources)",
|
|
});
|
|
|
|
// Third and fourth slots should display employee avatar
|
|
expect(".o_field_many2one_avatar_resource img").toHaveCount(2);
|
|
expect(
|
|
queryFirst(
|
|
".o_kanban_record:nth-of-type(3) .o_field_many2one_avatar_resource img"
|
|
).getAttribute("data-src")
|
|
).toBe("/web/image/resource.resource/3/avatar_128", {
|
|
message: "There should be the ID 3 in the URL as it is the one of resource 'Marie'",
|
|
});
|
|
expect(
|
|
queryFirst(
|
|
".o_kanban_record:nth-of-type(4) .o_field_many2one_avatar_resource img"
|
|
).getAttribute("data-src")
|
|
).toBe("/web/image/resource.resource/4/avatar_128", {
|
|
message: "There should be the ID 4 in the URL as it is the one of resource 'Pierre'",
|
|
});
|
|
|
|
// 1. Clicking on material resource's icon with only one role
|
|
await click(".o_kanban_record:nth-of-type(1) .o_m2o_avatar i");
|
|
await animationFrame();
|
|
expect(".o_avatar_card").toHaveCount(0);
|
|
|
|
// 2. Clicking on material resource's icon with two roles
|
|
await click(".o_kanban_record:nth-of-type(2) .o_m2o_avatar i");
|
|
await animationFrame();
|
|
expect(".o_avatar_card").toHaveCount(1);
|
|
expect(".o_avatar_card .o_avatar > img").toHaveCount(0, {
|
|
message: "There should not be any avatar for material resource",
|
|
});
|
|
expect(".o_avatar_card_buttons button").toHaveCount(0);
|
|
expect(".o_avatar_card .o_resource_roles_tags .o_tag").toHaveCount(2, {
|
|
message: "Roles should be listed in the card",
|
|
});
|
|
|
|
// 3. Clicking on human resource's avatar with no user associated
|
|
await click(".o_kanban_record:nth-of-type(3) .o_m2o_avatar img");
|
|
await animationFrame();
|
|
expect(".o_card_user_infos span:first").toHaveText("Marie");
|
|
|
|
// 4. Clicking on human resource's avatar with one user associated
|
|
await click(".o_kanban_record:nth-of-type(4) .o_m2o_avatar img");
|
|
await animationFrame();
|
|
expect(".o_card_user_infos span:first").toHaveText("Pierre");
|
|
});
|
|
|
|
test("Employee avatar in Gantt view", async () => {
|
|
mockDate("2023-11-08 8:00:00", 0);
|
|
onRpc("get_gantt_data", ({ kwargs, parent }) => {
|
|
const result = parent();
|
|
expect(kwargs.progress_bar_fields).toEqual(["resource_id"]);
|
|
result.progress_bars.resource_id = {
|
|
1: {
|
|
value: 100,
|
|
max_value: 100,
|
|
is_material_resource: true,
|
|
resource_color: 1,
|
|
display_popover_material_resource: false,
|
|
employee_id: false,
|
|
},
|
|
2: {
|
|
value: 100,
|
|
max_value: 100,
|
|
is_material_resource: true,
|
|
resource_color: 1,
|
|
display_popover_material_resource: true, // Testing this full behavior would require a tour
|
|
employee_id: false,
|
|
},
|
|
3: {
|
|
value: 100,
|
|
max_value: 100,
|
|
is_material_resource: false,
|
|
resource_color: false,
|
|
display_popover_material_resource: false,
|
|
employee_id: 1,
|
|
},
|
|
4: {
|
|
value: 100,
|
|
max_value: 100,
|
|
is_material_resource: false,
|
|
resource_color: false,
|
|
display_popover_material_resource: false,
|
|
employee_id: 2,
|
|
},
|
|
};
|
|
result.planning_data = {
|
|
"work_intervals": {
|
|
1: [
|
|
["2022-10-10 06:00:00", "2022-10-10 10:00:00"], //Monday 4h
|
|
["2022-10-11 06:00:00", "2022-10-11 10:00:00"], //Tuesday 5h
|
|
["2022-10-11 11:00:00", "2022-10-11 12:00:00"],
|
|
["2022-10-12 06:00:00", "2022-10-12 10:00:00"], //Wednesday 6h
|
|
["2022-10-12 11:00:00", "2022-10-12 13:00:00"],
|
|
["2022-10-13 06:00:00", "2022-10-13 10:00:00"], //Thursday 7h
|
|
["2022-10-13 11:00:00", "2022-10-13 14:00:00"],
|
|
["2022-10-14 06:00:00", "2022-10-14 10:00:00"], //Friday 8h
|
|
["2022-10-14 11:00:00", "2022-10-14 15:00:00"],
|
|
],
|
|
2: [],
|
|
3: [],
|
|
4: [],
|
|
},
|
|
"is_flexible": {},
|
|
"avg_hours": {},
|
|
}
|
|
return result;
|
|
});
|
|
await mountView({
|
|
resModel: "planning.slot",
|
|
type: "gantt",
|
|
arch: `<gantt js_class="planning_gantt" date_start="start_datetime" date_stop="end_datetime" progress_bar="resource_id"/>`,
|
|
groupBy: ["resource_id"],
|
|
});
|
|
expect(".o_gantt_row_title .o_avatar").toHaveCount(4);
|
|
expect(".o_avatar .o_material_resource .fa-wrench").toHaveCount(2, {
|
|
message:
|
|
"material icon should be displayed for the first two gantt rows (material resources)",
|
|
});
|
|
expect(".o_gantt_row_title .o_avatar img").toHaveCount(2, {
|
|
message: "avatar should be displayed for the third and fourth gantt rows (human resources)",
|
|
});
|
|
expect(queryAll(".o_gantt_row_title .o_avatar img")[1].getAttribute("data-src")).toBe(
|
|
"/web/image/resource.resource/4/avatar_128",
|
|
{
|
|
message:
|
|
"avatar of the employee associated to the human resource should be displayed on fourth row",
|
|
}
|
|
);
|
|
|
|
// 1. Clicking on material resource's icon with only one role
|
|
await click(".o_avatar .o_material_resource .fa-wrench");
|
|
await animationFrame();
|
|
expect(".o_avatar_card").toHaveCount(0);
|
|
|
|
// 2. Clicking on material resource's icon with two roles
|
|
await click(queryAll(".o_avatar .o_material_resource .fa-wrench")[1]);
|
|
await animationFrame();
|
|
expect(".o_avatar_card").toHaveCount(1);
|
|
expect(".o_avatar_card .o_avatar > img").toHaveCount(0, {
|
|
message: "There should not be any avatar for material resource",
|
|
});
|
|
expect(".o_avatar_card_buttons button").toHaveCount(0);
|
|
expect(".o_avatar_card .o_resource_roles_tags .o_tag").toHaveCount(2, {
|
|
message: "Roles should be listed in the card",
|
|
});
|
|
|
|
// 3. Clicking on human resource's avatar with no user associated
|
|
await click(".o_gantt_row_title .o_avatar img");
|
|
await animationFrame();
|
|
expect(".o_card_user_infos span:first").toHaveText("Marie");
|
|
expect(".o_avatar_card").toHaveCount(1, {
|
|
message: "Only one popover resource card should be opened at a time",
|
|
});
|
|
|
|
// 4. Clicking on human resource's avatar with one user associated
|
|
await click(queryAll(".o_gantt_row_title .o_avatar img")[1]);
|
|
await animationFrame();
|
|
expect(".o_card_user_infos span:first").toHaveText("Pierre");
|
|
expect(".o_avatar_card").toHaveCount(1, {
|
|
message: "Only one popover resource card should be opened at a time",
|
|
});
|
|
});
|