/** * Shared login helper for Playwright @playwright/test spec files. * Uses the project baseURL (http://localhost:3000) from playwright.config.ts. */ import { type Page, expect } from "@playwright/test"; export interface Credentials { email: string; password: string; } export const USERS = { TECH: { email: "tech@pelagia.local", password: "tech1234" }, MANNING: { email: "manning@pelagia.local", password: "manning1234" }, ACCOUNTS: { email: "accounts@pelagia.local", password: "accounts1234" }, MANAGER: { email: "manager@pelagia.local", password: "manager1234" }, SUPERUSER: { email: "superuser@pelagia.local", password: "super1234" }, AUDITOR: { email: "auditor@pelagia.local", password: "audit1234" }, ADMIN: { email: "admin@pelagia.local", password: "admin1234" }, } satisfies Record; export async function login(page: Page, creds: Credentials): Promise { await page.goto("/login"); await page.getByLabel(/email address/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 }); console.log(`✓ Logged in as ${creds.email}`); } export async function fillPoHeader(page: Page, title: string): Promise { await page.waitForSelector('input[name="title"]', { timeout: 15_000 }); await page.locator('input[name="title"]').fill(title); await page.locator('select[name="vesselId"]').selectOption({ index: 1 }); await page.locator('select[name="accountId"]').selectOption({ index: 1 }); } export async function fillFirstLineItem( page: Page, { name, quantity, unitPrice, description, }: { name: string; quantity: string; unitPrice: string; description?: string; } ): Promise { const lineItems = page.locator("section").filter({ has: page.getByRole("heading", { name: /line items/i }), }); const firstRow = lineItems.locator("tbody tr").first(); await firstRow.getByPlaceholder("Item name *").fill(name); if (description) { await firstRow.getByPlaceholder("Description (optional)").fill(description); } await firstRow.locator('input[type="number"]').first().fill(quantity); await firstRow.locator('input[placeholder="0.00"]').fill(unitPrice); } /** * Create a minimal draft PO and return the absolute PO URL. * Uses name-based selectors since the PO form labels have no htmlFor binding. */ export async function createDraftPo(page: Page, title: string): Promise { await page.goto("/po/new"); await fillPoHeader(page, title); await fillFirstLineItem(page, { name: "Test item", quantity: "1", unitPrice: "100", }); await page.getByRole("button", { name: /save as draft/i }).click(); await expect(page).toHaveURL(/\/po\//, { timeout: 20_000 }); return page.url(); } /** Create a PO and submit it for approval; returns the PO URL. */ export async function submitPo(page: Page, title: string): Promise { await page.goto("/po/new"); await fillPoHeader(page, title); await fillFirstLineItem(page, { name: "Engine gasket", quantity: "2", unitPrice: "250", }); await page.getByRole("button", { name: /submit for approval/i }).click(); await expect(page).toHaveURL(/\/po\//, { timeout: 20_000 }); return page.url(); }