Files
ITWorx-Pulse-Public/apps/web/tests/e2e/mobile-incident.spec.ts
T
2026-09-30 01:14:48 +00:00

60 lines
4.6 KiB
TypeScript

import AxeBuilder from '@axe-core/playwright';
import { expect, test } from '@playwright/test';
const now = new Date().toISOString();
test('mobile incident command mode is prioritized, bounded and accessible', async ({ page }, testInfo) => {
test.skip(testInfo.project.name !== 'mobile-chromium', 'Mobile incident mode uses the supported 390x844 viewport.');
const mutations: Array<{ path: string; method: string; ifMatch: string | null; idempotencyKey: string | null; body: unknown }> = [];
let canOperate = true;
await page.route('**/api/v1/**', async (route) => {
const path = new URL(route.request().url()).pathname;
if (route.request().method() !== 'GET') mutations.push({ path, method: route.request().method(), ifMatch: route.request().headers()['if-match'] ?? null, idempotencyKey: route.request().headers()['idempotency-key'] ?? null, body: route.request().postDataJSON() });
const body = path === '/api/v1/session' ? {
subject: canOperate ? 'operator-1' : 'viewer-1', role: canOperate ? 'operator' : 'viewer', environment: 'test', permissions: { view: true, operate: canOperate, edit: false, admin: false },
} : path === '/api/v1/system/status' ? {
version: '1', generatedAt: now, overallState: 'degraded', components: [],
backup: { state: 'disabled', reason: 'not_configured' }, sourceLag: [],
} : path === '/api/v1/incidents/incident-1' ? {
incident: {
id: 'incident-1', correlationKey: 'cachepool', title: 'Cachepool bijna vol',
summary: 'Cachepool is 92% gebruikt en groeit sneller dan verwacht.', severity: 'critical',
status: 'open', startedAt: now, correlationMethod: 'temporal-window', confidence: .84,
revision: 2, updatedAt: now, ownerUserId: '', alerts: [
{ alertId: 'alert-1', rationale: 'Capaciteitsdrempel van 90% overschreden', confidence: .84, correlationMethod: 'temporal-window', manual: false, createdAt: now },
], notes: [{ id: 'note-1', incidentId: 'incident-1', author: 'Pulse', body: 'Mover is niet actief.', createdAt: now }],
},
} : path === '/api/v1/alerts/alert-1' ? {
alert: { id: 'alert-1', state: 'firing', retainedState: 'firing', ruleName: 'Cachepoolcapaciteit', severity: 'critical', reason: 'Capaciteitsdrempel overschreden', revision: 7, updatedAt: now },
} : path === '/api/v1/alerts/alert-1/acknowledge' ? {
alert: { id: 'alert-1', state: 'acknowledged', revision: 8 },
} : {};
await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(body) });
});
await page.goto('/incidents/incident-1');
await expect(page.getByRole('heading', { level: 1, name: 'Cachepool bijna vol' })).toBeVisible();
await expect(page.locator('.incident-command-strip')).toContainText('Kritiek');
await expect(page.locator('.incident-command-strip')).toContainText('84%');
await expect(page.locator('.incident-timeline')).toContainText('Capaciteitsdrempel van 90% overschreden');
await page.getByRole('button', { name: 'Melding erkennen' }).click();
await expect(page.getByRole('status')).toContainText('lost de infrastructuur niet automatisch op');
expect(mutations).toHaveLength(1);
expect(mutations[0]).toMatchObject({ path: '/api/v1/alerts/alert-1/acknowledge', method: 'POST', ifMatch: '7', body: { evaluationKey: 'incident-incident-1-alert-alert-1-ack-7' } });
expect(mutations[0].idempotencyKey).toBe('incident-incident-1-alert-alert-1-ack-7');
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBe(390);
const undersizedTargets = await page.locator('button, .mobile-navigation a, .mobile-more summary').evaluateAll((items) => items.filter((item) => {
const style = getComputedStyle(item); return style.display !== 'none' && style.visibility !== 'hidden' && item.getClientRects().length > 0;
}).map((item) => ({ label: item.textContent?.trim(), height: item.getBoundingClientRect().height })).filter((item) => item.height < 44));
expect(undersizedTargets).toEqual([]);
const axe = await new AxeBuilder({ page }).analyze();
expect(axe.violations.filter((item) => item.impact === 'critical' || item.impact === 'serious')).toEqual([]);
canOperate = false;
await page.reload();
await expect(page.getByRole('button', { name: 'Melding erkennen' })).toHaveCount(0);
await expect(page.getByRole('button', { name: 'Eigenaar opslaan' })).toBeDisabled();
await expect(page.getByText('Je rol kan de opvolgcontext alleen bekijken.')).toBeVisible();
expect(mutations).toHaveLength(1);
if (process.env.PULSE_CAPTURE_VISUALS) await page.screenshot({ path: '../../artifacts/evidence/M14-04/mobile-incident-command.png', fullPage: true });
});