178 lines
5.9 KiB
TypeScript
178 lines
5.9 KiB
TypeScript
/**
|
|
* User stories covered: Features 5 & 6 — Export gate and approver as signatory
|
|
* - Export buttons (PDF/XLSX) NOT shown on DRAFT/SUBMITTED/MGR_REVIEW POs
|
|
* - Export buttons ARE shown on MGR_APPROVED or later statuses
|
|
* - API returns 403 for DRAFT PO export attempts
|
|
* - XLSX export returns correct content-type for approved POs (Feature 6)
|
|
*
|
|
* Note on Feature 5 export gate:
|
|
* The po-detail.tsx source shows export buttons only render for statuses:
|
|
* ["MGR_APPROVED", "SENT_FOR_PAYMENT", "PAID_DELIVERED", "PARTIALLY_CLOSED", "CLOSED"]
|
|
* This supersedes the old po-export.spec.ts which expected buttons on DRAFT — those tests
|
|
* were written before the export gate fix.
|
|
*
|
|
* Created: 2026-05-17
|
|
*/
|
|
import { test, expect, type BrowserContext } from "@playwright/test";
|
|
import { login, USERS, createDraftPo, submitPo } from "./helpers/login";
|
|
|
|
// Helper: Create a PO and fully approve it (tech → manager approval)
|
|
async function createApprovedPo(
|
|
page: import("@playwright/test").Page,
|
|
context: BrowserContext,
|
|
title: string
|
|
): Promise<string> {
|
|
await login(page, USERS.TECH);
|
|
const poUrl = await submitPo(page, title);
|
|
|
|
await context.clearCookies();
|
|
await login(page, USERS.MANAGER);
|
|
await page.goto(poUrl);
|
|
await page.getByRole("button", { name: /^approve$/i }).click();
|
|
await expect(page.getByText(/approved/i)).toBeVisible({ timeout: 10_000 });
|
|
return poUrl;
|
|
}
|
|
|
|
test.describe("Feature 5 — Export gate: only approved POs can be exported", () => {
|
|
test("US-5a: Export PDF button is NOT shown on a DRAFT PO", async ({ page }) => {
|
|
await login(page, USERS.TECH);
|
|
const poUrl = await createDraftPo(page, `E2E_GATE_DRAFT_${Date.now()}`);
|
|
await page.goto(poUrl);
|
|
|
|
await expect(
|
|
page.getByRole("link", { name: /export pdf/i })
|
|
).not.toBeVisible();
|
|
console.log("✓ Export PDF button correctly absent on DRAFT PO");
|
|
});
|
|
|
|
test("US-5a: Export XLSX button is NOT shown on a DRAFT PO", async ({ page }) => {
|
|
await login(page, USERS.TECH);
|
|
const poUrl = await createDraftPo(page, `E2E_GATE_DRAFTX_${Date.now()}`);
|
|
await page.goto(poUrl);
|
|
|
|
await expect(
|
|
page.getByRole("link", { name: /export xlsx/i })
|
|
).not.toBeVisible();
|
|
console.log("✓ Export XLSX button correctly absent on DRAFT PO");
|
|
});
|
|
|
|
test("US-5a: Export buttons are NOT shown on a SUBMITTED PO", async ({ page }) => {
|
|
await login(page, USERS.TECH);
|
|
const poUrl = await submitPo(page, `E2E_GATE_SUB_${Date.now()}`);
|
|
await page.goto(poUrl);
|
|
|
|
await expect(
|
|
page.getByRole("link", { name: /export pdf/i })
|
|
).not.toBeVisible();
|
|
await expect(
|
|
page.getByRole("link", { name: /export xlsx/i })
|
|
).not.toBeVisible();
|
|
console.log("✓ Export buttons correctly absent on SUBMITTED PO");
|
|
});
|
|
|
|
test("US-5b: Export buttons ARE shown on a MGR_APPROVED PO", async ({
|
|
page,
|
|
context,
|
|
}: {
|
|
page: import("@playwright/test").Page;
|
|
context: BrowserContext;
|
|
}) => {
|
|
const poUrl = await createApprovedPo(
|
|
page,
|
|
context,
|
|
`E2E_GATE_APPROVED_${Date.now()}`
|
|
);
|
|
// Still logged in as manager; view the approved PO
|
|
await page.goto(poUrl);
|
|
|
|
await expect(page.getByRole("link", { name: /export pdf/i })).toBeVisible({
|
|
timeout: 10_000,
|
|
});
|
|
await expect(
|
|
page.getByRole("link", { name: /export xlsx/i })
|
|
).toBeVisible();
|
|
console.log("✓ Export buttons visible on MGR_APPROVED PO");
|
|
});
|
|
|
|
test("US-5c: GET /api/po/[id]/export?format=pdf returns 403 for a DRAFT PO", async ({
|
|
page,
|
|
}) => {
|
|
await login(page, USERS.TECH);
|
|
const poUrl = await createDraftPo(page, `E2E_GATE_API_${Date.now()}`);
|
|
const poId = poUrl.split("/po/")[1].replace(/\/$/, "");
|
|
|
|
const response = await page.request.get(
|
|
`/api/po/${poId}/export?format=pdf`
|
|
);
|
|
expect(response.status()).toBe(403);
|
|
console.log(`✓ API returns 403 for DRAFT PO export (id: ${poId})`);
|
|
});
|
|
|
|
test("US-5c: GET /api/po/[id]/export?format=xlsx returns 403 for a DRAFT PO", async ({
|
|
page,
|
|
}) => {
|
|
await login(page, USERS.TECH);
|
|
const poUrl = await createDraftPo(page, `E2E_GATE_APIX_${Date.now()}`);
|
|
const poId = poUrl.split("/po/")[1].replace(/\/$/, "");
|
|
|
|
const response = await page.request.get(
|
|
`/api/po/${poId}/export?format=xlsx`
|
|
);
|
|
expect(response.status()).toBe(403);
|
|
console.log(`✓ API returns 403 for DRAFT PO XLSX export (id: ${poId})`);
|
|
});
|
|
});
|
|
|
|
test.describe("Feature 6 — Approver as signatory: export content-types", () => {
|
|
test("US-6a: ACCOUNTS user — XLSX export returns HTTP 200 with spreadsheet content-type", async ({
|
|
page,
|
|
context,
|
|
}: {
|
|
page: import("@playwright/test").Page;
|
|
context: BrowserContext;
|
|
}) => {
|
|
// Create and approve a PO first
|
|
const poUrl = await createApprovedPo(
|
|
page,
|
|
context,
|
|
`E2E_XLSX_ACCT_${Date.now()}`
|
|
);
|
|
const poId = poUrl.split("/po/")[1].replace(/\/$/, "");
|
|
|
|
// Switch to accounts user
|
|
await context.clearCookies();
|
|
await login(page, USERS.ACCOUNTS);
|
|
|
|
const response = await page.request.get(
|
|
`/api/po/${poId}/export?format=xlsx`
|
|
);
|
|
expect(response.status()).toBe(200);
|
|
const ct = response.headers()["content-type"] ?? "";
|
|
expect(ct).toContain("spreadsheetml");
|
|
console.log(`✓ XLSX export HTTP 200 with content-type: ${ct}`);
|
|
});
|
|
|
|
test("US-6a: ACCOUNTS user — PDF export returns HTTP 200", async ({
|
|
page,
|
|
context,
|
|
}: {
|
|
page: import("@playwright/test").Page;
|
|
context: BrowserContext;
|
|
}) => {
|
|
const poUrl = await createApprovedPo(
|
|
page,
|
|
context,
|
|
`E2E_PDF_ACCT_${Date.now()}`
|
|
);
|
|
const poId = poUrl.split("/po/")[1].replace(/\/$/, "");
|
|
|
|
await context.clearCookies();
|
|
await login(page, USERS.ACCOUNTS);
|
|
|
|
const response = await page.request.get(
|
|
`/api/po/${poId}/export?format=pdf`
|
|
);
|
|
expect(response.status()).toBe(200);
|
|
console.log("✓ PDF export HTTP 200 for ACCOUNTS user on approved PO");
|
|
});
|
|
});
|