import { describe, it, expect, beforeEach, vi } from 'vitest' import { createTimeseriesDownloadConfig } from './download' import type { TimeseriesWidgetData } from './types' let csvText = '' beforeEach(() => { csvText = '' vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:mock') vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => undefined) const RealBlob = global.Blob vi.stubGlobal( 'Blob', class extends RealBlob { constructor(parts: BlobPart[], opts?: BlobPropertyBag) { csvText = typeof parts[0] === 'string' ? parts[0] : '' super(parts, opts) } }, ) }) describe('createTimeseriesDownloadConfig', () => { it('CSV-only by default', () => { expect( createTimeseriesDownloadConfig({ filename: 't', getData: () => [[{ name: '2024-01-01', value: 1 }]], }).map((i) => i.id), ).toEqual(['csv']) }) it('prepends PNG when getCaptureEl is provided', () => { const items = createTimeseriesDownloadConfig({ filename: 't', getData: () => [], getCaptureEl: () => document.createElement('div'), }) expect(items.map((i) => i.id)).toEqual(['png', 'csv']) }) it('emits ISO strings for Date keys and aligns rows across series', async () => { const d1 = new Date('2024-01-01T00:00:00.000Z') const d2 = new Date('2024-01-02T00:00:00.000Z') const data: TimeseriesWidgetData = [ [ { name: d1, value: 1 }, { name: d2, value: 2 }, ], [{ name: d2, value: 20 }], ] const items = createTimeseriesDownloadConfig({ filename: 't', getData: () => data, }) const handle = await items.find((i) => i.id === 'csv')!.resolve() expect(handle.filename).toBe('t.csv') expect(csvText).toBe( 'time,series_1,series_2\n' + '2024-01-01T00:00:00.000Z,1,\n' + '2024-01-02T00:00:00.000Z,2,20', ) }) it('emits ISO strings for numeric ms-since-epoch keys', async () => { const ts = Date.UTC(2024, 0, 1) const data: TimeseriesWidgetData = [[{ name: ts, value: 7 }]] const items = createTimeseriesDownloadConfig({ filename: 't', getData: () => data, }) await items.find((i) => i.id === 'csv')!.resolve() expect(csvText).toContain('2024-01-01T00:00:00.000Z,7') }) it('passes string time keys through verbatim', async () => { const data: TimeseriesWidgetData = [[{ name: '2024-Q1', value: 1 }]] const items = createTimeseriesDownloadConfig({ filename: 't', getData: () => data, }) await items.find((i) => i.id === 'csv')!.resolve() expect(csvText).toContain('2024-Q1,1') }) it('uses supplied seriesNames in the header', async () => { const items = createTimeseriesDownloadConfig({ filename: 't', getData: () => [[{ name: '2024', value: 1 }]], seriesNames: ['revenue'], }) await items.find((i) => i.id === 'csv')!.resolve() expect(csvText.split('\n')[0]).toBe('time,revenue') }) })