import { describe, expect, it } from 'vitest'; import { genericProfile } from '../../src/profiles/generic/generic-profile'; import { importFile } from '../../src/importers/importer'; import { ImportError } from '../../src/shared/errors'; import genericFixture from '../../fixtures/generic/findings.synthetic.csv?raw'; const options = { profiles: [genericProfile] }; describe('file importer', () => { it('imports the persistent generic CSV fixture through the full pipeline', async () => { const file = new File([genericFixture], 'findings.synthetic.csv', { type: 'text/csv', lastModified: 1234 }); const imported = await importFile(file, options); expect(imported.profileId).toBe('generic'); expect(imported.scanTool).toBe('Tabular Data'); expect(imported.sheets[0].analysis.records).toHaveLength(2); expect(imported.sheets[0].analysis.records[0].title).toBe('Synthetic weak policy'); }); it('falls back to Windows-1252 when UTF-8 decoding fails', async () => { const prefix = new TextEncoder().encode('Title;Severity\nPr'); const suffix = new TextEncoder().encode('fung;High'); const bytes = new Uint8Array([...prefix, 0xfc, ...suffix]); const file = new File([bytes], 'windows-1252.csv', { type: 'text/csv' }); const imported = await importFile(file, options); expect(imported.sheets[0].rows[1][0]).toBe('Pr\u00fcfung'); }); it('rejects a file without any evaluable rows', async () => { const file = new File(['\r\n\r\n'], 'empty.csv', { type: 'text/csv' }); await expect(importFile(file, options)).rejects.toThrow(ImportError); await expect(importFile(file, options)).rejects.toThrow('Die Datei enth\u00e4lt keine auswertbaren Tabellen.'); }); it('imports a larger realistic CSV without losing rows', async () => { const header = 'Title;Severity;Status;Asset'; const rows = Array.from({ length: 5000 }, (_, index) => `Synthetic finding ${index + 1};Medium;Open;asset-${index + 1}` ); const file = new File([[header, ...rows].join('\n')], 'large.csv', { type: 'text/csv' }); const imported = await importFile(file, options); expect(imported.sheets[0].analysis.records).toHaveLength(5000); expect(imported.sheets[0].analysis.records[4999].title).toBe('Synthetic finding 5000'); }); it('rejects a truncated XLSX container', async () => { const truncatedZip = new Uint8Array([0x50, 0x4b, 0x03, 0x04]); const file = new File([truncatedZip], 'broken.xlsx', { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); await expect(importFile(file, options)).rejects.toThrow(); }); });