41 lines
3.8 KiB
TypeScript
41 lines
3.8 KiB
TypeScript
import AxeBuilder from '@axe-core/playwright';
|
|
import { expect, test, type Page, type Route } from '@playwright/test';
|
|
|
|
const observedAt = '2026-09-01T10:00:00Z';
|
|
const layout = { desktop: { x: 0, y: 0, w: 6, h: 4, visible: true }, tablet: { x: 0, y: 0, w: 6, h: 4, visible: true }, mobile: { x: 0, y: 0, w: 1, h: 4, visible: true }, wallboard: { x: 0, y: 0, w: 6, h: 4, visible: true } };
|
|
|
|
async function fulfill(route: Route, body: unknown): Promise<void> { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(body) }); }
|
|
async function shell(page: Page): Promise<void> {
|
|
await page.route('**/api/v1/system/status', (route) => fulfill(route, { version: '1.5.0', generatedAt: observedAt, overallState: 'healthy', components: [], backup: { state: 'disabled', reason: 'not_configured' }, sourceLag: [] }));
|
|
await page.route('**/api/v1/session', (route) => fulfill(route, { subject: 'viewer-1', role: 'viewer', environment: 'test', permissions: { view: true, operate: false, edit: false, admin: false } }));
|
|
await page.route('**/api/v1/host', (route) => fulfill(route, { identity: { name: 'runtime-fixture' } }));
|
|
}
|
|
|
|
test('dashboard renders bounded alerts, incidents, text and contains an unknown type', async ({ page }, testInfo) => {
|
|
test.skip(testInfo.project.name === 'wallboard-chromium', 'De runtimeflow wordt apart als wallboard gevalideerd.');
|
|
await shell(page);
|
|
await page.route('**/api/v1/alerts**', (route) => fulfill(route, { items: [{ id: 'alert-1', ruleName: 'Disk warm', state: 'firing', severity: 'critical', entityName: 'disk1', reason: 'Temperatuur hoog', updatedAt: observedAt }] }));
|
|
await page.route('**/api/v1/incidents**', (route) => fulfill(route, { items: [{ id: 'incident-1', title: 'Opslagincident', status: 'open', severity: 'warning', summary: 'Controle nodig', updatedAt: observedAt }] }));
|
|
await page.route('**/api/v1/dashboards/runtime', (route) => fulfill(route, {
|
|
dashboard: { id: 'runtime', slug: 'runtime', name: 'Runtimebewijs', description: 'Widgetadapters', scope: 'shared', revision: 1, currentVersion: 1 },
|
|
version: { document: { variables: [], widgets: [
|
|
{ id: 'alert-widget', type: 'alert-summary', title: 'Actieve meldingen', data: { sourceType: 'alerts', limit: 1000 }, behavior: { liveIntervalSeconds: 1 }, layouts: layout },
|
|
{ id: 'incident-widget', type: 'table', title: 'Open incidenten', data: { sourceType: 'incidents', limit: 1000 }, behavior: { liveIntervalSeconds: 1 }, layouts: { ...layout, desktop: { ...layout.desktop, x: 6 } } },
|
|
{ id: 'text-widget', type: 'text', title: 'Runbook', data: { sourceType: 'text', text: '# Start\n[Open incidenten](/incidents)\n<script>alert(1)</script>' }, behavior: {}, layouts: { ...layout, desktop: { ...layout.desktop, y: 4 } } },
|
|
{ id: 'unknown-widget', type: 'made-up', title: 'Onbekend', data: { sourceType: 'alerts', limit: 5 }, behavior: {}, layouts: { ...layout, desktop: { ...layout.desktop, x: 6, y: 4 } } },
|
|
] } },
|
|
}));
|
|
|
|
await page.goto('/dashboards/runtime');
|
|
await expect(page.getByRole('heading', { level: 1, name: 'Runtimebewijs' })).toBeVisible();
|
|
await expect(page.getByText('Disk warm')).toBeVisible();
|
|
await expect(page.getByText('Opslagincident')).toBeVisible();
|
|
await expect(page.getByRole('link', { name: 'Open incidenten' })).toHaveAttribute('href', '/incidents');
|
|
await expect(page.getByText('<script>alert(1)</script>')).toBeVisible();
|
|
await expect(page.getByText('Onbekend widgettype')).toBeVisible();
|
|
expect(await page.evaluate(() => document.querySelectorAll('script').length)).toBeLessThan(10);
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1)).toBe(true);
|
|
const serious = (await new AxeBuilder({ page }).analyze()).violations.filter((violation) => violation.impact === 'critical' || violation.impact === 'serious');
|
|
expect(serious).toEqual([]);
|
|
});
|