Assessor_2.0/tests/features/database-review.test.ts

64 lines
3.6 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import type { FindingReview } from '../../src/domain/canonical-model';
import type { ImportedDataset } from '../../src/domain/dataset';
import { defaultReview } from '../../src/domain/review';
import {
hydrateWorkspaceReviews, reviewFromDatabase, reviewToDatabase
} from '../../src/features/review-workspace/database-review';
const timestamp = '2026-09-06T10:00:00.000Z';
describe('database-backed finding reviews', () => {
it('round-trips every FindingReader workflow field without losing exact labels or unknown markers', () => {
const ui = {
...defaultReview(), include: true, status: 'Clarification Needed', priority: 'Critical', owner: 'Security Team',
due: '2026-10-15', prerequisites: 'Maintenance window', access: 'Domain Admin', nextStep: 'Validate change',
evidence: 'Control reports compliant', comment: 'Coordinate first', markerQuestion: true, markerBlocked: true,
markerQuickwin: true, markerExternal: true, markerNotRelevant: true
};
const current: FindingReview = {
id: 'review-1', target: { kind: 'occurrence', occurrenceId: 'occurrence-1' }, workflowStatus: 'open',
priority: 'medium', includeInActionPlan: false, markers: ['future-marker'], createdAt: timestamp,
updatedAt: timestamp, revision: 3
};
const stored = reviewToDatabase(ui, current.target, current, '2026-09-06T11:00:00.000Z');
expect(stored).toMatchObject({
workflowStatus: 'deferred', workflowLabel: 'Clarification Needed', priority: 'critical', includeInActionPlan: true,
owner: 'Security Team', dueAt: '2026-10-15', prerequisites: 'Maintenance window', requiredAccess: 'Domain Admin',
nextStep: 'Validate change', acceptanceEvidence: 'Control reports compliant', comment: 'Coordinate first', revision: 4
});
expect(stored.markers).toEqual([
'future-marker', 'question-needed', 'permission-blocked', 'quick-win', 'external-team', 'not-relevant'
]);
expect(reviewFromDatabase(stored)).toEqual(ui);
});
it('hydrates duplicate dataset projections from one database review and lets database state win over the browser cache', () => {
const makeRecord = (id: string) => ({
id, findingOccurrenceId: 'occurrence-1', findingDefinitionId: 'definition-1', index: 0, title: 'Synthetic finding',
fields: [], filled: [], meta: []
});
const dataset = {
fileName: 'Synthetic', fileSize: 1, lastModified: 0, format: 'CSV', rawText: '', profileId: 'generic', scanTool: 'Synthetic',
sheets: [
{ id: 'all', name: 'All', rows: [], raw: '', analysis: { headerIndex: 0, headers: [], records: [makeRecord('aggregate')], columns: [], signals: [], title: 'All' } },
{ id: 'source', name: 'Source', rows: [], raw: '', analysis: { headerIndex: 0, headers: [], records: [makeRecord('source-record')], columns: [], signals: [], title: 'Source' } }
]
} satisfies ImportedDataset;
const databaseReview: FindingReview = {
id: 'review-1', target: { kind: 'occurrence', occurrenceId: 'occurrence-1' }, workflowStatus: 'resolved',
workflowLabel: 'Done', priority: 'high', includeInActionPlan: true, owner: 'Database Team', markers: [],
createdAt: timestamp, updatedAt: timestamp, revision: 2
};
const hydrated = hydrateWorkspaceReviews(dataset, [databaseReview], {
aggregate: { ...defaultReview(), owner: 'Old local value' }
});
expect(hydrated.reviews.aggregate).toMatchObject({ status: 'Done', priority: 'High', owner: 'Database Team' });
expect(hydrated.reviews['source-record']).toEqual(hydrated.reviews.aggregate);
});
});