Files
gridpilot.gg/apps/website/lib/builders/view-data/HealthViewDataBuilder.test.ts
Marc Mintel 1f4f837282
Some checks failed
Contract Testing / contract-tests (pull_request) Failing after 5m58s
Contract Testing / contract-snapshot (pull_request) Has been skipped
view data tests
2026-01-22 18:06:46 +01:00

554 lines
17 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { HealthViewDataBuilder, HealthDTO } from './HealthViewDataBuilder';
describe('HealthViewDataBuilder', () => {
describe('happy paths', () => {
it('should transform HealthDTO to HealthViewData correctly', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: 99.95,
responseTime: 150,
errorRate: 0.05,
lastCheck: new Date().toISOString(),
checksPassed: 995,
checksFailed: 5,
components: [
{
name: 'Database',
status: 'ok',
lastCheck: new Date().toISOString(),
responseTime: 50,
errorRate: 0.01,
},
{
name: 'API',
status: 'ok',
lastCheck: new Date().toISOString(),
responseTime: 100,
errorRate: 0.02,
},
],
alerts: [
{
id: 'alert-1',
type: 'info',
title: 'System Update',
message: 'System updated successfully',
timestamp: new Date().toISOString(),
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.overallStatus.status).toBe('ok');
expect(result.overallStatus.statusLabel).toBe('Healthy');
expect(result.overallStatus.statusColor).toBe('#10b981');
expect(result.overallStatus.statusIcon).toBe('✓');
expect(result.metrics.uptime).toBe('99.95%');
expect(result.metrics.responseTime).toBe('150ms');
expect(result.metrics.errorRate).toBe('0.05%');
expect(result.metrics.checksPassed).toBe(995);
expect(result.metrics.checksFailed).toBe(5);
expect(result.metrics.totalChecks).toBe(1000);
expect(result.metrics.successRate).toBe('99.5%');
expect(result.components).toHaveLength(2);
expect(result.components[0].name).toBe('Database');
expect(result.components[0].status).toBe('ok');
expect(result.components[0].statusLabel).toBe('Healthy');
expect(result.alerts).toHaveLength(1);
expect(result.alerts[0].id).toBe('alert-1');
expect(result.alerts[0].type).toBe('info');
expect(result.hasAlerts).toBe(true);
expect(result.hasDegradedComponents).toBe(false);
expect(result.hasErrorComponents).toBe(false);
});
it('should handle missing optional fields gracefully', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.overallStatus.status).toBe('ok');
expect(result.metrics.uptime).toBe('N/A');
expect(result.metrics.responseTime).toBe('N/A');
expect(result.metrics.errorRate).toBe('N/A');
expect(result.metrics.checksPassed).toBe(0);
expect(result.metrics.checksFailed).toBe(0);
expect(result.metrics.totalChecks).toBe(0);
expect(result.metrics.successRate).toBe('N/A');
expect(result.components).toEqual([]);
expect(result.alerts).toEqual([]);
expect(result.hasAlerts).toBe(false);
expect(result.hasDegradedComponents).toBe(false);
expect(result.hasErrorComponents).toBe(false);
});
it('should handle degraded status correctly', () => {
const healthDTO: HealthDTO = {
status: 'degraded',
timestamp: new Date().toISOString(),
uptime: 95.5,
responseTime: 500,
errorRate: 4.5,
components: [
{
name: 'Database',
status: 'degraded',
lastCheck: new Date().toISOString(),
responseTime: 200,
errorRate: 2.0,
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.overallStatus.status).toBe('degraded');
expect(result.overallStatus.statusLabel).toBe('Degraded');
expect(result.overallStatus.statusColor).toBe('#f59e0b');
expect(result.overallStatus.statusIcon).toBe('⚠');
expect(result.metrics.uptime).toBe('95.50%');
expect(result.metrics.responseTime).toBe('500ms');
expect(result.metrics.errorRate).toBe('4.50%');
expect(result.hasDegradedComponents).toBe(true);
});
it('should handle error status correctly', () => {
const healthDTO: HealthDTO = {
status: 'error',
timestamp: new Date().toISOString(),
uptime: 85.2,
responseTime: 2000,
errorRate: 14.8,
components: [
{
name: 'Database',
status: 'error',
lastCheck: new Date().toISOString(),
responseTime: 1500,
errorRate: 10.0,
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.overallStatus.status).toBe('error');
expect(result.overallStatus.statusLabel).toBe('Error');
expect(result.overallStatus.statusColor).toBe('#ef4444');
expect(result.overallStatus.statusIcon).toBe('✕');
expect(result.metrics.uptime).toBe('85.20%');
expect(result.metrics.responseTime).toBe('2.00s');
expect(result.metrics.errorRate).toBe('14.80%');
expect(result.hasErrorComponents).toBe(true);
});
it('should handle multiple components with mixed statuses', () => {
const healthDTO: HealthDTO = {
status: 'degraded',
timestamp: new Date().toISOString(),
components: [
{
name: 'Database',
status: 'ok',
lastCheck: new Date().toISOString(),
},
{
name: 'API',
status: 'degraded',
lastCheck: new Date().toISOString(),
},
{
name: 'Cache',
status: 'error',
lastCheck: new Date().toISOString(),
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.components).toHaveLength(3);
expect(result.hasDegradedComponents).toBe(true);
expect(result.hasErrorComponents).toBe(true);
expect(result.components[0].statusLabel).toBe('Healthy');
expect(result.components[1].statusLabel).toBe('Degraded');
expect(result.components[2].statusLabel).toBe('Error');
});
it('should handle multiple alerts with different severities', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
alerts: [
{
id: 'alert-1',
type: 'critical',
title: 'Critical Alert',
message: 'Critical issue detected',
timestamp: new Date().toISOString(),
},
{
id: 'alert-2',
type: 'warning',
title: 'Warning Alert',
message: 'Warning message',
timestamp: new Date().toISOString(),
},
{
id: 'alert-3',
type: 'info',
title: 'Info Alert',
message: 'Informational message',
timestamp: new Date().toISOString(),
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.alerts).toHaveLength(3);
expect(result.hasAlerts).toBe(true);
expect(result.alerts[0].severity).toBe('Critical');
expect(result.alerts[0].severityColor).toBe('#ef4444');
expect(result.alerts[1].severity).toBe('Warning');
expect(result.alerts[1].severityColor).toBe('#f59e0b');
expect(result.alerts[2].severity).toBe('Info');
expect(result.alerts[2].severityColor).toBe('#3b82f6');
});
});
describe('data transformation', () => {
it('should preserve all DTO fields in the output', () => {
const now = new Date();
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: now.toISOString(),
uptime: 99.99,
responseTime: 100,
errorRate: 0.01,
lastCheck: now.toISOString(),
checksPassed: 9999,
checksFailed: 1,
components: [
{
name: 'Test Component',
status: 'ok',
lastCheck: now.toISOString(),
responseTime: 50,
errorRate: 0.005,
},
],
alerts: [
{
id: 'test-alert',
type: 'info',
title: 'Test Alert',
message: 'Test message',
timestamp: now.toISOString(),
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.overallStatus.status).toBe(healthDTO.status);
expect(result.overallStatus.timestamp).toBe(healthDTO.timestamp);
expect(result.metrics.uptime).toBe('99.99%');
expect(result.metrics.responseTime).toBe('100ms');
expect(result.metrics.errorRate).toBe('0.01%');
expect(result.metrics.lastCheck).toBe(healthDTO.lastCheck);
expect(result.metrics.checksPassed).toBe(healthDTO.checksPassed);
expect(result.metrics.checksFailed).toBe(healthDTO.checksFailed);
expect(result.components[0].name).toBe(healthDTO.components![0].name);
expect(result.components[0].status).toBe(healthDTO.components![0].status);
expect(result.alerts[0].id).toBe(healthDTO.alerts![0].id);
expect(result.alerts[0].type).toBe(healthDTO.alerts![0].type);
});
it('should not modify the input DTO', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: 99.95,
responseTime: 150,
errorRate: 0.05,
components: [
{
name: 'Database',
status: 'ok',
lastCheck: new Date().toISOString(),
},
],
};
const originalDTO = JSON.parse(JSON.stringify(healthDTO));
HealthViewDataBuilder.build(healthDTO);
expect(healthDTO).toEqual(originalDTO);
});
it('should transform all numeric fields to formatted strings', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: 99.95,
responseTime: 150,
errorRate: 0.05,
checksPassed: 995,
checksFailed: 5,
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(typeof result.metrics.uptime).toBe('string');
expect(typeof result.metrics.responseTime).toBe('string');
expect(typeof result.metrics.errorRate).toBe('string');
expect(typeof result.metrics.successRate).toBe('string');
});
it('should handle large numbers correctly', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: 99.999,
responseTime: 5000,
errorRate: 0.001,
checksPassed: 999999,
checksFailed: 1,
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.metrics.uptime).toBe('100.00%');
expect(result.metrics.responseTime).toBe('5.00s');
expect(result.metrics.errorRate).toBe('0.00%');
expect(result.metrics.successRate).toBe('100.0%');
});
});
describe('edge cases', () => {
it('should handle null/undefined numeric fields', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: null as any,
responseTime: undefined,
errorRate: null as any,
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.metrics.uptime).toBe('N/A');
expect(result.metrics.responseTime).toBe('N/A');
expect(result.metrics.errorRate).toBe('N/A');
});
it('should handle negative numeric values', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: -1,
responseTime: -100,
errorRate: -0.5,
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.metrics.uptime).toBe('N/A');
expect(result.metrics.responseTime).toBe('N/A');
expect(result.metrics.errorRate).toBe('N/A');
});
it('should handle empty components and alerts arrays', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
components: [],
alerts: [],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.components).toEqual([]);
expect(result.alerts).toEqual([]);
expect(result.hasAlerts).toBe(false);
expect(result.hasDegradedComponents).toBe(false);
expect(result.hasErrorComponents).toBe(false);
});
it('should handle component with missing optional fields', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
components: [
{
name: 'Test Component',
status: 'ok',
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.components[0].lastCheck).toBeDefined();
expect(result.components[0].formattedLastCheck).toBeDefined();
expect(result.components[0].responseTime).toBe('N/A');
expect(result.components[0].errorRate).toBe('N/A');
});
it('should handle alert with missing optional fields', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
alerts: [
{
id: 'alert-1',
type: 'info',
title: 'Test Alert',
message: 'Test message',
timestamp: new Date().toISOString(),
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.alerts[0].id).toBe('alert-1');
expect(result.alerts[0].type).toBe('info');
expect(result.alerts[0].title).toBe('Test Alert');
expect(result.alerts[0].message).toBe('Test message');
expect(result.alerts[0].timestamp).toBeDefined();
expect(result.alerts[0].formattedTimestamp).toBeDefined();
expect(result.alerts[0].relativeTime).toBeDefined();
});
it('should handle unknown status', () => {
const healthDTO: HealthDTO = {
status: 'unknown',
timestamp: new Date().toISOString(),
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.overallStatus.status).toBe('unknown');
expect(result.overallStatus.statusLabel).toBe('Unknown');
expect(result.overallStatus.statusColor).toBe('#6b7280');
expect(result.overallStatus.statusIcon).toBe('?');
});
});
describe('derived fields', () => {
it('should correctly calculate hasAlerts', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
alerts: [
{
id: 'alert-1',
type: 'info',
title: 'Test',
message: 'Test message',
timestamp: new Date().toISOString(),
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.hasAlerts).toBe(true);
});
it('should correctly calculate hasDegradedComponents', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
components: [
{
name: 'Component 1',
status: 'ok',
lastCheck: new Date().toISOString(),
},
{
name: 'Component 2',
status: 'degraded',
lastCheck: new Date().toISOString(),
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.hasDegradedComponents).toBe(true);
});
it('should correctly calculate hasErrorComponents', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
components: [
{
name: 'Component 1',
status: 'ok',
lastCheck: new Date().toISOString(),
},
{
name: 'Component 2',
status: 'error',
lastCheck: new Date().toISOString(),
},
],
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.hasErrorComponents).toBe(true);
});
it('should correctly calculate totalChecks', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
checksPassed: 100,
checksFailed: 20,
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.metrics.totalChecks).toBe(120);
});
it('should correctly calculate successRate', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
checksPassed: 90,
checksFailed: 10,
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.metrics.successRate).toBe('90.0%');
});
it('should handle zero checks correctly', () => {
const healthDTO: HealthDTO = {
status: 'ok',
timestamp: new Date().toISOString(),
checksPassed: 0,
checksFailed: 0,
};
const result = HealthViewDataBuilder.build(healthDTO);
expect(result.metrics.totalChecks).toBe(0);
expect(result.metrics.successRate).toBe('N/A');
});
});
});