/** * E2E — Accounts payment workflow. * Covers: A-01 (view payment queue), A-02 (mark PO as paid with reference). */ import { test, expect, type Page } from "@playwright/test"; import { fillFirstLineItem, fillPoHeader } from "./helpers/login"; const TECH = { email: "tech@pelagia.local", password: "tech1234" }; const MGR = { email: "manager@pelagia.local", password: "manager1234" }; const ACCT = { email: "accounts@pelagia.local", password: "accounts1234" }; async function login(page: Page, creds: typeof TECH) { await page.goto("/login"); await page.getByLabel(/email/i).fill(creds.email); await page.getByLabel(/password/i).fill(creds.password); await page.getByRole("button", { name: /sign in/i }).click(); await expect(page).not.toHaveURL(/\/login/, { timeout: 20_000 }); } /** Full flow: create PO as tech → approve as manager → return PO URL */ async function createApprovedPo(page: Page, context: import("@playwright/test").BrowserContext, title: string) { // Step 1: create + submit as tech await login(page, TECH); await page.goto("/po/new"); await fillPoHeader(page, title); await fillFirstLineItem(page, { name: "Deck paint", quantity: "3", unitPrice: "800", }); await page.getByRole("button", { name: /submit for approval/i }).click(); await expect(page).toHaveURL(/\/po\//); const poUrl = page.url(); // Step 2: approve as manager await context.clearCookies(); await login(page, MGR); await page.goto(poUrl); await page.getByRole("button", { name: /^approve$/i }).click(); await expect(page.getByText(/approved/i)).toBeVisible(); return poUrl; } // ── A-01: Payment queue ─────────────────────────────────────────────────────── test("A-01 — accounts user sees the payment queue page", async ({ page }) => { await login(page, ACCT); await page.goto("/payments"); await expect(page.getByRole("heading", { name: /payment/i })).toBeVisible(); // Should show a table or list of approved POs await expect(page.locator("table, [role='list']")).toBeVisible(); }); test("A-01 — accounts dashboard shows payment queue CTA", async ({ page }) => { await login(page, ACCT); await expect(page.getByRole("link", { name: /payment/i })).toBeVisible(); }); test("A-01 — TECHNICAL role cannot access payment queue", async ({ page }) => { await login(page, TECH); await page.goto("/payments"); await expect(page).not.toHaveURL(/payments/); }); // ── A-02: Mark as paid ──────────────────────────────────────────────────────── test("A-02 — accounts user can start processing payment (MGR_APPROVED → SENT_FOR_PAYMENT)", async ({ page, context }) => { const title = `E2E_ACCT_PROCESS_${Date.now()}`; const poUrl = await createApprovedPo(page, context, title); await context.clearCookies(); await login(page, ACCT); await page.goto(poUrl); const processBtn = page.getByRole("button", { name: /process payment|start payment/i }); await expect(processBtn).toBeVisible(); await processBtn.click(); await expect(page.getByText(/sent for payment/i)).toBeVisible(); }); test("A-02 — accounts user can mark PO as paid with a reference number", async ({ page, context }) => { const title = `E2E_ACCT_PAID_${Date.now()}`; const poUrl = await createApprovedPo(page, context, title); await context.clearCookies(); await login(page, ACCT); await page.goto(poUrl); // Process payment first await page.getByRole("button", { name: /process payment|start payment/i }).click(); await expect(page.getByText(/sent for payment/i)).toBeVisible(); // Mark as paid const paymentRefInput = page.getByPlaceholder(/reference|ref/i).first(); await paymentRefInput.fill("NEFT/2026/TEST001"); await page.getByRole("button", { name: /mark.*paid|confirm payment/i }).click(); await expect(page.getByText(/paid/i)).toBeVisible(); }); test("A-02 — payment reference is required to mark as paid", async ({ page, context }) => { const title = `E2E_ACCT_NOREF_${Date.now()}`; const poUrl = await createApprovedPo(page, context, title); await context.clearCookies(); await login(page, ACCT); await page.goto(poUrl); await page.getByRole("button", { name: /process payment|start payment/i }).click(); await expect(page.getByText(/sent for payment/i)).toBeVisible(); // Try to mark as paid without a reference await page.getByRole("button", { name: /mark.*paid|confirm payment/i }).click(); // Should show validation error or stay on same page await expect(page.getByText(/sent for payment/i)).toBeVisible(); });