Files
pleno-vue/tests/e2e/admin-department-visibility.spec.ts
T

227 lines
8.6 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { mockApi, seedAuthenticatedState } from "./support/network.js";
import { isCompactProject, isDesktopProject } from "./support/projects";
const adminPermissions = [
"admin",
"list_department_daily_reports",
"department_access_1",
"department_access_2",
"department_access_3",
"department_access_4",
];
const defaultDepartments = [
{ id: 1, name: "Visible North", visible: true },
{ id: 2, name: "Hidden South", visible: false },
{ id: 3, name: "Legacy East" },
{ id: 4, name: "Numeric Hidden", visible: 0 },
];
const json = (body: unknown, status = 200) => ({
status,
contentType: "application/json",
body: JSON.stringify(body),
});
const buildOverviewPayload = () => ({
data: {
department_ids: [1],
date: "2026-04-08",
date_to: "2026-04-08",
metrics: {
bookings: { state: "ready", value: 4, out_of: 6, message: null },
complaints: {
state: "unavailable",
value: null,
out_of: null,
message: "Complaints data is not available yet.",
},
night_washes: { state: "ready", value: 1, out_of: null, message: null },
revenue: { state: "ready", value: 2400, out_of: null, message: null },
washes: { state: "ready", value: 8, out_of: null, message: null },
products_sold: { state: "ready", value: 19, out_of: null, message: null },
transactions: { state: "ready", value: 11, out_of: null, message: null },
water_usage: { state: "ready", value: 32, out_of: null, message: null },
overtime: { state: "ready", value: 1.5, out_of: null, message: null },
},
products: [],
},
});
async function mockAdminDepartmentDependencies(page, options: {
departmentDelayMs?: number;
departments?: Array<Record<string, unknown>>;
permissions?: string[];
sessionData?: Record<string, unknown>;
} = {}) {
await seedAuthenticatedState(page);
await mockApi(page, {
authenticated: true,
permissions: options.permissions || adminPermissions,
sessionData: options.sessionData,
});
await page.route(/\/departments(\?.*)?$/i, async (route) => {
if (options.departmentDelayMs) {
await new Promise((resolve) => setTimeout(resolve, options.departmentDelayMs));
}
await route.fulfill(
json({
data: options.departments || defaultDepartments,
})
);
});
await page.route(/\/departments\/weather(\?.*)?$/i, async (route) => {
await route.fulfill(json({ data: [] }));
});
await page.route(/\/departments\/daily-reports\/get(\?.*)?$/i, async (route) => {
await route.fulfill(
json({
data: {
id: 10,
department_id: 1,
water_usage: 32,
notes: "",
filled_by: 1,
created_at: "2026-04-08 00:00:00",
},
})
);
});
await page.route(/\/departments\/daily-reports(?:\/overview)?(\?.*)?$/i, async (route) => {
const url = new URL(route.request().url());
if (url.pathname.endsWith("/departments/daily-reports/overview")) {
await route.fulfill(json(buildOverviewPayload()));
return;
}
await route.fulfill(json({ data: [] }));
});
}
async function expandDepartmentFiltersOnMobile(page, testInfo) {
if (!isCompactProject(testInfo)) {
return;
}
if (await page.getByTestId("daily-report-department-controls").count()) {
return;
}
await page.getByTestId("daily-report-mobile-departments-toggle").click();
await expect(page.getByTestId("daily-report-department-controls")).toBeVisible();
}
test.describe("Admin department visibility", () => {
test("hides placeholder departments from desktop admin navigation pickers", async ({ page }, testInfo) => {
test.skip(!isDesktopProject(testInfo), "Desktop only");
await mockAdminDepartmentDependencies(page, {
permissions: [
...adminPermissions,
"department_access_5",
],
departments: [
{ id: 1, name: "Visible North", visible: true, priority_order: 20 },
{ id: 2, name: "Ingen data", visible: true, priority_order: 1 },
{ id: 3, name: " ", visible: true, priority_order: 2 },
{ id: 4, name: "Visible East", visible: true, priority_order: 10 },
],
});
await page.goto("/admin");
await expect(page.getByTestId("daily-report-page")).toBeVisible();
const desktopNavigation = page.getByTestId("desktop-buefy-navigation");
const desktopDepartmentSelect = page.getByTestId("desktop-header-department-select");
await expect(desktopNavigation).toContainText("Visible North");
await expect(desktopNavigation).toContainText("Visible East");
await expect(desktopNavigation).not.toContainText(/Ingen data/i);
const desktopNavigationText = await desktopNavigation.innerText();
expect(desktopNavigationText.indexOf("Visible East")).toBeLessThan(desktopNavigationText.indexOf("Visible North"));
await expect(desktopDepartmentSelect.locator("option")).toHaveCount(3);
await expect(desktopDepartmentSelect.locator("option", { hasText: "Visible North" })).toHaveCount(1);
await expect(desktopDepartmentSelect.locator("option", { hasText: "Visible East" })).toHaveCount(1);
await expect(desktopDepartmentSelect.locator("option", { hasText: "Ingen data" })).toHaveCount(0);
const desktopDepartmentOptionTexts = await desktopDepartmentSelect
.locator("option")
.evaluateAll((options) => options.map((option) => option.textContent?.trim() || ""));
expect(desktopDepartmentOptionTexts.slice(1)).toEqual(["Visible East", "Visible North"]);
});
test("hides invisible departments from both the header selector and the daily report department controls", async ({
page,
}, testInfo) => {
await mockAdminDepartmentDependencies(page);
await page.goto("/admin/1/modules/daily-report?departmentIds=1&dateFrom=2026-04-08&dateTo=2026-04-08");
await expect(page.getByTestId("daily-report-page")).toBeVisible();
await expandDepartmentFiltersOnMobile(page, testInfo);
const departmentControls = page.getByTestId("daily-report-department-controls");
await expect(departmentControls.getByRole("button", { name: "Visible North" })).toBeVisible();
await expect(departmentControls.getByRole("button", { name: "Legacy East" })).toBeVisible();
await expect(departmentControls.getByRole("button", { name: "Hidden South" })).toHaveCount(0);
await expect(departmentControls.getByRole("button", { name: "Numeric Hidden" })).toHaveCount(0);
if (isDesktopProject(test.info())) {
const desktopDepartmentSelect = page.getByTestId("desktop-header-department-select");
await expect(desktopDepartmentSelect.locator("option", { hasText: "Visible North" })).toHaveCount(1);
await expect(desktopDepartmentSelect.locator("option", { hasText: "Legacy East" })).toHaveCount(1);
await expect(desktopDepartmentSelect.locator("option", { hasText: "Hidden South" })).toHaveCount(0);
await expect(desktopDepartmentSelect.locator("option", { hasText: "Numeric Hidden" })).toHaveCount(0);
}
});
test("renders department controls after a delayed departments response", async ({ page }, testInfo) => {
await mockAdminDepartmentDependencies(page, { departmentDelayMs: 400 });
await page.goto("/admin/1/modules/daily-report?departmentIds=1&dateFrom=2026-04-08&dateTo=2026-04-08");
await expect(page.getByTestId("daily-report-page")).toBeVisible();
await expandDepartmentFiltersOnMobile(page, testInfo);
const departmentControls = page.getByTestId("daily-report-department-controls");
await expect(departmentControls.getByRole("button", { name: "Visible North" })).toBeVisible();
await expect(departmentControls.getByRole("button", { name: "Legacy East" })).toBeVisible();
});
test("shows the draft transactions navigation item in the desktop buefy menu when a draft customer is configured", async ({
page,
}, testInfo) => {
test.skip(!isDesktopProject(testInfo), "Desktop only");
await mockAdminDepartmentDependencies(page, {
permissions: [
...adminPermissions,
"add_order",
"list_orders",
],
sessionData: {
runtime_config: {
economic: {
transaction_draft_customer_number: 6001,
},
},
},
});
await page.goto("/admin/1/modules/daily-report");
const desktopNavigation = page.getByTestId("desktop-buefy-navigation");
await expect(desktopNavigation).toContainText("Kladder");
await desktopNavigation.getByText("Kladder", { exact: true }).click();
await expect(page).toHaveURL(/\/admin\/1\/modules\/pos\/drafts$/);
await expect(page.getByTestId("department-pos-drafts-page")).toBeVisible();
});
});