Pulse/frontend-modern/src/pages/__tests__/Alerts.helpers.test.ts
rcourtman 4838793677 feat: enhance alerts system with tests and improved thresholds
- Add comprehensive test coverage for alerts package with 285+ new tests
- Implement ThresholdsTable component with metric thresholds display
- Enhance Alerts page UI with improved layout and metric filtering
- Add frontend component tests for Alerts page and ThresholdsTable
- Set up Vitest testing infrastructure for SolidJS components
- Improve config persistence with better validation
- Expand discovery tests with 333+ test cases
- Update API, configuration, and Docker monitoring documentation
2025-10-15 22:25:04 +00:00

162 lines
3.9 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
ALERT_TAB_SEGMENTS,
createDefaultCooldown,
createDefaultEscalation,
createDefaultGrouping,
createDefaultQuietHours,
extractTriggerValues,
getTriggerValue,
normalizeMetricDelayMap,
pathForTab,
tabFromPath,
} from '../Alerts';
describe('normalizeMetricDelayMap', () => {
it('returns empty object when input is nullish', () => {
expect(normalizeMetricDelayMap(undefined)).toEqual({});
// @ts-expect-error - testing runtime null handling
expect(normalizeMetricDelayMap(null)).toEqual({});
});
it('normalizes resource and metric keys while discarding invalid values', () => {
const input = {
Guest: {
CPU: 10,
' ': 5,
memory: -1,
disk: Number.NaN,
},
node: {
Temperature: 30,
disk: 15.6,
},
' ': {
metric: 5,
},
};
const result = normalizeMetricDelayMap(input);
expect(result).toEqual({
guest: {
cpu: 10,
},
node: {
temperature: 30,
disk: 16,
},
});
});
it('drops metric groups that normalize to empty', () => {
const result = normalizeMetricDelayMap({
guest: {
cpu: -1,
mem: Number.NaN,
},
});
expect(result).toEqual({});
});
});
describe('tab path helpers', () => {
it('maps tab to path', () => {
expect(pathForTab('overview')).toBe('/alerts/overview');
expect(pathForTab('schedule')).toBe('/alerts/schedule');
});
it('resolves tab from path', () => {
expect(tabFromPath('/alerts')).toBe('overview');
expect(tabFromPath('/alerts/thresholds')).toBe('thresholds');
expect(tabFromPath('/alerts/thresholds/proxmox')).toBe('thresholds');
expect(tabFromPath('/alerts/custom-rules')).toBe('thresholds');
expect(tabFromPath('/foo/bar')).toBe('overview');
});
it('allows custom segments map', () => {
const custom = { ...ALERT_TAB_SEGMENTS, overview: 'summary' as const };
expect(pathForTab('overview', custom)).toBe('/alerts/summary');
expect(tabFromPath('/alerts/summary', custom)).toBe('overview');
});
});
describe('default schedule helpers', () => {
it('creates quiet hours defaults', () => {
const quiet = createDefaultQuietHours();
const expectedTz = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
expect(quiet).toMatchObject({
enabled: false,
start: '22:00',
end: '08:00',
suppress: {
performance: false,
storage: false,
offline: false,
},
});
expect(quiet.timezone).toBe(expectedTz);
expect(quiet.days).toEqual({
monday: true,
tuesday: true,
wednesday: true,
thursday: true,
friday: true,
saturday: false,
sunday: false,
});
});
it('creates cooldown defaults', () => {
expect(createDefaultCooldown()).toEqual({
enabled: true,
minutes: 30,
maxAlerts: 3,
});
});
it('creates grouping defaults', () => {
expect(createDefaultGrouping()).toEqual({
enabled: true,
window: 5,
byNode: true,
byGuest: false,
});
});
it('creates escalation defaults', () => {
expect(createDefaultEscalation()).toEqual({
enabled: false,
levels: [],
});
});
});
describe('threshold helper utilities', () => {
it('extracts trigger values and ignores non-threshold keys', () => {
const result = extractTriggerValues({
cpu: { trigger: 80, clear: 70 },
memory: 85,
disabled: true,
poweredOffSeverity: 'warning',
networkIn: false,
label: 'ignored',
});
expect(result).toEqual({
cpu: 80,
memory: 85,
networkIn: 0,
});
});
it('getTriggerValue handles multiple input shapes', () => {
expect(getTriggerValue(75)).toBe(75);
expect(getTriggerValue({ trigger: 90, clear: 80 })).toBe(90);
expect(getTriggerValue(true)).toBe(0);
expect(getTriggerValue(undefined)).toBe(0);
});
});