94 lines
3.3 KiB
TypeScript
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();
|
|
}
|