/** * Test utility functions for ROA2WEB frontend testing */ /** * Wait for element to be visible with custom timeout * @param {Page} page - Playwright page object * @param {string} selector - CSS selector * @param {number} timeout - Timeout in milliseconds */ export async function waitForVisible(page, selector, timeout = 10000) { await page.waitForSelector(selector, { state: 'visible', timeout }); } /** * Wait for all API calls to complete * @param {Page} page - Playwright page object */ export async function waitForApiCalls(page) { await page.waitForLoadState('networkidle'); } /** * Take screenshot with timestamp * @param {Page} page - Playwright page object * @param {string} name - Screenshot name */ export async function takeTimestampedScreenshot(page, name) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); await page.screenshot({ path: `test-results/${name}-${timestamp}.png`, fullPage: true }); } /** * Check if element exists in DOM (without waiting) * @param {Page} page - Playwright page object * @param {string} selector - CSS selector * @returns {boolean} True if element exists */ export async function elementExists(page, selector) { const element = await page.$(selector); return element !== null; } /** * Get element text content safely * @param {Page} page - Playwright page object * @param {string} selector - CSS selector * @returns {string|null} Text content or null if element not found */ export async function getTextContent(page, selector) { try { const element = await page.locator(selector); if (await element.isVisible()) { return await element.textContent(); } } catch (error) { console.warn(`Element not found: ${selector}`); } return null; } /** * Wait for toast message and return its content * @param {Page} page - Playwright page object * @param {string} type - Toast type: 'error', 'success', 'info', 'warn' * @param {number} timeout - Timeout in milliseconds * @returns {string|null} Toast message content */ export async function waitForToast(page, type = 'error', timeout = 5000) { try { const toastSelector = `.p-toast-message-${type}`; await page.waitForSelector(toastSelector, { timeout }); return await page.locator(toastSelector).textContent(); } catch (error) { return null; } } /** * Fill form fields from object * @param {Page} page - Playwright page object * @param {Object} fields - Object with selector: value pairs */ export async function fillForm(page, fields) { for (const [selector, value] of Object.entries(fields)) { await page.fill(selector, value); } } /** * Check if current URL matches pattern * @param {Page} page - Playwright page object * @param {string} pattern - URL pattern to match * @returns {boolean} True if URL matches */ export function urlMatches(page, pattern) { return page.url().includes(pattern); } /** * Mock successful authentication for tests * @param {Page} page - Playwright page object */ export async function mockSuccessfulAuth(page) { await page.route('**/api/auth/login', async route => { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ access_token: 'mock_access_token', refresh_token: 'mock_refresh_token', user: { id: 1, username: 'testuser', full_name: 'Test User' } }), }); }); } /** * Mock companies API * @param {Page} page - Playwright page object * @param {Array} companies - Array of company objects */ export async function mockCompanies(page, companies = []) { const defaultCompanies = [ { code: 'COMP1', name: 'Test Company 1' }, { code: 'COMP2', name: 'Test Company 2' } ]; await page.route('**/api/companies', async route => { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(companies.length > 0 ? companies : defaultCompanies), }); }); } /** * Mock API error response * @param {Page} page - Playwright page object * @param {string} endpoint - API endpoint pattern * @param {number} status - HTTP status code * @param {string} message - Error message */ export async function mockApiError(page, endpoint, status = 500, message = 'Internal server error') { await page.route(endpoint, async route => { await route.fulfill({ status, contentType: 'application/json', body: JSON.stringify({ detail: message }), }); }); } /** * Clear all localStorage data * @param {Page} page - Playwright page object */ export async function clearStorage(page) { await page.evaluate(() => { localStorage.clear(); sessionStorage.clear(); }); } /** * Set viewport to common device size * @param {Page} page - Playwright page object * @param {string} device - Device name: 'mobile', 'tablet', 'desktop' */ export async function setDeviceViewport(page, device) { const viewports = { mobile: { width: 375, height: 667 }, tablet: { width: 768, height: 1024 }, desktop: { width: 1024, height: 768 }, wide: { width: 1920, height: 1080 } }; if (viewports[device]) { await page.setViewportSize(viewports[device]); } }