diff --git a/jest.config.ts b/jest.config.ts index 73738651..3a9741cf 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -4,4 +4,13 @@ export default { transform: { '^.+\\.(ts|tsx)$': 'ts-jest', }, + moduleNameMapper: { + '^assets/(.*)$': '/src/assets/$1', + '^components/(.*)$': '/src/components/$1', + '^lib/(.*)$': '/src/lib/$1', + '^pages/(.*)$': '/src/pages/$1', + '^queries/(.*)$': '/src/queries/$1', + '^store/(.*)$': '/src/store/$1', + '^styles/(.*)$': '/src/styles/$1', + }, }; diff --git a/src/lib/__tests__/charts.test.ts b/src/lib/__tests__/charts.test.ts new file mode 100644 index 00000000..cd9e8651 --- /dev/null +++ b/src/lib/__tests__/charts.test.ts @@ -0,0 +1,80 @@ +import { renderNumberLabels, renderDateLabels } from 'lib/charts'; +import { formatDate } from 'lib/date'; + +// test for renderNumberLabels + +describe('renderNumberLabels', () => { + test.each([ + ['1000000', '1.0m'], + ['2500000', '2.5m'], + ])("formats numbers ≥ 1 million as 'Xm' (%s → %s)", (input, expected) => { + expect(renderNumberLabels(input)).toBe(expected); + }); + + test.each([['150000', '150k']])("formats numbers ≥ 100K as 'Xk' (%s → %s)", (input, expected) => { + expect(renderNumberLabels(input)).toBe(expected); + }); + + test.each([['12500', '12.5k']])( + "formats numbers ≥ 10K as 'X.Xk' (%s → %s)", + (input, expected) => { + expect(renderNumberLabels(input)).toBe(expected); + }, + ); + + test.each([['1500', '1.50k']])("formats numbers ≥ 1K as 'X.XXk' (%s → %s)", (input, expected) => { + expect(renderNumberLabels(input)).toBe(expected); + }); + + test.each([['999', '999']])( + 'calls formatNumber for values < 1000 (%s → %s)', + (input, expected) => { + expect(renderNumberLabels(input)).toBe(expected); + }, + ); + + test.each([ + ['0', '0'], + ['-5000', '-5000'], + ])('handles edge cases correctly (%s → %s)', (input, expected) => { + expect(renderNumberLabels(input)).toBe(expected); + }); +}); + +describe('renderDateLabels', () => { + const mockValues = [{ value: '2024-03-23T10:00:00Z' }, { value: '2024-03-24T15:30:00Z' }]; + + beforeEach(() => { + jest.spyOn(require('lib/date'), 'formatDate'); + }); + + afterEach(() => { + jest.restoreAllMocks(); // Reset spy to prevent interference + }); + + test.each([ + ['minute', 'h:mm', 'en-US'], + ['hour', 'p', 'en-US'], + ['day', 'MMM d', 'en-US'], + ['month', 'MMM', 'en-US'], + ['year', 'yyyy', 'en-US'], + ])('formats date correctly for unit: %s', (unit, expectedFormat, locale) => { + const formatLabel = renderDateLabels(unit, locale); + const formatted = formatLabel('label', 0, mockValues); + + expect(formatDate).toHaveBeenCalledWith(new Date(mockValues[0].value), expectedFormat, locale); + expect(formatted).toBe(formatDate(new Date(mockValues[0].value), expectedFormat, locale)); + }); + + test('returns label for unknown unit', () => { + const formatLabel = renderDateLabels('unknown', 'en-US'); + expect(formatLabel('original-label', 0, mockValues)).toBe('original-label'); + }); + + test('throws error for invalid date input', () => { + const invalidValues = [{ value: 'invalid-date' }]; + const formatLabel = renderDateLabels('day', 'en-US'); + + expect(() => formatLabel('label', 0, invalidValues)).toThrow(); + }); +}); diff --git a/src/lib/charts.ts b/src/lib/charts.ts index d6917c83..957d4962 100644 --- a/src/lib/charts.ts +++ b/src/lib/charts.ts @@ -19,7 +19,7 @@ export function renderDateLabels(unit: string, locale: string) { case 'month': return formatDate(d, 'MMM', locale); case 'year': - return formatDate(d, 'YYY', locale); + return formatDate(d, 'yyyy', locale); default: return label; }