Publish curated ITWorx-Pulse source from 0e0633c8ac91cb71312a26837f791035a78d81b8
Public source validation / validate (push) Failing after 2m10s
Public source validation / validate (push) Failing after 2m10s
This commit is contained in:
1 parent
a4956c2af9
commit
db8093b608
88 files changed
+3685
-469
No files matched your search
@@ -0,0 +1,71 @@
|
||||
import { cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { DashboardEditor, validateDashboardLayouts, validateWidget, type EditorWidget } from '../../src/DashboardEditor';
|
||||
|
||||
afterEach(() => { cleanup(); vi.unstubAllGlobals(); });
|
||||
|
||||
function layouts(x: number, y: number, w = 6, h = 4) {
|
||||
return {
|
||||
desktop: { x, y, w, h, visible: true }, tablet: { x: Math.min(x, 2), y, w: Math.min(w, 8), h, visible: true },
|
||||
mobile: { x: 0, y, w: 1, h, visible: true }, wallboard: { x, y, w, h, visible: true },
|
||||
};
|
||||
}
|
||||
|
||||
function widget(id: string, title: string, x: number, y: number, locked = false): EditorWidget {
|
||||
return { id, type: 'stat', title, data: { sourceType: 'inventory', limit: 10 }, visualization: { decimals: 0, thresholds: [] }, behavior: { locked, hidden: false, liveIntervalSeconds: 30 }, layouts: layouts(x, y) };
|
||||
}
|
||||
|
||||
const document = { schemaVersion: 2, id: '00000000-0000-4000-8000-000000000001', slug: 'test', name: 'Test', scope: 'personal', variables: [], widgets: [widget('00000000-0000-4000-8000-000000000011', 'CPU', 0, 0), widget('00000000-0000-4000-8000-000000000012', 'Geheugen', 10, 8)], settings: { defaultTimeRange: '1h' } };
|
||||
|
||||
describe('DashboardEditor spatial composition', () => {
|
||||
it('keeps viewport layouts independent and saves x/y/w/h, thresholds and an internal link', async () => {
|
||||
let savedBody: Record<string, unknown> | undefined;
|
||||
vi.stubGlobal('fetch', vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
|
||||
savedBody = JSON.parse(String(init?.body));
|
||||
return new Response(JSON.stringify({ dashboard: { revision: 2 } }), { status: 200, headers: { 'Content-Type': 'application/json' } });
|
||||
}));
|
||||
const onSaved = vi.fn();
|
||||
const user = userEvent.setup();
|
||||
render(<DashboardEditor dashboardId="dashboard-1" revision={1} document={document} onExit={() => undefined} onSaved={onSaved} />);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Widget naar rechts: CPU' }));
|
||||
expect(screen.getByLabelText('Kolom (x) (Desktop)')).toHaveValue(1);
|
||||
fireEvent.change(screen.getByLabelText('Hoogte in rijen'), { target: { value: '6' } });
|
||||
await user.selectOptions(screen.getByLabelText('Layout'), 'tablet');
|
||||
expect(screen.getByLabelText('Kolom (x) (Tablet)')).toHaveValue(0);
|
||||
fireEvent.change(screen.getByLabelText('Kolom (x) (Tablet)'), { target: { value: '2' } });
|
||||
await user.selectOptions(screen.getByLabelText('Layout'), 'desktop');
|
||||
expect(screen.getByLabelText('Kolom (x) (Desktop)')).toHaveValue(1);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Drempel toevoegen' }));
|
||||
const threshold = screen.getByLabelText('Drempels').querySelector<HTMLElement>('.config-threshold-row')!;
|
||||
fireEvent.change(within(threshold).getByLabelText('Waarde'), { target: { value: '85' } });
|
||||
fireEvent.change(within(threshold).getByLabelText('Kleur'), { target: { value: '#ff8800' } });
|
||||
await user.type(screen.getByLabelText('Interne drilldownlink'), '/incidents');
|
||||
await user.click(screen.getByRole('button', { name: 'Opslaan' }));
|
||||
|
||||
await waitFor(() => expect(onSaved).toHaveBeenCalled());
|
||||
const widgets = savedBody?.widgets as EditorWidget[];
|
||||
expect((widgets[0].layouts?.desktop as Record<string, unknown>)).toMatchObject({ x: 1, y: 0, w: 6, h: 6 });
|
||||
expect((widgets[0].layouts?.tablet as Record<string, unknown>)).toMatchObject({ x: 2, y: 0, w: 6, h: 4 });
|
||||
expect(widgets[0].visualization?.thresholds).toEqual([{ value: 85, color: '#ff8800', label: '' }]);
|
||||
expect(widgets[0].behavior?.link).toBe('/incidents');
|
||||
}, 15_000);
|
||||
|
||||
it('prevents every spatial control from mutating a locked widget', () => {
|
||||
const lockedDocument = { ...document, widgets: [widget('00000000-0000-4000-8000-000000000021', 'Vergrendeld', 2, 3, true)] };
|
||||
render(<DashboardEditor dashboardId="dashboard-1" revision={1} document={lockedDocument} onExit={() => undefined} onSaved={() => undefined} />);
|
||||
expect(screen.getByRole('button', { name: 'Widget naar links: Vergrendeld' })).toBeDisabled();
|
||||
expect(screen.getByRole('button', { name: 'Widget omhoog: Vergrendeld' })).toBeDisabled();
|
||||
expect(screen.getByRole('slider', { name: 'Breedte aanpassen: Vergrendeld' })).toBeDisabled();
|
||||
expect(screen.getByLabelText('Kolom (x) (Desktop)')).toBeDisabled();
|
||||
expect(screen.getByLabelText('Hoogte in rijen')).toBeDisabled();
|
||||
});
|
||||
|
||||
it('rejects unsafe links, malformed thresholds and colliding persisted layouts', () => {
|
||||
expect(validateWidget({ ...widget('x', 'Onveilig', 0, 0), visualization: { thresholds: [{ value: 80, color: 'red' }] }, behavior: { link: 'https://example.test', liveIntervalSeconds: 30 } })).toMatchObject({ 'visualization.thresholds': expect.any(String), 'behavior.link': expect.any(String) });
|
||||
expect(validateDashboardLayouts([widget('a', 'A', 0, 0), widget('b', 'B', 0, 0)])).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user