import { describe, it, expect, beforeEach, vi } from 'vitest' import { createTableDownloadConfig } from './download' import type { TableColumn, TableWidgetData } from './types' const columns: TableColumn[] = [ { id: 'name', label: 'Name' }, { id: 'score', label: 'Score' }, ] const data: TableWidgetData = [ { id: 1, name: 'Alpha', score: 10 }, { id: 2, name: 'Beta', score: 20 }, ] 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('createTableDownloadConfig', () => { it('CSV-only by default', () => { expect( createTableDownloadConfig({ filename: 't', getData: () => data, columns, }).map((i) => i.id), ).toEqual(['csv']) }) it('prepends PNG when getCaptureEl is provided', () => { const items = createTableDownloadConfig({ filename: 't', getData: () => data, columns, getCaptureEl: () => document.createElement('div'), }) expect(items.map((i) => i.id)).toEqual(['png', 'csv']) }) it('CSV resolve uses tableDataToCsv with the supplied columns', async () => { const items = createTableDownloadConfig({ filename: 't', getData: () => data, columns, }) const handle = await items.find((i) => i.id === 'csv')!.resolve() expect(handle.filename).toBe('t.csv') expect(csvText).toBe('Name,Score\nAlpha,10\nBeta,20') }) it('CSV guards formula-injection cells end-to-end', async () => { const items = createTableDownloadConfig({ filename: 't', getData: () => [{ id: 1, name: '=HYPERLINK("x")', score: 1 }], columns, }) await items.find((i) => i.id === 'csv')!.resolve() expect(csvText).toBe('Name,Score\n"\'=HYPERLINK(""x"")",1') }) it('CSV calls getData() at click time (not at config creation)', async () => { let snapshot: TableWidgetData = data const items = createTableDownloadConfig({ filename: 't', getData: () => snapshot, columns, }) snapshot = [{ id: 9, name: 'Gamma', score: 99 }] await items.find((i) => i.id === 'csv')!.resolve() expect(csvText).toBe('Name,Score\nGamma,99') }) })