91 lines
4.3 KiB
TypeScript
91 lines
4.3 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import type { ImportedDataset } from '../../src/domain/dataset';
|
|
import type { ImportRecognitionResult } from '../../src/domain/import-recognition';
|
|
import {
|
|
confirmEntryMappings,
|
|
createBrowserFingerprintStore,
|
|
createImportReport,
|
|
enterImportPreview,
|
|
preparePreviewEntriesForReview,
|
|
previewEntryFromDataset,
|
|
recognitionOverridesFromResult
|
|
} from '../../src/features/import-workflow/import-workflow';
|
|
|
|
const recognition: ImportRecognitionResult = {
|
|
version: 1,
|
|
source: {
|
|
selected: { toolId: 'generic', toolName: 'Generic', confidence: { level: 'low', score: 0.4, reasons: [] }, evidence: [] },
|
|
candidates: [], decisionSource: 'automatic', requiresConfirmation: true
|
|
},
|
|
tables: [],
|
|
fields: []
|
|
};
|
|
|
|
const dataset: ImportedDataset = {
|
|
fileName: 'findings.csv', fileSize: 20, lastModified: 0, format: 'CSV', rawText: '', profileId: 'generic',
|
|
scanTool: 'Generic', recognition,
|
|
sheets: [{
|
|
id: 'table-1', name: 'Findings', rows: [['Title'], ['Issue']], raw: 'Title\nIssue',
|
|
analysis: { headerIndex: 0, headers: ['Title'], records: [{ id: 'record-1', index: 1, title: 'Issue', fields: [], filled: [], meta: [] }], columns: [], signals: [], title: 'Findings' }
|
|
}]
|
|
};
|
|
|
|
const fingerprint = { sha256: 'a'.repeat(64), fileName: 'findings.csv', sizeBytes: 20, lastModified: 0 };
|
|
|
|
describe('import workflow', () => {
|
|
it('summarizes recognition and clears explicit mapping confirmations', () => {
|
|
const preview = previewEntryFromDataset(dataset, fingerprint);
|
|
expect(preview).toMatchObject({ status: 'warning', selected: true, recordCount: 1, mappingsToConfirm: 1 });
|
|
const confirmed = confirmEntryMappings(preview);
|
|
expect(confirmed.mappingsToConfirm).toBe(0);
|
|
expect(confirmed.dataset?.recognition?.source.decisionSource).toBe('user-confirmed');
|
|
expect(recognitionOverridesFromResult(confirmed.dataset?.recognition)).toEqual({
|
|
sourceTool: { toolId: 'generic', toolName: 'Generic' },
|
|
tableSelections: undefined,
|
|
fieldRoles: undefined
|
|
});
|
|
});
|
|
|
|
it('persists fingerprints and reports repeated imports deterministically', () => {
|
|
const values = new Map<string, string>();
|
|
const storage = { getItem: (key: string) => values.get(key) ?? null, setItem: (key: string, value: string) => { values.set(key, value); } };
|
|
const store = createBrowserFingerprintStore(storage);
|
|
store.record([fingerprint], '2026-07-17T08:00:00.000Z');
|
|
const repeated = store.record([fingerprint], '2026-07-17T09:00:00.000Z');
|
|
expect(repeated[0]).toMatchObject({ sha256: fingerprint.sha256, importCount: 2, firstImportedAt: '2026-07-17T08:00:00.000Z' });
|
|
|
|
const entry = previewEntryFromDataset(dataset, fingerprint, 'findings.csv');
|
|
const report = createImportReport({ version: 1, batchId: 'batch-1', createdAt: 'now', entries: [entry] }, new Set());
|
|
expect(report).toMatchObject({ importedFiles: 0, skippedFiles: 1, duplicateFiles: 1 });
|
|
});
|
|
|
|
it('keeps an expected duplicate selected in the targeted reimport review', () => {
|
|
const duplicate = previewEntryFromDataset(dataset, fingerprint, 'findings.csv');
|
|
expect(duplicate).toMatchObject({ status: 'duplicate', selected: false });
|
|
|
|
expect(preparePreviewEntriesForReview([duplicate], { reimport: true, singleFile: true }))
|
|
.toEqual([expect.objectContaining({ status: 'duplicate', selected: true })]);
|
|
expect(preparePreviewEntriesForReview([duplicate], { reimport: false, singleFile: false }))
|
|
.toEqual([expect.objectContaining({ status: 'duplicate', selected: false })]);
|
|
});
|
|
|
|
it('preserves the target tenant while a confirmed preview is completed', () => {
|
|
const preview = { version: 1 as const, batchId: 'batch-targeted', createdAt: 'now', entries: [] };
|
|
const state = enterImportPreview({ phase: 'preparing', targetProjectId: 'project-target' }, preview);
|
|
|
|
expect(state).toEqual({
|
|
phase: 'preview',
|
|
targetProjectId: 'project-target',
|
|
preview,
|
|
error: undefined
|
|
});
|
|
}); it('keeps a possible duplicate selectable while displaying it as a warning', () => {
|
|
const entry = previewEntryFromDataset(dataset, fingerprint, undefined, 'PingCastle vom 22.07.2026, 10:00:00');
|
|
|
|
expect(entry).toMatchObject({
|
|
status: 'warning',
|
|
selected: true,
|
|
possibleDuplicateOf: 'PingCastle vom 22.07.2026, 10:00:00'
|
|
});
|
|
});});
|