Charts.utils.test.ts170 lines · main
| 1 | import { renderHook } from '@testing-library/react' |
| 2 | import { describe, expect, it, test } from 'vitest' |
| 3 | |
| 4 | import { |
| 5 | compactNumberFormatter, |
| 6 | formatPercentage, |
| 7 | isFloat, |
| 8 | numberFormatter, |
| 9 | precisionFormatter, |
| 10 | useStacked, |
| 11 | } from '@/components/ui/Charts/Charts.utils' |
| 12 | |
| 13 | test('isFloat', () => { |
| 14 | expect(isFloat(123)).toBe(false) |
| 15 | expect(isFloat(123.123)).toBe(true) |
| 16 | }) |
| 17 | |
| 18 | describe('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 | |
| 47 | describe('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 | |
| 93 | describe('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 | |
| 110 | describe('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 | |
| 141 | test('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 | }) |