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