test: add comprehensive tests for export utilities

Add tests for exportToCSV, exportToJSON, and formatDateForExport
covering file download, date formatting, and edge cases.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
soufiane 2025-12-01 22:42:05 +01:00
parent 43a2dadd0e
commit c03e6f9d12

View File

@ -0,0 +1,227 @@
/**
* Tests for the export utility functions
* @jest-environment jsdom
*/
import { exportToCSV, exportToJSON, formatDateForExport } from '@/utils/export';
describe('Export Utilities', () => {
// Mock DOM methods for file download
let mockClick: jest.Mock;
let mockLink: Partial<HTMLAnchorElement>;
const originalCreateObjectURL = URL.createObjectURL;
const originalRevokeObjectURL = URL.revokeObjectURL;
beforeAll(() => {
// Mock URL methods globally
URL.createObjectURL = jest.fn(() => 'blob:test-url');
URL.revokeObjectURL = jest.fn();
});
afterAll(() => {
URL.createObjectURL = originalCreateObjectURL;
URL.revokeObjectURL = originalRevokeObjectURL;
});
beforeEach(() => {
mockClick = jest.fn();
mockLink = {
href: '',
download: '',
style: { display: '' } as CSSStyleDeclaration,
click: mockClick,
};
jest.spyOn(document, 'createElement').mockReturnValue(mockLink as HTMLAnchorElement);
jest.spyOn(document.body, 'appendChild').mockImplementation(() => mockLink as Node);
jest.spyOn(document.body, 'removeChild').mockImplementation(() => mockLink as Node);
});
afterEach(() => {
jest.restoreAllMocks();
});
describe('exportToCSV', () => {
it('should create and download a CSV file', () => {
const data = [
['Header1', 'Header2'],
['Value1', 'Value2'],
];
exportToCSV(data, 'test-file');
expect(document.createElement).toHaveBeenCalledWith('a');
expect(URL.createObjectURL).toHaveBeenCalled();
expect(document.body.appendChild).toHaveBeenCalled();
expect(mockClick).toHaveBeenCalled();
expect(document.body.removeChild).toHaveBeenCalled();
expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:test-url');
});
it('should include date in filename by default', () => {
const data = [['test']];
const today = new Date().toISOString().split('T')[0];
exportToCSV(data, 'test-file');
expect(mockLink.download).toContain('test-file');
expect(mockLink.download).toContain(today);
expect(mockLink.download).toContain('.csv');
});
it('should exclude date when includeDate is false', () => {
const data = [['test']];
exportToCSV(data, 'test-file', { includeDate: false });
expect(mockLink.download).toBe('test-file.csv');
});
it('should use custom separator', () => {
const data = [['A', 'B'], ['C', 'D']];
// We can't easily verify the content of the blob, but we can verify the function runs
expect(() => exportToCSV(data, 'test', { separator: ';' })).not.toThrow();
expect(mockClick).toHaveBeenCalled();
});
it('should handle null and undefined values', () => {
const data = [[null, undefined, 'value']];
expect(() => exportToCSV(data, 'test')).not.toThrow();
expect(mockClick).toHaveBeenCalled();
});
it('should escape values containing separator', () => {
const data = [['value,with,commas', 'normal']];
expect(() => exportToCSV(data, 'test')).not.toThrow();
expect(mockClick).toHaveBeenCalled();
});
it('should escape values containing quotes', () => {
const data = [['value"with"quotes', 'normal']];
expect(() => exportToCSV(data, 'test')).not.toThrow();
expect(mockClick).toHaveBeenCalled();
});
it('should escape values containing newlines', () => {
const data = [['value\nwith\nnewlines', 'normal']];
expect(() => exportToCSV(data, 'test')).not.toThrow();
expect(mockClick).toHaveBeenCalled();
});
it('should handle boolean values', () => {
const data = [[true, false]];
expect(() => exportToCSV(data, 'test')).not.toThrow();
expect(mockClick).toHaveBeenCalled();
});
it('should handle number values', () => {
const data = [[123, 456.78]];
expect(() => exportToCSV(data, 'test')).not.toThrow();
expect(mockClick).toHaveBeenCalled();
});
it('should set link style to hidden', () => {
const data = [['test']];
exportToCSV(data, 'test');
expect(mockLink.style?.display).toBe('none');
});
});
describe('exportToJSON', () => {
it('should create and download a JSON file', () => {
const data = { key: 'value', nested: { a: 1 } };
exportToJSON(data, 'test-file');
expect(document.createElement).toHaveBeenCalledWith('a');
expect(URL.createObjectURL).toHaveBeenCalled();
expect(document.body.appendChild).toHaveBeenCalled();
expect(mockClick).toHaveBeenCalled();
expect(document.body.removeChild).toHaveBeenCalled();
expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:test-url');
});
it('should include date in filename', () => {
const data = { test: true };
const today = new Date().toISOString().split('T')[0];
exportToJSON(data, 'test-file');
expect(mockLink.download).toContain('test-file');
expect(mockLink.download).toContain(today);
expect(mockLink.download).toContain('.json');
});
it('should handle arrays', () => {
const data = [1, 2, 3, { a: 'b' }];
expect(() => exportToJSON(data, 'test')).not.toThrow();
expect(mockClick).toHaveBeenCalled();
});
it('should handle nested objects', () => {
const data = {
level1: {
level2: {
level3: 'deep',
},
},
};
expect(() => exportToJSON(data, 'test')).not.toThrow();
expect(mockClick).toHaveBeenCalled();
});
it('should set link style to hidden', () => {
const data = { test: true };
exportToJSON(data, 'test');
expect(mockLink.style?.display).toBe('none');
});
});
describe('formatDateForExport', () => {
it('should format date string correctly', () => {
const result = formatDateForExport('2024-01-15T10:30:00Z');
// French format: DD/MM/YYYY HH:MM
expect(result).toMatch(/\d{2}\/\d{2}\/\d{4}/);
});
it('should format Date object correctly', () => {
const date = new Date('2024-01-15T10:30:00Z');
const result = formatDateForExport(date);
expect(result).toMatch(/\d{2}\/\d{2}\/\d{4}/);
});
it('should return empty string for null', () => {
expect(formatDateForExport(null)).toBe('');
});
it('should return empty string for undefined', () => {
expect(formatDateForExport(undefined)).toBe('');
});
it('should return empty string for empty string', () => {
expect(formatDateForExport('')).toBe('');
});
it('should include time in the format', () => {
const result = formatDateForExport('2024-01-15T10:30:00Z');
// Should contain time component
expect(result).toMatch(/\d{2}:\d{2}/);
});
});
});