/** * Languages module tests for cPad. * * Routes under /cp/language/{type} — type can be: app, system * * Coverage: * • Language list pages load without errors * • No console/server errors * • Add-language page loads * • (Optional) CRUD flow when list data is available * * Run: * npx playwright test tests/cpad/modules/languages.spec.ts --project=cpad */ import { test, expect } from '@playwright/test'; import { CP_PATH, attachErrorListeners } from '../../helpers/auth'; import { hasListData, tryCrudCreate } from '../../helpers/crudHelper'; const LANGUAGE_TYPES = ['app', 'system'] as const; test.describe('cPad Languages Module', () => { for (const type of LANGUAGE_TYPES) { const basePath = `${CP_PATH}/language/${type}`; test(`language list (${type}) loads without errors`, async ({ page }) => { const { consoleErrors, networkErrors } = attachErrorListeners(page); await page.goto(basePath); await page.waitForLoadState('networkidle'); expect(page.url()).not.toContain('/login'); await expect(page.locator('body')).toBeVisible(); const bodyText = await page.locator('body').textContent() ?? ''; const hasError = /Whoops|Server Error|SQLSTATE|Call to undefined/.test(bodyText); expect(hasError, `Server error on ${basePath}`).toBe(false); expect(consoleErrors.length, `Console errors: ${consoleErrors.join(' | ')}`).toBe(0); expect(networkErrors.length, `HTTP 5xx: ${networkErrors.join(' | ')}`).toBe(0); }); test(`language add page (${type}) loads`, async ({ page }) => { const { consoleErrors, networkErrors } = attachErrorListeners(page); await page.goto(`${basePath}/add`); await page.waitForLoadState('networkidle'); expect(page.url()).not.toContain('/login'); await expect(page.locator('body')).toBeVisible(); expect(consoleErrors.length, `Console errors: ${consoleErrors.join(' | ')}`).toBe(0); expect(networkErrors.length, `HTTP 5xx: ${networkErrors.join(' | ')}`).toBe(0); }); test(`language list (${type}) shows table or empty state`, async ({ page }) => { await page.goto(basePath); await page.waitForLoadState('networkidle'); // Either a data table OR a "no data" message must be present const tableCount = await page.locator('table').count(); const emptyMsgCount = await page.locator( ':has-text("No languages"), :has-text("No records"), :has-text("Empty")', ).count(); expect(tableCount + emptyMsgCount, 'Should show a table or an empty-state message').toBeGreaterThan(0); }); } test('language list (app) — CRUD: add language form submission', async ({ page }) => { const { networkErrors } = attachErrorListeners(page); await page.goto(`${CP_PATH}/language/app/add`); await page.waitForLoadState('networkidle'); if (page.url().includes('/login')) { test.skip(true, 'Skipped: not authenticated'); return; } // Try submitting the add form const didCreate = await tryCrudCreate(page); if (!didCreate) { // The add page itself is the form; submit directly const submit = page.locator('button[type=submit], input[type=submit]').first(); if (await submit.count() > 0 && await submit.isVisible()) { await submit.click(); await page.waitForLoadState('networkidle'); } } expect(networkErrors.length, `HTTP 5xx after form submit: ${networkErrors.join(' | ')}`).toBe(0); }); });