113 lines
3.9 KiB
TypeScript
113 lines
3.9 KiB
TypeScript
/**
|
|
* Translations module tests for cPad.
|
|
*
|
|
* Routes under /cp/translation/{file}
|
|
* The most common translation file is "app".
|
|
*
|
|
* Coverage:
|
|
* • Main translation index page loads
|
|
* • Translation list page for "app" file loads
|
|
* • Add translation entry page loads
|
|
* • Translation grid page loads
|
|
* • No console/server errors on any page
|
|
* • (Optional) inline edit via CRUD helper
|
|
*
|
|
* Run:
|
|
* npx playwright test tests/cpad/modules/translations.spec.ts --project=cpad
|
|
*/
|
|
|
|
import { test, expect } from '@playwright/test';
|
|
import { CP_PATH, attachErrorListeners } from '../../helpers/auth';
|
|
|
|
/** Translation file slugs to probe — add more as needed */
|
|
const TRANSLATION_FILES = ['app'] as const;
|
|
|
|
/** Reusable page-health assertion */
|
|
async function assertPageHealthy(page: import('@playwright/test').Page, path: 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(err.message));
|
|
page.on('response', (res) => {
|
|
if (res.status() >= 500) networkErrors.push(`HTTP ${res.status()}: ${res.url()}`);
|
|
});
|
|
|
|
await page.goto(path);
|
|
await page.waitForLoadState('networkidle', { timeout: 20_000 });
|
|
|
|
expect(page.url(), `${path} must not redirect to login`).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 at ${path}`).toBe(false);
|
|
|
|
expect(consoleErrors.length, `Console errors at ${path}: ${consoleErrors.join(' | ')}`).toBe(0);
|
|
expect(networkErrors.length, `HTTP 5xx at ${path}: ${networkErrors.join(' | ')}`).toBe(0);
|
|
}
|
|
|
|
test.describe('cPad Translations Module', () => {
|
|
for (const file of TRANSLATION_FILES) {
|
|
const base = `${CP_PATH}/translation/${file}`;
|
|
|
|
test(`translation main page (${file}) loads`, async ({ page }) => {
|
|
await assertPageHealthy(page, base);
|
|
});
|
|
|
|
test(`translation list page (${file}) loads`, async ({ page }) => {
|
|
await assertPageHealthy(page, `${base}/list`);
|
|
});
|
|
|
|
test(`translation add page (${file}) loads`, async ({ page }) => {
|
|
await assertPageHealthy(page, `${base}/add`);
|
|
});
|
|
|
|
test(`translation grid page (${file}) loads`, async ({ page }) => {
|
|
await assertPageHealthy(page, `${base}/grid`);
|
|
});
|
|
|
|
test(`translation list (${file}) renders content`, async ({ page }) => {
|
|
await page.goto(`${base}/list`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
if (page.url().includes('/login')) {
|
|
test.skip(true, 'Not authenticated');
|
|
return;
|
|
}
|
|
|
|
// A table, a grid element, or an empty-state message should be present
|
|
const tableCount = await page.locator('table, .grid, [class*="grid"]').count();
|
|
const emptyMsgCount = await page.locator(
|
|
':has-text("No translations"), :has-text("No records"), :has-text("Empty")',
|
|
).count();
|
|
const inputCount = await page.locator('input[type=text], textarea').count();
|
|
|
|
expect(
|
|
tableCount + emptyMsgCount + inputCount,
|
|
'Translation list should contain table, grid, empty state, or editable fields',
|
|
).toBeGreaterThan(0);
|
|
});
|
|
|
|
test(`translation add page (${file}) contains a form`, async ({ page }) => {
|
|
await page.goto(`${base}/add`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
if (page.url().includes('/login')) {
|
|
test.skip(true, 'Not authenticated');
|
|
return;
|
|
}
|
|
|
|
const formCount = await page.locator('form').count();
|
|
const inputCount = await page.locator('input:not([type=hidden]), textarea').count();
|
|
|
|
expect(
|
|
formCount + inputCount,
|
|
'Add translation page should contain a form or input fields',
|
|
).toBeGreaterThan(0);
|
|
});
|
|
}
|
|
});
|