import { Page, expect } from '@playwright/test'; export const TEST_USER = { username: 'e2e_testuser', password: 'TestPassword123!', }; /** * Log in via the UI login form. */ export async function login(page: Page, username: string, password: string) { await page.goto('/login'); await page.fill('#loginUsername', username); await page.fill('#loginPassword', password); const [response] = await Promise.all([ page.waitForResponse((resp) => resp.url().includes('/api/auth/login')), page.click('#loginSubmit'), ]); expect(response.status()).toBeLessThan(400); // Wait for success message or redirect await Promise.race([ page.locator('#authSuccess').waitFor({ state: 'visible', timeout: 5000 }), page.waitForURL('**/web**', { timeout: 5000 }), ]); } /** * Register a new unique user via the UI form. */ export async function register(page: Page, username: string, password: string) { await page.goto('/login'); await page.click('text=Inscription'); await page.fill('#registerUsername', username); await page.fill('#registerPassword', password); await page.fill('#registerPasswordConfirm', password); const [response] = await Promise.all([ page.waitForResponse((resp) => resp.url().includes('/api/auth/register')), page.click('#registerSubmit'), ]); expect(response.status()).toBeLessThan(400); await page.locator('#authSuccess').waitFor({ state: 'visible', timeout: 5000 }); } /** * Switch to a tab by name (Accueil, Anime, Série, Watchlist, etc.) */ export async function switchTab(page: Page, tabName: string) { // Wait for tabs to be rendered await page.locator('nav#mainTabs .tab').first().waitFor({ state: 'visible', timeout: 5000 }); const tab = page.locator('nav#mainTabs .tab', { hasText: new RegExp(tabName, 'i') }); await tab.waitFor({ state: 'visible', timeout: 5000 }); await tab.click(); await expect(tab).toHaveClass(/active/); } /** * Wait for HTMX content to settle (no more hx-request in flight). */ export async function waitForHtmx(page: Page, timeout = 10000) { await page.waitForFunction( () => document.querySelectorAll('.htmx-request').length === 0, { timeout } ); } /** * Check that no unhandled JS errors occurred on the page. */ export function collectJsErrors(page: Page): string[] { const errors: string[] = []; page.on('pageerror', (err) => errors.push(err.message)); return errors; }