Migración desde workspace-v2/projects/template-saas/apps/frontend Este repositorio es parte del estándar multi-repo v2 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
164 lines
3.4 KiB
TypeScript
164 lines
3.4 KiB
TypeScript
import { Page, expect } from '@playwright/test';
|
|
|
|
/**
|
|
* Wait for page to be fully loaded
|
|
*/
|
|
export async function waitForPageLoad(page: Page): Promise<void> {
|
|
await page.waitForLoadState('networkidle');
|
|
}
|
|
|
|
/**
|
|
* Wait for API call to complete
|
|
*/
|
|
export async function waitForApi(
|
|
page: Page,
|
|
urlPattern: string | RegExp
|
|
): Promise<void> {
|
|
await page.waitForResponse(
|
|
(response) =>
|
|
(typeof urlPattern === 'string'
|
|
? response.url().includes(urlPattern)
|
|
: urlPattern.test(response.url())) && response.status() === 200
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Fill form fields from object
|
|
*/
|
|
export async function fillForm(
|
|
page: Page,
|
|
fields: Record<string, string>
|
|
): Promise<void> {
|
|
for (const [name, value] of Object.entries(fields)) {
|
|
const input = page.locator(`input[name="${name}"], textarea[name="${name}"]`);
|
|
if (await input.count() > 0) {
|
|
await input.fill(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Submit form and wait for response
|
|
*/
|
|
export async function submitFormAndWait(
|
|
page: Page,
|
|
apiUrlPattern?: string | RegExp
|
|
): Promise<void> {
|
|
const submitPromise = page.click('button[type="submit"]');
|
|
|
|
if (apiUrlPattern) {
|
|
await Promise.all([
|
|
submitPromise,
|
|
waitForApi(page, apiUrlPattern),
|
|
]);
|
|
} else {
|
|
await submitPromise;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check for toast message
|
|
*/
|
|
export async function expectToast(
|
|
page: Page,
|
|
type: 'success' | 'error' | 'info',
|
|
messageContains?: string
|
|
): Promise<void> {
|
|
const toast = page.locator(`[data-testid="toast-${type}"], .toast-${type}`);
|
|
await expect(toast).toBeVisible({ timeout: 5000 });
|
|
|
|
if (messageContains) {
|
|
await expect(toast).toContainText(messageContains);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Navigate with authentication check
|
|
*/
|
|
export async function navigateTo(
|
|
page: Page,
|
|
path: string,
|
|
options?: { waitForApi?: string | RegExp }
|
|
): Promise<void> {
|
|
const navigationPromise = page.goto(path);
|
|
|
|
if (options?.waitForApi) {
|
|
await Promise.all([
|
|
navigationPromise,
|
|
waitForApi(page, options.waitForApi),
|
|
]);
|
|
} else {
|
|
await navigationPromise;
|
|
await waitForPageLoad(page);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get table row count
|
|
*/
|
|
export async function getTableRowCount(
|
|
page: Page,
|
|
tableSelector: string = 'table tbody tr'
|
|
): Promise<number> {
|
|
return await page.locator(tableSelector).count();
|
|
}
|
|
|
|
/**
|
|
* Click table row action button
|
|
*/
|
|
export async function clickRowAction(
|
|
page: Page,
|
|
rowIndex: number,
|
|
actionName: string
|
|
): Promise<void> {
|
|
const row = page.locator('table tbody tr').nth(rowIndex);
|
|
await row.locator(`[data-testid="action-${actionName}"]`).click();
|
|
}
|
|
|
|
/**
|
|
* Generate unique test email
|
|
*/
|
|
export function generateTestEmail(): string {
|
|
const timestamp = Date.now();
|
|
return `test.${timestamp}@example.com`;
|
|
}
|
|
|
|
/**
|
|
* Generate unique test slug
|
|
*/
|
|
export function generateTestSlug(): string {
|
|
const timestamp = Date.now();
|
|
return `test-company-${timestamp}`;
|
|
}
|
|
|
|
/**
|
|
* Take screenshot for debugging
|
|
*/
|
|
export async function debugScreenshot(
|
|
page: Page,
|
|
name: string
|
|
): Promise<void> {
|
|
await page.screenshot({
|
|
path: `./tests/e2e/screenshots/${name}-${Date.now()}.png`,
|
|
fullPage: true,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Mock API response
|
|
*/
|
|
export async function mockApiResponse(
|
|
page: Page,
|
|
urlPattern: string | RegExp,
|
|
response: object,
|
|
status: number = 200
|
|
): Promise<void> {
|
|
await page.route(urlPattern, (route) => {
|
|
route.fulfill({
|
|
status,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify(response),
|
|
});
|
|
});
|
|
}
|