e2e/stock-receipt.spec.ts
Rama main · réplica de lectura del repositorio original.
import { expect, test } from "@playwright/test";
import { randomUUID } from "node:crypto";
for (const width of [390, 1440]) test(`received stock returns to its requirement for explicit count and match at ${width}px`, async ({ page }) => {
await page.setViewportSize({ width, height: 900 });
await page.goto("/"); await page.getByLabel("Workspace password").fill("demo-password-please-change");
await page.getByRole("button", { name: "Sign in", exact: true }).click();
await expect(page.getByRole("heading", { name: "Projects", exact: true })).toBeVisible();
const id = `receipt-${randomUUID()}`, revision = `${id}-r1`;
const csrf = (await page.context().cookies()).find(cookie => cookie.name === "forge_csrf")!.value;
const post = async (path: string, data: object) => {
const response = await page.request.post(`/api/v1${path}`, { headers: { "x-csrf-token": csrf, "idempotency-key": randomUUID() }, data });
expect(response.status(), await response.text()).toBeLessThan(300); return response.json();
};
await post("/projects/with-initial-revision", { project: { id, name: `Synthetic receipt project ${width}`, status: "planned", description: "Receipt continuity regression." }, revision: { id: revision, name: "Initial", status: "concept", fabricationRoute: "none" } });
const createdLine = await post(`/project-revisions/${revision}/bom`, { name: "Receipt connectors", requiredQuantity: 4, unit: "each", role: "consumed", optional: false, constraints: {}, alternatives: [] });
const readRequirement = async () => {
const response = await page.request.get(`/api/v1/project-revisions/${revision}/bom`);
expect(response.ok(), await response.text()).toBe(true);
const lines = await response.json();
const line = lines.find((candidate: { id: string }) => candidate.id === createdLine.data.id);
expect(line).toBeDefined();
return line;
};
await page.goto(`/#/projects/${id}/offers`); await page.reload();
const row = page.locator(".sourcing-requirement");
await expect(row.getByRole("button", { name: "Match owned stock" })).toBeVisible();
await row.getByRole("button", { name: "Record quote for Receipt connectors" }).click();
await row.getByLabel("Supplier", { exact: true }).fill("Synthetic supplier");
await row.getByLabel("Supplier source URL").fill("https://supplier.example/connectors");
await row.getByLabel("Quantity per pack", { exact: true }).fill("10");
await row.getByLabel("Pack price", { exact: true }).fill("2.50");
await row.getByRole("button", { name: "Save quote" }).click();
await row.getByLabel("I checked that this quoted item meets the current requirement").check();
await row.getByRole("button", { name: "Use reviewed quote" }).click();
await row.getByRole("button", { name: "Record received stock" }).click();
const add = page.getByRole("dialog", { name: "Add to inventory", exact: true });
await expect(add.getByRole("region", { name: "Receiving for requirement" })).toContainText("Receipt connectors");
await add.getByRole("combobox", { name: "What are you adding?" }).selectOption("electronic");
await add.getByRole("button", { name: "Continue", exact: true }).click();
const form = page.getByRole("dialog");
await expect(form.getByLabel("Name", { exact: true })).toHaveValue("Receipt connectors");
await expect(form.getByLabel("Quantity received", { exact: true })).toHaveValue("");
await form.getByLabel("Quantity received", { exact: true }).fill("4");
await form.getByRole("button", { name: "Add item", exact: true }).click();
const drawer = page.getByRole("dialog", { name: /^Receipt connectors/u });
await expect(drawer.getByRole("region", { name: "Continue receiving stock" })).toContainText("Confirm its physical count above");
const requirementBeforeCount = await readRequirement();
expect(requirementBeforeCount.itemId ?? null).toBeNull();
await drawer.getByLabel("Counted quantity").fill("4");
await drawer.getByRole("button", { name: "Review physical count", exact: true }).click();
const review = page.getByRole("alertdialog", { name: "Review physical count", exact: true });
await review.getByRole("button", { name: "Confirm physical count", exact: true }).click();
await expect(review).toHaveCount(0);
await expect(drawer.getByRole("status", { name: "Physical count saved", exact: true })).toContainText("Confirmed 4 pieces");
expect(await readRequirement()).toEqual(requirementBeforeCount);
await expect(drawer.getByRole("region", { name: "Continue receiving stock" })).toContainText("Physical quantity recorded");
await expect(drawer.getByRole("button", { name: "Done", exact: true })).toHaveCount(0);
await drawer.getByRole("button", { name: "Return to Receipt connectors", exact: true }).click();
await expect(page).toHaveURL(new RegExp(`/projects/${id}/plan$`, "u"));
const edit = page.getByRole("dialog", { name: "Part details", exact: true });
await expect(edit.getByLabel("Requirement name", { exact: true })).toHaveValue("Receipt connectors");
await expect(edit.getByLabel("Required quantity", { exact: true })).toHaveValue("4");
await expect(edit.getByRole("region", { name: "Selected stock candidate", exact: true })).toContainText("Receipt connectors");
await expect(edit.getByRole("region", { name: "Selected stock candidate", exact: true })).toContainText("Selection is a planning choice, not confirmation of fit or usable stock.");
await edit.getByRole("button", { name: "Choose another owned item", exact: true }).click();
await expect(edit.getByRole("button", { name: "Clear owned item selection" })).toBeVisible();
expect(await readRequirement()).toEqual(requirementBeforeCount);
await edit.getByRole("button", { name: "Save requirement", exact: true }).click();
await expect(edit).toHaveCount(0);
expect((await readRequirement()).itemId).toBeTruthy();
await page.getByRole("tab", { name: /^Parts/u }).click();
await expect(page.locator(".bom-row")).toContainText("Ready");
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true);
});