Files
PacketStation/tests/e2e/tests/checklists.spec.ts
T

88 lines
4.6 KiB
TypeScript

import { expect, test } from "./helpers";
import { actor, api, closeAll } from "./shophelpers";
import { call } from "./adminhelpers";
import type { Json } from "./whhelpers";
// Change C8 on the CI stack: checklists per department. multi.mia (Clerical and 06 Code Bldg 2 supervisor) opens
// Checklists from the top bar, sees only her own department, adds an item and saves. sup.wes (03 supervisor) can
// read 06 but not change it, and Q.C. and a lead cannot change any. At the end mia sets 06 back to the default list
// so the other scenarios keep the lists they expect.
const RUN = Date.now().toString(36).toLowerCase().slice(-5);
const KEY = `e2e_${RUN}`;
const TEXT = `Nameplate checked ${RUN}`;
async function resetTo06Default(a: Parameters<typeof api>[0]): Promise<void> {
const cur = await api(a, "get", "/api/checklists/06");
if (cur.custom) await api(a, "put", "/api/checklists/06", { items: null, base: cur.version });
}
test.describe.serial("department checklists", () => {
test.setTimeout(120_000);
test("C8: a supervisor edits their own department's checklist; others cannot", async ({ browser }) => {
const mia = await actor(browser, "multi.mia");
await resetTo06Default(mia);
const list = (await api(mia, "get", "/api/checklists")) as unknown as Json[];
const editable = list.filter((d) => d.editable).map((d) => String(d.dept_code));
expect(editable).toEqual(["06"]);
// the top-bar link; one department, so no picker
const page = mia.page;
await page.goto("/clerical");
await page.getByRole("banner").getByRole("link", { name: "Checklists", exact: true }).click();
await expect(page).toHaveURL(/\/checklists$/);
await expect(page.getByRole("heading", { level: 1, name: "Checklists" })).toBeVisible();
await expect(page.getByLabel("Department", { exact: true })).toHaveCount(0);
const editor = page.locator("section").filter({ has: page.getByRole("heading", { name: /^06 / }) });
await expect(editor).toBeVisible();
await expect(editor).toContainText(/Uses the default/);
const keys = editor.getByLabel(/^Item \d+ key$/);
const n = await keys.count();
expect(n).toBeGreaterThan(0);
// add an item at the end and save
await editor.getByRole("button", { name: "Add item", exact: true }).click();
await expect(keys).toHaveCount(n + 1);
await editor.getByLabel(`Item ${n + 1} group`, { exact: true }).fill("Final");
await editor.getByLabel(`Item ${n + 1} key`, { exact: true }).fill(KEY);
await editor.getByLabel(`Item ${n + 1} text`, { exact: true }).fill(TEXT);
await editor.getByRole("button", { name: "Save checklist", exact: true }).click();
await expect(editor.getByText(/^Checklist saved\./)).toBeVisible();
await expect(editor).toContainText("Own list");
const saved = await api(mia, "get", "/api/checklists/06");
expect(saved.custom).toBe(true);
expect(saved.editable).toBe(true);
expect((saved.items as Json[]).map((i) => i.key)).toContain(KEY);
expect((saved.items as Json[]).length).toBe(n + 1);
// sup.wes reads 06 but may not change it; his own list is 03
const wes = await actor(browser, "sup.wes");
const as03 = await api(wes, "get", "/api/checklists/06");
expect(as03.editable).toBe(false);
expect((as03.items as Json[]).map((i) => i.key)).toContain(KEY);
const refused = await call(wes, "put", "/api/checklists/06", { items: [], base: saved.version });
expect(refused.status).toBe(403);
await wes.page.goto("/checklists");
await expect(wes.page.locator("section").filter({ has: wes.page.getByRole("heading", { name: /^03 / }) })).toBeVisible();
await expect(wes.page.getByRole("heading", { name: /^06 / })).toHaveCount(0);
// Q.C. and a lead: no edit, no screen
const quinn = await actor(browser, "qc.quinn");
expect((await call(quinn, "put", "/api/checklists/03", { items: [], base: 0 })).status).toBe(403);
const lou = await actor(browser, "lead.lou");
expect((await api(lou, "get", "/api/checklists/03")).editable).toBe(false);
await lou.page.goto("/checklists");
await expect(lou.page.getByTestId("not-for-role")).toContainText("The Checklists screen is not for your role.");
// a stale save is refused with the current list
const stale = await call(mia, "put", "/api/checklists/06", { items: saved.items, base: Number(saved.version) - 1 });
expect(stale.status).toBe(409);
// back to the default so the other scenarios keep their lists
await resetTo06Default(mia);
expect((await api(mia, "get", "/api/checklists/06")).custom).toBe(false);
await closeAll(mia, wes, quinn, lou);
});
});