tests/chart-breakdown.unit.test.ts
Rama main · réplica de lectura del repositorio original.
import type { NumericSeriesByApp } from '../src/services/usageSeries'
import { describe, expect, it } from 'vitest'
import { limitChartBreakdown, MAX_CHART_BREAKDOWN_SERIES } from '../src/utils/chartBreakdown'
describe('chart breakdown rendering budget', () => {
it.concurrent('keeps a small active breakdown in its existing order without copying its arrays', () => {
const source = { 'com.example.first': [1, 2], 'com.example.second': [4, 5] }
const result = limitChartBreakdown(source)
expect(result.map(series => series.id)).toEqual(Object.keys(source))
expect(result[0].data).toBe(source['com.example.first'])
expect(result[1].data).toBe(source['com.example.second'])
})
it.concurrent('does not spend the rendering budget on inactive or missing-only series', () => {
expect(limitChartBreakdown({
'com.example.empty': [],
'com.example.zero': [0, 0],
'com.example.missing': [undefined, undefined],
'com.example.active': [undefined, 1],
})).toEqual([{ id: 'com.example.active', data: [undefined, 1] }])
})
it.concurrent('groups the remainder without mutating inputs or fabricating an app identity', () => {
const source = Object.fromEntries(Array.from({ length: 1000 }, (_, index) => [
`com.example.app${index}`,
[index + 1, (index + 1) * 2, undefined],
]))
const snapshot = structuredClone(source)
const result = limitChartBreakdown(source)
expect(result).toHaveLength(MAX_CHART_BREAKDOWN_SERIES)
expect(result[0].id).toBe('com.example.app999')
expect(result.at(-1)?.id).toBeUndefined()
expect(result.at(-1)?.data[2]).toBeUndefined()
expect(source).toEqual(snapshot)
for (let dayIndex = 0; dayIndex < 2; dayIndex++) {
const sum = result.reduce((total, series) => total + (series.data[dayIndex] ?? 0), 0)
expect(sum).toBe(500_500 * (dayIndex + 1))
}
})
it.concurrent('preserves signed totals, differing lengths, and zero days when grouping', () => {
const source: NumericSeriesByApp = Object.fromEntries(Array.from({ length: 9 }, (_, index) => [
`com.example.top${index}`,
[100, 100],
]))
source['com.example.corrections'] = [-5, 5, undefined, 0]
source['com.example.later'] = [undefined, -1, 2]
const result = limitChartBreakdown(source)
expect(result.at(-1)).toEqual({ data: [-5, 4, 2, 0] })
expect(result.reduce((total, series) => total + (series.data[0] ?? 0), 0)).toBe(895)
})
it.concurrent('keeps tied series deterministic at the rendering boundary', () => {
const source = Object.fromEntries(Array.from({ length: 11 }, (_, index) => [`com.example.app${index}`, [1]]))
const result = limitChartBreakdown(source)
expect(result.slice(0, -1).map(series => series.id)).toEqual(Object.keys(source).slice(0, 9))
expect(result.at(-1)).toEqual({ data: [2] })
})
})