Charts.utils.test.ts170 lines · main
1import { renderHook } from '@testing-library/react'
2import { describe, expect, it, test } from 'vitest'
3
4import {
5 compactNumberFormatter,
6 formatPercentage,
7 isFloat,
8 numberFormatter,
9 precisionFormatter,
10 useStacked,
11} from '@/components/ui/Charts/Charts.utils'
12
13test('isFloat', () => {
14 expect(isFloat(123)).toBe(false)
15 expect(isFloat(123.123)).toBe(true)
16})
17
18describe('numberFormatter', () => {
19 it('should format integers without decimals', () => {
20 expect(numberFormatter(123)).toBe('123')
21 expect(numberFormatter(1000)).toBe('1,000')
22 })
23
24 it('should format floats with default precision', () => {
25 expect(numberFormatter(123.123)).toBe('123.12')
26 expect(numberFormatter(123.456)).toBe('123.45')
27 expect(numberFormatter(123.999)).toBe('123.99')
28 expect(numberFormatter(123456.78)).toBe('123,456.78')
29 })
30
31 it('should show "<0.01" for small positive floats', () => {
32 expect(numberFormatter(0.00123)).toBe('<0.01')
33 expect(numberFormatter(0.005)).toBe('<0.01')
34 })
35
36 it('should show ">-0.01" for small negative floats', () => {
37 expect(numberFormatter(-0.00123)).toBe('>-0.01')
38 expect(numberFormatter(-0.005)).toBe('>-0.01')
39 })
40
41 it('should respect custom precision', () => {
42 expect(numberFormatter(0.0001, 3)).toBe('<0.001')
43 expect(numberFormatter(123.456789, 4)).toBe('123.4567')
44 })
45})
46
47describe('precisionFormatter', () => {
48 it('should format regular numbers with precision', () => {
49 expect(precisionFormatter(123, 1)).toBe('123.0')
50 expect(precisionFormatter(123, 2)).toBe('123.00')
51 expect(precisionFormatter(123.123, 2)).toBe('123.12')
52 expect(precisionFormatter(123.999, 2)).toBe('123.99')
53 expect(precisionFormatter(123.12345, 4)).toBe('123.1234')
54 expect(precisionFormatter(123456, 2)).toBe('123,456.00')
55 expect(precisionFormatter(123456.78, 2)).toBe('123,456.78')
56 })
57
58 it('should show "<0.01" for small positive numbers below threshold', () => {
59 expect(precisionFormatter(0.00123, 2)).toBe('<0.01')
60 expect(precisionFormatter(0.005, 2)).toBe('<0.01')
61 expect(precisionFormatter(0.009, 2)).toBe('<0.01')
62 })
63
64 it('should show ">-0.01" for small negative numbers below threshold', () => {
65 expect(precisionFormatter(-0.00123, 2)).toBe('>-0.01')
66 expect(precisionFormatter(-0.005, 2)).toBe('>-0.01')
67 expect(precisionFormatter(-0.009, 2)).toBe('>-0.01')
68 })
69
70 it('should format numbers at or above threshold normally', () => {
71 expect(precisionFormatter(0.01, 2)).toBe('0.01')
72 expect(precisionFormatter(0.02, 2)).toBe('0.02')
73 expect(precisionFormatter(-0.01, 2)).toBe('-0.01')
74 expect(precisionFormatter(-0.02, 2)).toBe('-0.02')
75 })
76
77 it('should handle different precision values', () => {
78 expect(precisionFormatter(0.0001, 3)).toBe('<0.001')
79 expect(precisionFormatter(0.001, 3)).toBe('0.001')
80 expect(precisionFormatter(-0.0001, 3)).toBe('>-0.001')
81 })
82
83 it('should handle precision 0', () => {
84 expect(precisionFormatter(123.456, 0)).toBe('123')
85 expect(precisionFormatter(0.5, 0)).toBe('1')
86 })
87
88 it('should format exactly zero normally', () => {
89 expect(precisionFormatter(0, 2)).toBe('0.00')
90 })
91})
92
93describe('formatPercentage', () => {
94 it('should format 100 without decimals', () => {
95 expect(formatPercentage(100, 2)).toBe('100%')
96 expect(formatPercentage(100, 0)).toBe('100%')
97 })
98
99 it('should keep decimals for non-100 values', () => {
100 expect(formatPercentage(99.99, 2)).toBe('99.99%')
101 expect(formatPercentage(0.5, 2)).toBe('0.50%')
102 })
103
104 it('should use numberFormatter for integers below 100', () => {
105 expect(formatPercentage(50, 2)).toBe('50%')
106 expect(formatPercentage(1, 2)).toBe('1%')
107 })
108})
109
110describe('compactNumberFormatter', () => {
111 it('returns the number as-is below 1000', () => {
112 expect(compactNumberFormatter(0)).toBe('0')
113 expect(compactNumberFormatter(1)).toBe('1')
114 expect(compactNumberFormatter(999)).toBe('999')
115 })
116
117 it('formats thousands with K suffix', () => {
118 expect(compactNumberFormatter(1000)).toBe('1K')
119 expect(compactNumberFormatter(1500)).toBe('1.5K')
120 expect(compactNumberFormatter(64000)).toBe('64K')
121 expect(compactNumberFormatter(999999)).toBe('1M') // rounds up
122 })
123
124 it('formats millions with M suffix', () => {
125 expect(compactNumberFormatter(1_000_000)).toBe('1M')
126 expect(compactNumberFormatter(1_500_000)).toBe('1.5M')
127 expect(compactNumberFormatter(2_500_000)).toBe('2.5M')
128 })
129
130 it('formats billions with B suffix', () => {
131 expect(compactNumberFormatter(1_000_000_000)).toBe('1B')
132 expect(compactNumberFormatter(2_500_000_000)).toBe('2.5B')
133 })
134
135 it('handles negative numbers', () => {
136 expect(compactNumberFormatter(-1000)).toBe('-1K')
137 expect(compactNumberFormatter(-1_500_000)).toBe('-1.5M')
138 })
139})
140
141test('useStacked', () => {
142 const { result } = renderHook(() =>
143 useStacked({
144 data: [
145 { label: 'a', x: 1, y: 2 },
146 { label: 'b', x: 1, y: 3 },
147 ] as unknown as Array<Record<string, number>>,
148 xAxisKey: 'x',
149 yAxisKey: 'y',
150 stackKey: 'label',
151 variant: 'percentages',
152 })
153 )
154 expect(result.current).toMatchObject({
155 stackedData: [
156 {
157 a: 2,
158 b: 3,
159 x: 1,
160 },
161 ],
162 percentagesStackedData: [
163 {
164 a: 2 / 5,
165 b: 3 / 5,
166 x: 1,
167 },
168 ],
169 })
170})