Assessor_2.0/tests/features/import-workflow.test.ts

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'
});
});});