diff --git a/apps/studio/components/ui/Charts/Charts.utils.tsx b/apps/studio/components/ui/Charts/Charts.utils.tsx index 31463e0adc6..ae0a84b78f7 100644 --- a/apps/studio/components/ui/Charts/Charts.utils.tsx +++ b/apps/studio/components/ui/Charts/Charts.utils.tsx @@ -31,11 +31,23 @@ export const isFloat = (num: number) => String(num).includes('.') * @example * precisionFormatter(123, 2) // "123.00" * precisionFormatter(123.123, 2) // "123.12" + * precisionFormatter(0.00123, 2) // "<0.01" + * precisionFormatter(-0.00123, 2) // ">-0.01" */ export const precisionFormatter = (num: number, precision: number): string => { if (precision === 0) { return String(Math.round(num)) } + + // Handle small numbers that would display as 0.00 + const threshold = 1 / Math.pow(10, precision) + if (num > 0 && num < threshold) { + return `<${threshold.toFixed(precision)}` + } + if (num < 0 && num > -threshold) { + return `>-${threshold.toFixed(precision)}` + } + if (isFloat(num)) { const [head, tail] = String(num).split('.') return Number(head).toLocaleString() + '.' + tail.slice(0, precision) diff --git a/apps/studio/tests/components/ui/Charts/Charts.utils.test.ts b/apps/studio/tests/components/ui/Charts/Charts.utils.test.ts index f0f246586bb..c4b9c0344c5 100644 --- a/apps/studio/tests/components/ui/Charts/Charts.utils.test.ts +++ b/apps/studio/tests/components/ui/Charts/Charts.utils.test.ts @@ -5,23 +5,86 @@ import { precisionFormatter, useStacked, } from 'components/ui/Charts/Charts.utils' -import { test, expect } from 'vitest' +import { describe, expect, it, test } from 'vitest' test('isFloat', () => { expect(isFloat(123)).toBe(false) expect(isFloat(123.123)).toBe(true) }) -test('numberFormatter', () => { - expect(numberFormatter(123)).toBe('123') - expect(numberFormatter(123.123)).toBe('123.12') - expect(numberFormatter(123456.78)).toBe('123,456.78') + +describe('numberFormatter', () => { + it('should format integers without decimals', () => { + expect(numberFormatter(123)).toBe('123') + expect(numberFormatter(1000)).toBe('1,000') + }) + + it('should format floats with default precision', () => { + expect(numberFormatter(123.123)).toBe('123.12') + expect(numberFormatter(123.456)).toBe('123.45') + expect(numberFormatter(123.999)).toBe('123.99') + expect(numberFormatter(123456.78)).toBe('123,456.78') + }) + + it('should show "<0.01" for small positive floats', () => { + expect(numberFormatter(0.00123)).toBe('<0.01') + expect(numberFormatter(0.005)).toBe('<0.01') + }) + + it('should show ">-0.01" for small negative floats', () => { + expect(numberFormatter(-0.00123)).toBe('>-0.01') + expect(numberFormatter(-0.005)).toBe('>-0.01') + }) + + it('should respect custom precision', () => { + expect(numberFormatter(0.0001, 3)).toBe('<0.001') + expect(numberFormatter(123.456789, 4)).toBe('123.4567') + }) }) -test('precisionFormatter', () => { - expect(precisionFormatter(123, 1)).toBe('123.0') - expect(precisionFormatter(123.12345, 4)).toBe('123.1234') - expect(precisionFormatter(123456, 2)).toBe('123,456.00') - expect(precisionFormatter(123456.78, 2)).toBe('123,456.78') +describe('precisionFormatter', () => { + it('should format regular numbers with precision', () => { + expect(precisionFormatter(123, 1)).toBe('123.0') + expect(precisionFormatter(123, 2)).toBe('123.00') + expect(precisionFormatter(123.123, 2)).toBe('123.12') + expect(precisionFormatter(123.999, 2)).toBe('123.99') + expect(precisionFormatter(123.12345, 4)).toBe('123.1234') + expect(precisionFormatter(123456, 2)).toBe('123,456.00') + expect(precisionFormatter(123456.78, 2)).toBe('123,456.78') + }) + + it('should show "<0.01" for small positive numbers below threshold', () => { + expect(precisionFormatter(0.00123, 2)).toBe('<0.01') + expect(precisionFormatter(0.005, 2)).toBe('<0.01') + expect(precisionFormatter(0.009, 2)).toBe('<0.01') + }) + + it('should show ">-0.01" for small negative numbers below threshold', () => { + expect(precisionFormatter(-0.00123, 2)).toBe('>-0.01') + expect(precisionFormatter(-0.005, 2)).toBe('>-0.01') + expect(precisionFormatter(-0.009, 2)).toBe('>-0.01') + }) + + it('should format numbers at or above threshold normally', () => { + expect(precisionFormatter(0.01, 2)).toBe('0.01') + expect(precisionFormatter(0.02, 2)).toBe('0.02') + expect(precisionFormatter(-0.01, 2)).toBe('-0.01') + expect(precisionFormatter(-0.02, 2)).toBe('-0.02') + }) + + it('should handle different precision values', () => { + expect(precisionFormatter(0.0001, 3)).toBe('<0.001') + expect(precisionFormatter(0.001, 3)).toBe('0.001') + expect(precisionFormatter(-0.0001, 3)).toBe('>-0.001') + }) + + it('should handle precision 0', () => { + expect(precisionFormatter(123.456, 0)).toBe('123') + expect(precisionFormatter(0.5, 0)).toBe('1') + }) + + it('should format exactly zero normally', () => { + expect(precisionFormatter(0, 2)).toBe('0.00') + }) }) test('useStacked', () => { @@ -30,7 +93,7 @@ test('useStacked', () => { data: [ { label: 'a', x: 1, y: 2 }, { label: 'b', x: 1, y: 3 }, - ] as any, + ] as unknown as Array>, xAxisKey: 'x', yAxisKey: 'y', stackKey: 'label',