157 lines
8.6 KiB
TypeScript
157 lines
8.6 KiB
TypeScript
import { expect, test } from "./helpers";
|
|
import { makeDraft, runSuffix } from "./pmhelpers";
|
|
import { actor, api, closeAll, packet, type Actor } from "./shophelpers";
|
|
import { getJson, type Json } from "./whhelpers";
|
|
|
|
// Phase 10, the old tunits on the new UI. clerk.clara makes a project with three units at once (the Add units sheet's
|
|
// "Several units"), a duplicate unit number is refused, a packet moves to another unit through the two-step picker,
|
|
// and a closed unit takes no new packet. clerk.leo (Clerical supervisor) renumbers a unit; the packet follows, the
|
|
// old number stays an alias and cannot be taken again. clara has no Renumber, and the warehouse cannot move a packet.
|
|
|
|
let RUN = "";
|
|
let PROJECT = "";
|
|
let projectId = 0;
|
|
const units: Record<string, Json> = {};
|
|
let packetId = 0;
|
|
|
|
async function unitsOf(a: Actor): Promise<Json[]> {
|
|
const p = await getJson(a.page.request, `/api/projects/${projectId}`);
|
|
return (p.units ?? []) as Json[];
|
|
}
|
|
|
|
test.describe.serial("projects and units", () => {
|
|
test("tunits: a new project with three units at once; a duplicate unit is refused", async ({ browser }, info) => {
|
|
RUN = runSuffix(info.project.name);
|
|
PROJECT = `U${RUN}`;
|
|
const clara = await actor(browser, "clerk.clara");
|
|
const page = clara.page;
|
|
await page.goto("/clerical");
|
|
await page.getByRole("button", { name: "New project" }).click();
|
|
const proj = page.getByRole("dialog", { name: "New project" });
|
|
// typed in lower case: the number is kept in capitals
|
|
await proj.getByLabel("Project number").fill(PROJECT.toLowerCase());
|
|
await proj.getByLabel("Project name").fill("CI units");
|
|
await proj.getByLabel("Customer", { exact: true }).fill("CI Customer");
|
|
await proj.getByRole("button", { name: "Create project" }).click();
|
|
|
|
const add = page.getByRole("dialog", { name: "Add units" });
|
|
await expect(add).toBeVisible();
|
|
await add.getByRole("group", { name: "One or several" }).getByRole("button", { name: "Several units" }).click();
|
|
await add.getByLabel("How many").fill("3");
|
|
await add.getByLabel("Starting lot").fill("001");
|
|
await expect(add.getByText(`Numbers: ${PROJECT}001, ${PROJECT}002, ${PROJECT}003`)).toBeVisible();
|
|
await add.getByLabel("Description (all of them)").fill("CI separator");
|
|
await add.getByRole("button", { name: "Add", exact: true }).click();
|
|
await expect(page).toHaveURL(/\/clerical\/projects\/\d+$/);
|
|
projectId = Number(new URL(page.url()).pathname.split("/").pop());
|
|
await expect(page.getByRole("heading", { level: 1, name: `${PROJECT} · CI units` })).toBeVisible();
|
|
for (const lot of ["001", "002", "003"]) {
|
|
await expect(page.getByRole("row", { name: new RegExp(`${PROJECT}${lot}`) })).toBeVisible();
|
|
}
|
|
for (const u of await unitsOf(clara)) units[String(u.lot)] = u;
|
|
expect(Object.keys(units).sort()).toEqual(["001", "002", "003"]);
|
|
|
|
// The same unit number again is refused with the reason
|
|
await page.getByRole("button", { name: "Add units" }).click();
|
|
await expect(add).toBeVisible();
|
|
await add.getByRole("group", { name: "One or several" }).getByRole("button", { name: "One unit" }).click();
|
|
await add.getByLabel("Lot", { exact: true }).fill("002");
|
|
await add.getByRole("button", { name: "Add", exact: true }).click();
|
|
await expect(add.getByRole("alert")).toHaveText(`${PROJECT}002 already exists as a unit.`);
|
|
await add.getByRole("button", { name: "Cancel" }).click();
|
|
expect((await unitsOf(clara)).length).toBe(3);
|
|
await closeAll(clara);
|
|
});
|
|
|
|
test("tunits: a packet moves to another unit through the two-step picker; the warehouse cannot move one", async ({
|
|
browser,
|
|
}) => {
|
|
const clara = await actor(browser, "clerk.clara");
|
|
const u1 = units["001"] as Json;
|
|
const made = await makeDraft(clara, { id: Number(u1.id), number: String(u1.number), lot: "001" }, `Move spool ${RUN}`);
|
|
packetId = made.id;
|
|
const page = clara.page;
|
|
await page.goto(`/packets/${packetId}`);
|
|
await page.getByRole("button", { name: "Move", exact: true }).click();
|
|
const sheet = page.getByRole("dialog", { name: "Move to another unit" });
|
|
await expect(sheet).toBeVisible();
|
|
// The project is picked already (the packet's own); step two is the unit
|
|
await expect(sheet.getByText(PROJECT, { exact: true }).first()).toBeVisible();
|
|
// Moving to its own unit is refused in the sheet
|
|
await sheet.getByLabel("Unit", { exact: true }).selectOption({ label: `${PROJECT}001 · CI separator` });
|
|
await sheet.getByRole("button", { name: "Move packet" }).click();
|
|
await expect(sheet.getByRole("alert")).toHaveText("The packet is in that unit already.");
|
|
await sheet.getByLabel("Unit", { exact: true }).selectOption({ label: `${PROJECT}002 · CI separator` });
|
|
await sheet.getByLabel("Reason (optional)").fill("Built on the second unit");
|
|
await sheet.getByRole("button", { name: "Move packet" }).click();
|
|
await expect(page.getByText("Packet moved.")).toBeVisible();
|
|
await expect.poll(async () => String((await packet(clara, packetId)).unit.number)).toBe(`${PROJECT}002`);
|
|
await closeAll(clara);
|
|
|
|
// The warehouse may not move a packet (server check)
|
|
const wade = await actor(browser, "wh.wade");
|
|
const u3 = units["003"] as Json;
|
|
await api(wade, "post", `/api/packets/${packetId}/move`, { unit_id: u3.id }, { status: 403 });
|
|
expect(String((await packet(wade, packetId)).unit.number)).toBe(`${PROJECT}002`);
|
|
await closeAll(wade);
|
|
});
|
|
|
|
test("tunits: a Clerical supervisor renumbers a unit; its packet follows and the old number is an alias", async ({
|
|
browser,
|
|
}) => {
|
|
const clara = await actor(browser, "clerk.clara");
|
|
const u2 = units["002"] as Json;
|
|
await clara.page.goto(`/clerical/units/${u2.id}`);
|
|
await expect(clara.page.getByRole("heading", { level: 1, name: new RegExp(`^${PROJECT}002`) })).toBeVisible();
|
|
await expect(clara.page.getByRole("button", { name: "Renumber" })).toHaveCount(0);
|
|
await closeAll(clara);
|
|
|
|
const leo = await actor(browser, "clerk.leo");
|
|
const page = leo.page;
|
|
await page.goto(`/clerical/units/${u2.id}`);
|
|
await page.getByRole("button", { name: "Renumber" }).click();
|
|
const sheet = page.getByRole("dialog", { name: "Renumber unit" });
|
|
await expect(sheet).toBeVisible();
|
|
await sheet.getByLabel("New lot").fill("010");
|
|
await sheet.getByRole("button", { name: "Change number" }).click();
|
|
await expect(sheet.getByRole("alert")).toHaveText("Give a reason.");
|
|
await sheet.getByLabel("Reason").fill("Customer tag numbers changed");
|
|
await sheet.getByRole("button", { name: "Change number" }).click();
|
|
await expect(page.getByText(`Unit renumbered to ${PROJECT}010`)).toBeVisible();
|
|
await expect(page.getByRole("heading", { level: 1, name: new RegExp(`^${PROJECT}010`) })).toBeVisible();
|
|
// The packet follows its unit
|
|
expect(String((await packet(leo, packetId)).unit.number)).toBe(`${PROJECT}010`);
|
|
// The old number still finds the unit, as an alias, and cannot be used again
|
|
const found = await getJson(page.request, `/api/lookup/number?n=${PROJECT}002`);
|
|
expect(found.kind).toBe("unit");
|
|
expect(Number(found.id)).toBe(Number(u2.id));
|
|
expect(found.alias).toBeTruthy();
|
|
const again = await api(leo, "post", `/api/projects/${projectId}/units`, { lot: "002" }, { status: 409 });
|
|
expect(String(again.detail ?? again.message ?? JSON.stringify(again))).toContain(`old number of ${PROJECT}010`);
|
|
await closeAll(leo);
|
|
});
|
|
|
|
test("tunits: a closed unit takes no new packet", async ({ browser }) => {
|
|
const clara = await actor(browser, "clerk.clara");
|
|
const page = clara.page;
|
|
const u3 = units["003"] as Json;
|
|
await page.goto(`/clerical/units/${u3.id}`);
|
|
await expect(page.getByRole("button", { name: "Add packet" })).toBeVisible();
|
|
await page.getByRole("button", { name: "Edit unit" }).click();
|
|
const sheet = page.getByRole("dialog", { name: "Edit unit" });
|
|
await sheet.getByLabel("Status").selectOption({ label: "Closed" });
|
|
await sheet.getByRole("button", { name: "Save changes" }).click();
|
|
await expect(page.getByText("Unit saved")).toBeVisible();
|
|
await expect(page.getByText(/· Closed$/).first()).toBeVisible();
|
|
await expect(page.getByRole("button", { name: "Add packet" })).toHaveCount(0);
|
|
// The server refuses a packet on it too
|
|
const r = await page.request.post("/api/packets", {
|
|
headers: { Origin: new URL(page.url()).origin, "X-Requested-With": "PacketStation" },
|
|
data: { unit_id: u3.id, dept_code: "03", op: "WELD-PART", title: `Closed ${RUN}` },
|
|
});
|
|
expect(r.status(), await r.text()).toBeGreaterThanOrEqual(400);
|
|
expect(r.status()).toBeLessThan(500);
|
|
await closeAll(clara);
|
|
});
|
|
});
|