Files
pleno-vue/tests/e2e/superuser-department-employees.spec.ts
T

227 lines
7.8 KiB
TypeScript

import { expect, test, type Page } from "@playwright/test";
import { API_HOST, apiPathPattern, mockApi, seedAuthenticatedState } from "./support/network.js";
import { isDesktopProject } from "./support/projects";
const json = (body: unknown, status = 200) => ({
status,
contentType: "application/json",
body: JSON.stringify(body),
});
const departments = [
{ id: 1, name: "Assigned Depot", description: "", visible: true, archived: false, custom_pricing_only: true },
{ id: 2, name: "Remote Depot", description: "", visible: true, archived: false, custom_pricing_only: false },
];
const role = {
key: "department_admin",
label: "Department admin",
description: "Can manage department prices, customer pricing, and employee access.",
permission_groups: [
{
key: "limited_backoffice",
capabilities: ["open_limited_backoffice", "manage_employee_access"],
},
],
};
const roles = [
{
key: "viewer",
label: "Deactivated",
description: "Keeps the employee registered without order, booking, or management permissions.",
permission_groups: [{ key: "account", capabilities: ["sign_in", "view_own_permissions"] }],
},
role,
];
const employees = [
{
id: 501,
user_id: 501,
customer_number: 0,
display_name: "Casey Clerk",
email: "casey@example.com",
phone_country_code: 45,
phone: 12345678,
active: true,
role,
departments,
created_at: "2026-01-01 00:00:00",
updated_at: "2026-01-01 00:00:00",
},
{
id: 502,
user_id: 502,
customer_number: 0,
display_name: "Riley Remote",
email: "riley@example.com",
phone_country_code: null,
phone: null,
active: true,
role: roles[0],
departments: [departments[1]],
created_at: "2026-01-01 00:00:00",
updated_at: "2026-01-01 00:00:00",
},
];
async function seedSuperuser(page: Page) {
await page.addInitScript(() => {
window.localStorage.setItem("locale", "en");
});
await seedAuthenticatedState(page, "superuser-department-employees-token");
await mockApi(page, {
authenticated: true,
permissions: [
"superuser",
"user",
"limited_backoffice_access",
"limited_backoffice_employees_manage",
"superuser_fetch_department",
],
});
}
async function installRoutes(page: Page) {
const calls: string[] = [];
const createCalls: unknown[] = [];
const updateCalls: unknown[] = [];
const currentEmployees = { value: structuredClone(employees) };
await page.route(apiPathPattern("/superuser/department"), async (route) => {
const departmentId = Number(new URL(route.request().url()).searchParams.get("department_id"));
const department = departments.find((item) => item.id === departmentId) || departments[0];
await route.fulfill(
json({
data: {
...department,
branding: null,
created_at: "2026-01-01 00:00:00",
updated_at: "2026-07-06 09:30:00",
},
})
);
});
await page.route(API_HOST, async (route) => {
const request = route.request();
const url = new URL(request.url());
const pathname = url.pathname;
const method = request.method().toUpperCase();
calls.push(`${method} ${pathname}`);
if (pathname.endsWith("/limited-backoffice/departments") && method === "GET") {
await route.fulfill(json({ data: departments }));
return;
}
if (pathname.endsWith("/limited-backoffice/roles") && method === "GET") {
await route.fulfill(json({ data: roles }));
return;
}
if (pathname.endsWith("/limited-backoffice/employees") && method === "GET") {
await route.fulfill(json({ data: currentEmployees.value }));
return;
}
if (pathname.endsWith("/limited-backoffice/employees") && method === "POST") {
const body = request.postDataJSON?.() || {};
createCalls.push(body);
currentEmployees.value.unshift({
id: 900,
user_id: 900,
customer_number: 0,
display_name: body.display_name,
email: body.email,
phone_country_code: body.phone_country_code,
phone: body.phone,
active: true,
role,
departments: departments.filter((department) => body.department_ids?.includes(department.id)),
created_at: "2026-07-08 00:00:00",
updated_at: "2026-07-08 00:00:00",
});
await route.fulfill(json({ data: currentEmployees.value[0] }));
return;
}
const employeeMatch = pathname.match(/\/limited-backoffice\/employees\/(\d+)$/);
if (employeeMatch && method === "PUT") {
const body = request.postDataJSON?.() || {};
updateCalls.push(body);
await route.fulfill(json({ data: { ...currentEmployees.value[0], ...body } }));
return;
}
await route.fallback();
});
return { calls, createCalls, updateCalls };
}
test.describe("Superuser department employees", () => {
test("renders department-scoped employees and keeps multi-department access editable", async ({ page }, testInfo) => {
test.skip(!isDesktopProject(testInfo), "Desktop only");
await seedSuperuser(page);
const api = await installRoutes(page);
await page.goto("/superuser/departments/1/employees", { waitUntil: "domcontentloaded" });
await expect(page.getByRole("heading", { name: "Assigned Depot" })).toBeVisible();
await expect(page.getByTestId("limited-backoffice")).toHaveCount(0);
await expect(page.getByRole("heading", { name: "Employees" })).toBeVisible();
await expect(page.getByTestId("limited-employee-row-501")).toContainText("Casey Clerk");
await expect(page.getByTestId("limited-employee-row-502")).toHaveCount(0);
await expect(page.getByTestId("limited-employee-department-1")).toBeChecked();
await expect(page.getByTestId("limited-employee-department-2")).not.toBeChecked();
await page.getByTestId("limited-employee-department-2").check();
await page.getByTestId("limited-employee-name").fill("Morgan Manager");
await page.getByTestId("limited-employee-email").fill("morgan@example.com");
await page.getByTestId("limited-employee-password").fill("Secret123!");
await page.getByTestId("limited-employee-role").selectOption("department_admin");
await page.getByTestId("limited-employee-save").click();
expect(api.createCalls[0]).toMatchObject({
display_name: "Morgan Manager",
email: "morgan@example.com",
role_key: "department_admin",
department_ids: [1, 2],
});
await page.getByTestId("limited-employee-edit-501").click();
await expect(page.getByTestId("limited-employee-department-1")).toBeChecked();
await expect(page.getByTestId("limited-employee-department-2")).toBeChecked();
await page.getByTestId("limited-employee-name").fill("Casey Lead");
await page.getByTestId("limited-employee-save").click();
expect(api.updateCalls[0]).toMatchObject({
display_name: "Casey Lead",
department_ids: [1, 2],
});
await page.getByTestId("limited-employee-role-help").click();
await expect(page.getByTestId("limited-role-permissions-modal")).toBeVisible();
await expect(page.locator("body")).not.toContainText("department_access_1");
await expect(page.locator("body")).not.toContainText("limited_backoffice_employees_manage");
await expect(page.locator("body")).not.toContainText("raw_permissions");
});
test("does not fetch employees for unknown department tabs", async ({ page }, testInfo) => {
test.skip(!isDesktopProject(testInfo), "Desktop only");
await seedSuperuser(page);
const api = await installRoutes(page);
await page.goto("/superuser/departments/3/employees", { waitUntil: "domcontentloaded" });
await expect(page.getByTestId("limited-employees-forbidden")).toBeVisible();
await expect(page.getByTestId("limited-employees-table")).toHaveCount(0);
expect(api.calls.some((call) => call.includes("/limited-backoffice/employees"))).toBe(false);
});
});