76 lines
1.9 KiB
TypeScript
76 lines
1.9 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { toAlignedSeries, type UptimeProbe } from './uptime-chart'
|
|
|
|
function probe(
|
|
overrides: Partial<UptimeProbe> & Pick<UptimeProbe, 'id'>,
|
|
): UptimeProbe {
|
|
return {
|
|
status: 'up',
|
|
ok: true,
|
|
latency_ms: 10,
|
|
checked_at: '2026-01-01T00:00:00.000Z',
|
|
provider: 'local',
|
|
...overrides,
|
|
}
|
|
}
|
|
|
|
describe('toAlignedSeries', () => {
|
|
it('puts mixed-source probes in one 60s bucket instead of a sawtooth series', () => {
|
|
const { points, keys } = toAlignedSeries([
|
|
probe({
|
|
id: 1,
|
|
provider: 'local',
|
|
latency_ms: 4,
|
|
checked_at: '2026-01-01T00:00:10.000Z',
|
|
}),
|
|
probe({
|
|
id: 2,
|
|
provider: 'cloudflare',
|
|
latency_ms: 284,
|
|
checked_at: '2026-01-01T00:00:12.000Z',
|
|
}),
|
|
probe({
|
|
id: 3,
|
|
provider: 'globalping',
|
|
latency_ms: 38,
|
|
checked_at: '2026-01-01T00:00:40.000Z',
|
|
}),
|
|
])
|
|
|
|
expect(points).toHaveLength(1)
|
|
expect(points[0]?.local).toBe(4)
|
|
expect(points[0]?.cloudflare).toBe(284)
|
|
expect(points[0]?.globalping).toBe(38)
|
|
expect(keys).toEqual(['local', 'cloudflare', 'globalping'])
|
|
})
|
|
|
|
it('does not plot down probes as latency 0', () => {
|
|
const { points } = toAlignedSeries([
|
|
probe({
|
|
id: 1,
|
|
status: 'down',
|
|
ok: false,
|
|
latency_ms: 12,
|
|
provider: 'local',
|
|
}),
|
|
])
|
|
|
|
expect(points).toHaveLength(1)
|
|
expect(points[0]?.local).toBeNull()
|
|
expect(points[0]?.localOk).toBe(false)
|
|
expect(points[0]?.ok).toBe(false)
|
|
})
|
|
|
|
it('splits probes that fall into adjacent minutes', () => {
|
|
const { points } = toAlignedSeries([
|
|
probe({ id: 1, latency_ms: 10, checked_at: '2026-01-01T00:00:50.000Z' }),
|
|
probe({ id: 2, latency_ms: 20, checked_at: '2026-01-01T00:01:10.000Z' }),
|
|
])
|
|
|
|
expect(points).toHaveLength(2)
|
|
expect(points[0]?.local).toBe(10)
|
|
expect(points[1]?.local).toBe(20)
|
|
})
|
|
})
|