58 lines
4.5 KiB
TypeScript
58 lines
4.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { appendRiskAcceptanceReview, assertRiskAcceptanceUnchanged, emptyRiskAcceptanceDetails, riskAcceptanceIssues, riskAcceptanceState } from '../../src/domain/risk-acceptance';
|
|
import { reviewFromDatabase, reviewToDatabase, reviewsEqual } from '../../src/features/review-workspace/database-review';
|
|
import { riskCommand } from './risk-acceptance-fixture';
|
|
|
|
const now = '2026-09-10T10:00:00.000Z';
|
|
describe('documented risk acceptance', () => {
|
|
it('requires complete approval, independent authority, evidence and future review/expiry', () => {
|
|
const command = riskCommand('accept', now.slice(0, 10));
|
|
expect(riskAcceptanceIssues(command, '2026-09-10')).toEqual([]);
|
|
for (const field of ['scope', 'approvalReference', 'monitoring', 'obligationsReview', 'exitPlan'] as const) {
|
|
expect(riskAcceptanceIssues({ ...command, details: { ...command.details, [field]: '' } }, '2026-09-10').length).toBeGreaterThan(0);
|
|
}
|
|
for (const patch of [{ approver: command.details.riskOwner }, { approverContact: command.details.riskOwnerContact },
|
|
{ approvedOn: '2026-09-11' }, { validFrom: '2026-09-09' }, { expiresOn: '2026-09-10' }, { reviewOn: '2026-09-10' },
|
|
{ reviewOn: '2027-01-01' }, { approvedOn: '2026-02-31' }]) {
|
|
expect(riskAcceptanceIssues({ ...command, details: { ...command.details, ...patch } }, '2026-09-10').length).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
it('supports partial drafts and rejects malformed or oversized data', () => {
|
|
const draft = { ...riskCommand('draft'), details: emptyRiskAcceptanceDetails() };
|
|
expect(riskAcceptanceIssues(draft, '2026-09-10')).toEqual([]);
|
|
for (const value of [null, {}, { ...draft, details: null }, { ...draft, recordedBy: '' }, { ...draft, changeReason: '' },
|
|
{ ...draft, details: { ...draft.details, scope: 'x'.repeat(12001) } }]) {
|
|
expect(() => appendRiskAcceptanceReview(undefined, 'occurrence', value as never, now)).toThrow();
|
|
}
|
|
});
|
|
it('appends complete history, preserves review fields and does not mark the technical finding passed', () => {
|
|
const first = appendRiskAcceptanceReview(undefined, 'occurrence', riskCommand('draft', '2026-09-10'), now);
|
|
first.comment = 'Keep original review comment';
|
|
const before = JSON.stringify(first);
|
|
const accepted = appendRiskAcceptanceReview(first, 'occurrence', riskCommand('accept', '2026-09-10'), now);
|
|
expect(JSON.stringify(first)).toBe(before);
|
|
expect(accepted.riskAcceptance?.revisions).toHaveLength(2);
|
|
expect(accepted.riskAcceptance?.revisions[0]).toEqual(first.riskAcceptance?.revisions[0]);
|
|
expect(accepted).toMatchObject({ workflowStatus: 'open', comment: first.comment, revision: 2 });
|
|
expect(accepted.riskAcceptance?.revisions[1]).toMatchObject({ recordedAt: now, approvalIdentityVerified: false });
|
|
const ui = reviewFromDatabase(accepted);
|
|
expect(reviewToDatabase(ui, accepted.target, accepted, now).riskAcceptance).toEqual(accepted.riskAcceptance);
|
|
expect(reviewsEqual(ui, structuredClone(ui))).toBe(true);
|
|
expect(reviewsEqual(ui, { ...ui, riskAcceptance: undefined })).toBe(false);
|
|
expect(() => assertRiskAcceptanceUnchanged(accepted, { ...accepted, riskAcceptance: undefined })).toThrow();
|
|
expect(() => assertRiskAcceptanceUnchanged(accepted, { ...accepted, comment: 'Allowed ordinary edit' })).not.toThrow();
|
|
});
|
|
it('derives scheduled, review due, expired and reimport review-required states without rewriting history', () => {
|
|
const accepted = appendRiskAcceptanceReview(undefined, 'old-occurrence', riskCommand('accept', '2026-09-10'), now);
|
|
expect(riskAcceptanceState(accepted.riskAcceptance, 'old-occurrence', '2026-09-10')).toBe('Accepted');
|
|
expect(riskAcceptanceState(accepted.riskAcceptance, 'old-occurrence', '2026-09-09')).toBe('Scheduled');
|
|
expect(riskAcceptanceState(accepted.riskAcceptance, 'old-occurrence', '2026-10-10')).toBe('Review due');
|
|
expect(riskAcceptanceState(accepted.riskAcceptance, 'old-occurrence', '2027-01-01')).toBe('Expired');
|
|
expect(riskAcceptanceState(accepted.riskAcceptance, 'replacement', '2026-09-10')).toBe('Review required');
|
|
const revoked = appendRiskAcceptanceReview(accepted, 'old-occurrence', riskCommand('revoke', '2026-09-10'), now);
|
|
expect(riskAcceptanceState(revoked.riskAcceptance)).toBe('Revoked');
|
|
expect(revoked.riskAcceptance?.revisions[0]).toEqual(accepted.riskAcceptance?.revisions[0]);
|
|
expect(() => appendRiskAcceptanceReview(undefined, 'old-occurrence', riskCommand('revoke', '2026-09-10'), now)).toThrow();
|
|
});
|
|
});
|