Files
PacketStation/tests/e2e/tests/admin-departments.spec.ts
T

154 lines
7.3 KiB
TypeScript

import { expect, test } from "./helpers";
import { api, closeAll } from "./shophelpers";
import type { Json } from "./whhelpers";
import { admin, call, openAdminTab, runId } from "./adminhelpers";
// Phase 9 Admin, Departments tab, on the CI stack. admin.ann adds a shop department with a code and short name
// made for this run and sees the three AD group names IT must create. Then she renames it and a station in the
// edit form; the code and short name have no field there, and the API refuses them in a change (422). A repeated
// code is refused (409). Last, the department is set inactive through the API so it stays out of the other
// scenarios. Existing departments are never changed: other specs read their names and stations.
const RUN = runId();
const CODE = `Z${RUN.slice(-3)}`;
const SLUG = `Ci${RUN}`;
const NAME = `CI Paint ${RUN}`;
const NAME2 = `CI Paint renamed ${RUN}`;
const GROUPS = ["Worker", "Lead", "Supervisor"].map((l) => `PS-${CODE}-${SLUG}-${l}`);
test.describe.serial("admin departments", () => {
test.setTimeout(120_000);
test("the list shows the seeded departments with their groups", async ({ browser }) => {
const ann = await admin(browser);
const page = ann.page;
await openAdminTab(page, "departments");
const table = page.getByRole("table", { name: "Departments" });
await expect(table).toBeVisible();
const weld = table.getByRole("row").filter({ hasText: "Weld Parts" });
await expect(weld).toBeVisible();
await expect(weld).toContainText("03");
await expect(weld).toContainText("PS-03-WeldParts-Worker");
await expect(weld).toContainText("Stall 1");
const list = (await api(ann, "get", "/api/admin/departments")) as unknown as Json[];
const d03 = list.find((d) => d.code === "03");
expect(d03).toBeTruthy();
expect(d03?.slug).toBe("WeldParts");
expect((d03?.groups as Json[]).map((g) => g.name)).toEqual(
expect.arrayContaining(["PS-03-WeldParts-Worker", "PS-03-WeldParts-Lead", "PS-03-WeldParts-Supervisor"]),
);
await closeAll(ann);
});
test("add a department: the three group names IT must create", async ({ browser }) => {
const ann = await admin(browser);
const page = ann.page;
await openAdminTab(page, "departments");
await page.getByRole("button", { name: "New department", exact: true }).click();
const form = page.locator("form").filter({ has: page.getByRole("heading", { name: "Add department" }) });
await expect(form).toBeVisible();
await form.getByLabel("Code", { exact: true }).fill(CODE);
await form.getByLabel("Short name", { exact: true }).fill(SLUG);
await form.getByLabel("Name", { exact: true }).fill(NAME);
await form.getByLabel("Kind", { exact: true }).selectOption("shop");
await form.getByLabel("Stations, one per line").fill("Bay 1\nBay 2");
// the form previews the group names before saving
const preview = form.getByText(/IT will need to create these groups/);
for (const g of GROUPS) await expect(preview).toContainText(g);
const posted = page.waitForResponse(
(r) => r.url().endsWith("/api/admin/departments") && r.request().method() === "POST",
);
await form.getByRole("button", { name: "Add department", exact: true }).click();
const resp = await posted;
expect(resp.status(), await resp.text()).toBe(201);
const out = (await resp.json()) as Json;
expect([...(out.groups_to_create as string[])].sort()).toEqual([...GROUPS].sort());
expect(out.department.code).toBe(CODE);
expect(out.department.slug).toBe(SLUG);
const note = page.getByRole("status", { name: "Groups to create" });
await expect(note).toBeVisible();
for (const g of GROUPS) await expect(note).toContainText(g);
const row = page.getByRole("table", { name: "Departments" }).getByRole("row").filter({ hasText: NAME });
await expect(row).toBeVisible();
await expect(row).toContainText(CODE);
for (const g of GROUPS) await expect(row).toContainText(g);
await expect(row).toContainText("Bay 1, Bay 2");
// the same code again is refused
const again = await call(ann, "post", "/api/admin/departments", {
code: CODE,
slug: `${SLUG}x`,
name: `${NAME} again`,
kind: "shop",
weld: false,
supervisor_group: true,
stations: [],
});
expect(again.status, JSON.stringify(again.body)).toBe(409);
await closeAll(ann);
});
test("edit its name and a station; code and short name are not editable", async ({ browser }) => {
const ann = await admin(browser);
const page = ann.page;
await openAdminTab(page, "departments");
await page.getByRole("button", { name: `Edit department ${CODE}`, exact: true }).click();
const editor = page.locator("form").filter({ has: page.getByRole("heading", { name: `Edit ${CODE} ${NAME}` }) });
await expect(editor).toBeVisible();
// no field for the code or the short name
await expect(editor.getByLabel("Code", { exact: true })).toHaveCount(0);
await expect(editor.getByLabel("Short name", { exact: true })).toHaveCount(0);
await editor.getByLabel("Department name", { exact: true }).fill(NAME2);
await editor.getByLabel("Station 1 name", { exact: true }).fill("Bay 1A");
const patched = page.waitForResponse(
(r) => r.url().endsWith(`/api/admin/departments/${CODE}`) && r.request().method() === "PATCH",
);
await editor.getByRole("button", { name: "Save department", exact: true }).click();
const resp = await patched;
expect(resp.status(), await resp.text()).toBe(200);
await expect(page.getByRole("status").filter({ hasText: "Department saved." })).toBeVisible();
const row = page.getByRole("table", { name: "Departments" }).getByRole("row").filter({ hasText: NAME2 });
await expect(row).toBeVisible();
await expect(row).toContainText("Bay 1A, Bay 2");
const list = (await api(ann, "get", "/api/admin/departments")) as unknown as Json[];
const d = list.find((x) => x.code === CODE);
expect(d?.name).toBe(NAME2);
expect(d?.slug).toBe(SLUG);
expect((d?.stations as Json[]).map((s) => s.name)).toEqual(expect.arrayContaining(["Bay 1A", "Bay 2"]));
expect((d?.stations as Json[]).map((s) => s.name)).not.toContain("Bay 1");
// the API refuses a code or a short name in a change
for (const body of [{ code: "ZZZZ" }, { slug: "Other" }]) {
const r = await call(ann, "patch", `/api/admin/departments/${CODE}`, body);
expect(r.status, `${JSON.stringify(body)}: ${JSON.stringify(r.body)}`).toBe(422);
}
// two stations with one name are refused
const ids = (d?.stations as Json[]).map((s) => Number(s.id));
const dup = await call(ann, "patch", `/api/admin/departments/${CODE}`, {
stations: [
{ id: ids[0], name: "Same", sort: 1, active: true },
{ id: ids[1], name: "Same", sort: 2, active: true },
],
});
expect(dup.status, JSON.stringify(dup.body)).toBe(422);
await closeAll(ann);
});
test("cleanup: the CI department is set inactive", async ({ browser }) => {
const ann = await admin(browser);
const out = await api(ann, "patch", `/api/admin/departments/${CODE}`, { active: false });
expect(out.active).toBe(false);
await openAdminTab(ann.page, "departments");
const row = ann.page.getByRole("table", { name: "Departments" }).getByRole("row").filter({ hasText: NAME2 });
await expect(row).toContainText("Inactive");
await closeAll(ann);
});
});