/** * Authentication helper for cPad Control Panel tests. * * Usage in tests that do NOT use the pre-saved storageState: * import { loginAsAdmin } from '../helpers/auth'; * await loginAsAdmin(page); * * The cpad-setup project (auth.setup.ts) calls loginAsAdmin once and persists * the session to tests/.auth/admin.json so all other cpad tests reuse it. */ import { type Page, expect } from '@playwright/test'; import path from 'path'; export const ADMIN_EMAIL = 'gregor@klevze.si'; export const ADMIN_PASSWORD = 'Gre15#10gor!1976$'; export const CP_PATH = '/cp'; export const DASHBOARD_PATH = '/cp/dashboard'; export const AUTH_FILE = path.join('tests', '.auth', 'admin.json'); /** * Perform a full cPad login and wait for the dashboard to load. * Verifies the redirect ends up on a /cp/dashboard URL. */ export async function loginAsAdmin(page: Page): Promise { // Attach console-error listener so callers can detect JS exceptions page.on('console', (msg) => { if (msg.type() === 'error') { console.warn(`[CONSOLE ERROR] ${msg.text()}`); } }); await page.goto(CP_PATH); // Wait for the login form to be ready const emailField = page.locator('input[name="email"], input[type="email"]').first(); const passwordField = page.locator('input[name="password"], input[type="password"]').first(); const submitButton = page.locator('button[type="submit"], input[type="submit"]').first(); await emailField.waitFor({ state: 'visible', timeout: 15_000 }); await emailField.fill(ADMIN_EMAIL); await passwordField.fill(ADMIN_PASSWORD); await submitButton.click(); // After login, the panel may show a 2FA screen or land on dashboard // Wait up to 20 s for a URL that contains /cp (but isn't the login page) await page.waitForURL((url) => url.pathname.startsWith(CP_PATH) && !url.pathname.endsWith('/login'), { timeout: 20_000, }); } /** * Verify the current page is the cPad dashboard. * Call this *after* loginAsAdmin to assert a successful login. */ export async function assertDashboard(page: Page): Promise { await expect(page).toHaveURL(new RegExp(`${CP_PATH}`)); } /** * Attach console-error and network-failure listeners to the page. * Returns arrays that accumulate errors so the calling test can assert them. */ export function attachErrorListeners(page: Page): { consoleErrors: string[]; networkErrors: string[]; } { const consoleErrors: string[] = []; const networkErrors: string[] = []; page.on('console', (msg) => { if (msg.type() === 'error') { consoleErrors.push(msg.text()); } }); page.on('pageerror', (err) => { consoleErrors.push(`[pageerror] ${err.message}`); }); page.on('response', (response) => { const status = response.status(); if (status >= 500) { networkErrors.push(`HTTP ${status}: ${response.url()}`); } }); page.on('requestfailed', (request) => { networkErrors.push(`[requestfailed] ${request.url()} — ${request.failure()?.errorText}`); }); return { consoleErrors, networkErrors }; }