pelagia-portal/App/tests/e2e/helpers/login.ts

94 lines
3.3 KiB
TypeScript

/**
* 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<string, Credentials>;
export async function login(page: Page, creds: Credentials): Promise<void> {
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<void> {
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<void> {
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<string> {
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<string> {
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();
}