48 lines
4.4 KiB
TypeScript
48 lines
4.4 KiB
TypeScript
import AxeBuilder from '@axe-core/playwright';
|
|
import { expect, test, type Page, type Route } from '@playwright/test';
|
|
|
|
const nowSeconds = Math.floor(Date.parse('2026-09-01T10:00:00Z') / 1000);
|
|
const metrics = [
|
|
{ semanticName: 'host.cpu.utilization', description: 'CPU-gebruik van de host', unit: 'percent', valueKind: 'gauge', defaultAggregation: 'avg', allowedVisualizations: ['timeseries'], limits: { maxRangeSeconds: 2_592_000, maxSeries: 20, maxPoints: 4000, timeoutSeconds: 5 } },
|
|
{ semanticName: 'host.memory.utilization', description: 'Geheugengebruik van de host', unit: 'percent', valueKind: 'gauge', defaultAggregation: 'avg', allowedVisualizations: ['timeseries'], limits: { maxRangeSeconds: 2_592_000, maxSeries: 20, maxPoints: 4000, timeoutSeconds: 5 } },
|
|
];
|
|
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: '2026-09-01T10:00:00Z', overallState: 'healthy', components: [], backup: { state: 'disabled', reason: 'not_configured' }, sourceLag: [] }));
|
|
await page.route('**/api/v1/session', (route) => fulfill(route, { subject: 'viewer', role: 'viewer', environment: 'test', permissions: { view: true, operate: false, edit: false, admin: false } }));
|
|
await page.route('**/api/v1/host', (route) => fulfill(route, { identity: { name: 'explore-fixture' } }));
|
|
await page.route('**/api/v1/incidents**', (route) => fulfill(route, { items: [{ id: 'incident-1', title: 'Opslagincident', severity: 'warning', updatedAt: '2026-09-01T09:55:00Z' }] }));
|
|
await page.route('**/api/v1/alerts**', (route) => fulfill(route, { items: [] }));
|
|
}
|
|
|
|
test('operator finds, compares and queries a local custom range as UTC', async ({ page }, testInfo) => {
|
|
test.skip(testInfo.project.name === 'wallboard-chromium', 'Explore is een interactieve operatorroute.');
|
|
const requests: Array<Record<string, unknown>> = [];
|
|
await shell(page);
|
|
await page.route('**/api/v1/metrics/catalog', (route) => fulfill(route, { version: 'v1', metrics, bindings: metrics.map((metric) => ({ semanticName: metric.semanticName, state: 'supported' })) }));
|
|
await page.route('**/api/v1/metrics/query-range', async (route) => {
|
|
const body = route.request().postDataJSON() as Record<string, unknown>; requests.push(body);
|
|
await fulfill(route, { status: 'success', data: { result: [{ metric: { host: 'tower' }, values: [[nowSeconds - 60, '41'], [nowSeconds, '42']] }] }, provenance: { source: 'fixture', metric: body.metric, catalogVersion: 'v1', cacheKey: 'bounded' }, sourceObservedAt: '2026-09-01T10:00:00Z', receivedAt: '2026-09-01T10:00:01Z', freshness: 'fresh', cacheHit: false });
|
|
});
|
|
|
|
await page.goto('/explore');
|
|
await expect(page.getByRole('heading', { level: 1, name: 'Metrics verkennen' })).toBeVisible();
|
|
await page.getByPlaceholder('CPU, opslag, responstijd…').fill('cpu');
|
|
await page.getByRole('button', { name: /host.cpu.utilization/ }).click();
|
|
await expect(page.getByRole('img', { name: /Tijdreeks/ })).toBeVisible();
|
|
await expect(page.getByRole('list', { name: 'Incident- en meldingsannotaties' })).toContainText('Opslagincident');
|
|
await page.getByRole('tab', { name: 'Vergelijken' }).click();
|
|
await page.getByPlaceholder('CPU, opslag, responstijd…').fill('memory');
|
|
await page.getByRole('button', { name: /host.memory.utilization/ }).click();
|
|
await expect(page.getByRole('heading', { name: 'host.memory.utilization' })).toBeVisible();
|
|
await page.getByLabel('Periode').last().selectOption('custom');
|
|
await page.getByLabel('Vanaf').last().fill('2026-09-01T08:00');
|
|
await page.getByLabel('Tot').last().fill('2026-09-01T10:00');
|
|
await expect.poll(() => requests.filter((request) => (request.range as { from?: string })?.from === new Date('2026-09-01T08:00').toISOString()).length).toBeGreaterThan(0);
|
|
const latest = requests.at(-1)!;
|
|
expect(latest).toMatchObject({ maxSeries: 20, maxPoints: 4000, range: { from: new Date('2026-09-01T08:00').toISOString(), to: new Date('2026-09-01T10:00').toISOString() } });
|
|
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([]);
|
|
});
|