Files
pleno-vue/tests/e2e/superuser-roles-permissions.spec.ts
T
2026-07-06 12:43:03 +02:00

208 lines
6.9 KiB
TypeScript

import { expect, test, type Page, type Route } from "@playwright/test";
import { apiPathPattern, mockApi, seedAuthenticatedState } from "./support/network.js";
// This route is sensitive to stale cached Vue modules when the PWA service worker is active in mobile runs.
test.use({ serviceWorkers: "block" });
const json = (body: unknown, status = 200) => ({
status,
contentType: "application/json",
body: JSON.stringify(body),
});
const permissionCatalog = {
"/orders": {
GET: {
list_orders: "List orders",
},
POST: {
add_order: "Create orders",
},
},
"/admin/bookings": {
POST: {
create_bookings: "Create bookings",
},
},
"/superuser/system/replication": {
GET: {
superuser_replication_view: "View replication status",
},
},
};
const departments = [
{
id: 1,
name: "Copenhagen",
},
{
id: 2,
name: "Odense",
},
];
type PermissionCall = {
action: "add" | "remove";
permission: string;
};
const openGroupTab = async (page: Page, label: RegExp) => {
await page.locator(".tabs").getByText(label).click();
};
const clickPermissionSwitch = async (page: Page, permission: string) => {
await page.locator(`label[for="role-permission-${permission}"]`).click();
};
const installRolePermissionRoutes = async (
page: Page,
options: {
failAction?: "add" | "remove";
failPermission?: string;
} = {}
) => {
let rolePermissions = ["user", "superuser", "department_access_1", "list_orders"];
const calls: PermissionCall[] = [];
const rolePayload = () => ({
id: 2,
name: "Operations manager",
description: "Can manage operations.",
created_at: "2026-07-06T08:00:00.000Z",
permissions: [...rolePermissions],
});
await page.route(apiPathPattern("/permissions"), async (route: Route) => {
await route.fulfill(json({ data: permissionCatalog }));
});
await page.route(apiPathPattern("/departments"), async (route: Route) => {
await route.fulfill(json({ data: departments }));
});
await page.route(apiPathPattern("/roles"), async (route: Route) => {
await route.fulfill(json({ data: rolePayload() }));
});
await page.route(apiPathPattern("/roles/permissions"), async (route: Route) => {
const request = route.request();
const method = request.method();
const url = new URL(request.url());
const body = method === "POST" ? request.postDataJSON() : {};
const permission =
method === "POST" ? String(body.permission_id || "") : String(url.searchParams.get("permission_id") || "");
const action = method === "POST" ? "add" : "remove";
calls.push({ action, permission });
if (options.failAction === action && options.failPermission === permission) {
await route.fulfill(json({ data: { message: "Mutation failed" } }, 500));
return;
}
if (action === "add" && !rolePermissions.includes(permission)) {
rolePermissions = [...rolePermissions, permission];
}
if (action === "remove") {
rolePermissions = rolePermissions.filter((value) => value !== permission);
}
await route.fulfill(json({ data: rolePayload() }));
});
return {
calls,
getRolePermissions: () => [...rolePermissions],
};
};
const bootRolePermissionsPage = async (page: Page, routeOptions = {}) => {
await page.addInitScript(() => {
window.localStorage.setItem("locale", "en");
});
await seedAuthenticatedState(page, "superuser-role-permissions-token");
await mockApi(page, {
authenticated: true,
permissions: [
"superuser",
"user",
"permissions_list",
"list_roles",
"add_role_permission",
"delete_role_permission",
],
sessionData: {
group_id: 1,
},
});
const harness = await installRolePermissionRoutes(page, routeOptions);
await page.goto("/superuser/roles/2", { waitUntil: "domcontentloaded" });
await expect(page.getByTestId("role-permissions-page")).toBeVisible();
await expect(page.getByTestId("role-permissions-loading")).toHaveCount(0);
return harness;
};
test.describe("Superuser role permissions", () => {
test("@smoke @pr loads grouped permissions, searches, and toggles without a blank page", async ({ page }) => {
const { calls } = await bootRolePermissionsPage(page);
await expect(page.getByText("Operations manager permissions")).toBeVisible();
await expect(page.getByTestId("role-permissions-selected-count")).toContainText("4 of 9 selected");
await expect(page.getByRole("heading", { name: "Access" })).toBeVisible();
await openGroupTab(page, /Orders and POS/);
await expect(page.getByTestId("role-permission-row-list_orders")).toContainText("List orders");
await clickPermissionSwitch(page, "list_orders");
await expect.poll(() => calls).toContainEqual({ action: "remove", permission: "list_orders" });
await expect(page.getByTestId("role-permissions-page")).toBeVisible();
await expect(page.locator("body")).not.toContainText(/white screen|TypeError|Unhandled/i);
await page.getByTestId("role-permissions-search").fill("booking");
await openGroupTab(page, /Bookings/);
await expect(page.getByTestId("role-permission-row-create_bookings")).toContainText("Create bookings");
await openGroupTab(page, /Orders and POS/);
await expect(page.getByTestId("role-permissions-empty-orders_pos")).toBeVisible();
});
test("selects and clears all permissions in a group without no-op requests", async ({ page }) => {
const { calls, getRolePermissions } = await bootRolePermissionsPage(page);
await openGroupTab(page, /Orders and POS/);
await page.getByTestId("role-permissions-clear-all-orders_pos").click();
await expect.poll(() => calls).toEqual([{ action: "remove", permission: "list_orders" }]);
expect(getRolePermissions()).not.toContain("list_orders");
expect(getRolePermissions()).not.toContain("add_order");
await page.getByTestId("role-permissions-select-all-orders_pos").click();
await expect
.poll(() => calls)
.toEqual([
{ action: "remove", permission: "list_orders" },
{ action: "add", permission: "add_order" },
{ action: "add", permission: "list_orders" },
]);
expect(getRolePermissions()).toEqual(expect.arrayContaining(["list_orders", "add_order"]));
});
test("keeps the page rendered and reloads role permissions when a mutation fails", async ({ page }) => {
const { calls, getRolePermissions } = await bootRolePermissionsPage(page, {
failAction: "add",
failPermission: "add_order",
});
await openGroupTab(page, /Orders and POS/);
await clickPermissionSwitch(page, "add_order");
await expect.poll(() => calls).toContainEqual({ action: "add", permission: "add_order" });
await expect(page.getByTestId("role-permission-error")).toBeVisible();
await expect(page.getByTestId("role-permissions-page")).toBeVisible();
await expect(page.getByTestId("role-permission-toggle-add_order")).not.toBeChecked();
expect(getRolePermissions()).not.toContain("add_order");
});
});