116 lines
4.7 KiB
TypeScript
116 lines
4.7 KiB
TypeScript
/**
|
|
* 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();
|
|
});
|