- Replaced repetitive department module URL logic with `buildDepartmentModulePath` utility in `DepartmentModulesDisplay.vue`. - Enhanced layouts and responsive behavior across components, including `PosDepartmentStep1MobileTransactionHistory.vue` and `DepartmentDailyReport.vue`. - Removed unused `SuperuserInvoicingLocalStore.vue` and refactored to `SuperuserInvoicingLocalStore.ts`. - Updated media query handling and card layout adjustments in `DepartmentDailyReport.vue`. - Added new Playwright configurations (`playwright.prod.config.ts` and `playwright.live.config.ts`) for e2e release workflows. - Extended e2e and unit test coverage for mobile POS and department modules.
137 lines
5.2 KiB
TypeScript
137 lines
5.2 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import { mockApi, seedAuthenticatedState } from "./support/network.js";
|
|
|
|
const adminPermissions = [
|
|
"admin",
|
|
"list_department_daily_reports",
|
|
"department_access_1",
|
|
"department_access_2",
|
|
"department_access_3",
|
|
"department_access_4",
|
|
];
|
|
|
|
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: "Kundeklager er ikke tilgængelig endnu." },
|
|
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 } = {}) {
|
|
await seedAuthenticatedState(page);
|
|
await mockApi(page, {
|
|
authenticated: true,
|
|
permissions: adminPermissions,
|
|
});
|
|
|
|
await page.route(/\/departments(\?.*)?$/i, async (route) => {
|
|
if (options.departmentDelayMs) {
|
|
await new Promise((resolve) => setTimeout(resolve, options.departmentDelayMs));
|
|
}
|
|
|
|
await route.fulfill(json({
|
|
data: [
|
|
{ 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 },
|
|
],
|
|
}));
|
|
});
|
|
|
|
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 (!testInfo.project.use.isMobile) {
|
|
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 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 (!test.info().project.name.includes("mobile")) {
|
|
await expect(page.locator("option", { hasText: "Visible North" })).toHaveCount(1);
|
|
await expect(page.locator("option", { hasText: "Legacy East" })).toHaveCount(1);
|
|
await expect(page.locator("option", { hasText: "Hidden South" })).toHaveCount(0);
|
|
await expect(page.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();
|
|
});
|
|
});
|