/** * User stories covered: Feature 18 — Mobile Accounts payment actions * - ACCOUNTS at 375×812 can load /payments without Desktop Required overlay * - MGR_APPROVED PO shows "Start Payment Processing" button * - SENT_FOR_PAYMENT PO shows payment reference input and "Confirm Payment Sent" button * * Created: 2026-05-17 */ import { test, expect, type BrowserContext } from "@playwright/test"; import { login, USERS, submitPo } from "../helpers/login"; const MOBILE_VIEWPORT = { width: 375, height: 812 }; async function createApprovedPo( page: import("@playwright/test").Page, context: BrowserContext, title: string ): Promise { 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 18 — Mobile Accounts payment actions", () => { test("US-18a: ACCOUNTS at mobile viewport — /payments loads with NO Desktop Required overlay", async ({ page, }) => { await page.setViewportSize(MOBILE_VIEWPORT); await login(page, USERS.ACCOUNTS); await page.goto("/payments"); // Should NOT see the Desktop Required overlay (ACCOUNTS is a mobile-enabled role) await expect(page.getByText("Desktop Required")).not.toBeVisible(); await expect( page.getByRole("heading", { name: /payment queue/i }) ).toBeVisible(); console.log( "✓ ACCOUNTS at mobile sees Payment Queue (no Desktop Required overlay)" ); }); test("US-18a: ACCOUNTS at mobile — /payments page shows payment queue content", async ({ page, }) => { await page.setViewportSize(MOBILE_VIEWPORT); await login(page, USERS.ACCOUNTS); await page.goto("/payments"); await page.waitForLoadState("networkidle"); // The page shows either a list of PO cards or an empty-state message const hasQueue = (await page.locator("[class*='space-y']").count()) > 0 || (await page.getByText(/no orders in the payment queue/i).isVisible()); expect(hasQueue).toBeTruthy(); console.log("✓ Payment queue content rendered at mobile viewport"); }); test("US-18b: MGR_APPROVED PO shows Start Payment Processing button at mobile", async ({ page, context, }: { page: import("@playwright/test").Page; context: BrowserContext; }) => { const poUrl = await createApprovedPo( page, context, `E2E_MOBILE_PAY_${Date.now()}` ); await context.clearCookies(); await page.setViewportSize(MOBILE_VIEWPORT); await login(page, USERS.ACCOUNTS); await page.goto(poUrl); await page.waitForLoadState("networkidle"); const processBtn = page.getByRole("button", { name: /process payment|start payment/i, }); await expect(processBtn).toBeVisible({ timeout: 10_000 }); console.log("✓ Start Payment Processing button visible at mobile viewport for MGR_APPROVED PO"); }); test("US-18c: SENT_FOR_PAYMENT PO shows reference input and Confirm button at mobile", async ({ page, context, }: { page: import("@playwright/test").Page; context: BrowserContext; }) => { // Create and move to SENT_FOR_PAYMENT const poUrl = await createApprovedPo( page, context, `E2E_MOBILE_SENT_${Date.now()}` ); await context.clearCookies(); await page.setViewportSize(MOBILE_VIEWPORT); await login(page, USERS.ACCOUNTS); await page.goto(poUrl); // Start payment processing await page.getByRole("button", { name: /process payment|start payment/i }).click(); await expect(page.getByText(/sent for payment/i)).toBeVisible({ timeout: 10_000, }); // Now we should see payment reference input and confirm button const refInput = page.getByPlaceholder(/reference|ref/i).first(); await expect(refInput).toBeVisible({ timeout: 5_000 }); const confirmBtn = page.getByRole("button", { name: /confirm payment|mark.*paid/i, }); await expect(confirmBtn).toBeVisible(); console.log( "✓ Payment reference input and Confirm Payment button visible at mobile on SENT_FOR_PAYMENT PO" ); }); test("US-18a: ACCOUNTS mobile bottom nav is visible on /payments", async ({ page, }) => { await page.setViewportSize(MOBILE_VIEWPORT); await login(page, USERS.ACCOUNTS); // MobileBottomNav renders for ACCOUNTS — should be visible at mobile const bottomNav = page.locator("nav.md\\:hidden, nav[class*='md:hidden']"); await expect(bottomNav).toBeVisible(); console.log("✓ Mobile bottom navigation bar visible for ACCOUNTS at mobile viewport"); }); });