const { expect } = require('@playwright/test'); const path = require('path'); async function readBody(page) { return await page.locator('body').innerText().catch(() => ''); } async function expectNoBackendError(page) { const body = await readBody(page); expect(page.url()).not.toContain('500'); expect(body).not.toMatch(/Internal Server Error|Traceback|Exception in ASGI application|UndefinedError|AttributeError|OperationalError|ProgrammingError/i); } async function extractCsrfFromPage(page) { const token = await page.locator('input[name="csrf_token"]').first().getAttribute('value').catch(() => null); return token || ''; } async function blockedOrNotFound(response, text = '') { const status = response ? response.status() : 0; const safeStatus = [400,401,403,404,405,409,422,429].includes(status); const safeText = /login|required|forbidden|unauthorized|not found|access denied|permission|invalid|csrf|locked|closed/i.test(text || ''); expect(safeStatus || safeText).toBeTruthy(); } async function switchFinancialYearIfPossible(page, yearCode) { if (!yearCode) return false; const selectors = [ 'select[name="active_financial_year"]', 'select[name="financial_year"]', 'select[name="year_code"]', '[data-testid="active-fy-select"]', '[data-testid="financial-year-select"]' ]; for (const sel of selectors) { if (page.isClosed()) return false; const loc = page.locator(sel).first(); let found = 0; try { found = await loc.count(); } catch (_) { if (page.isClosed()) return false; found = 0; } if (found) { try { await loc.selectOption({ value: yearCode }); } catch (_) { try { await loc.selectOption({ label: yearCode }); } catch (__) { continue; } } const formSubmit = loc.locator('xpath=ancestor::form[1]//button[@type="submit" or not(@type)]').first(); if (await formSubmit.count()) await formSubmit.click().catch(() => {}); else await loc.press('Enter').catch(() => {}); await page.waitForLoadState('domcontentloaded').catch(() => {}); return true; } } const link = page.getByRole('link', { name: new RegExp(yearCode.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i') }).first(); if (await link.count()) { await link.click().catch(() => {}); await page.waitForLoadState('domcontentloaded').catch(() => {}); return true; } return false; } function uploadPath(fileName) { return path.resolve(__dirname, '..', 'test-data', 'uploads', fileName); } module.exports = { readBody, expectNoBackendError, extractCsrfFromPage, blockedOrNotFound, switchFinancialYearIfPossible, uploadPath, };