import { assertCanApproveContractStep, canEditContractStep, } from './freight-permission.util'; import { FREIGHT_PERMS } from '../seed/freight-permissions.registry'; // The document-edit gate (canEditContractStep) must be STRICT: only the approver // whose turn it is may edit. This is the fix for a previous approver keeping the // "Edit contract articles" button after acting, because the approve gate lets // through anyone holding any contract-approve permission. describe('canEditContractStep (strict per-step edit gate)', () => { const director = { employee: { position: { positionType: { key: '-marketing-director-' } } }, }; // A line staff who already approved their own step but still holds a // contract-approve permission — the exact actor that leaked edit rights. const officerWithApprovePerm = { employee: { position: { positionType: { key: '-marketing-officer-' }, permissions: [{ key: FREIGHT_PERMS.contracts.approveLineStaff }], }, }, }; const superAdmin = { roles: [{ key: 'super_admin' }] }; it('lets the step’s own approver edit', () => { expect(canEditContractStep(director, '-marketing-director-')).toBe(true); }); it('lets an approval admin edit any step', () => { expect(canEditContractStep(superAdmin, '-marketing-director-')).toBe(true); }); it('does NOT let a different approver edit just because they hold an approve permission', () => { expect(canEditContractStep(officerWithApprovePerm, '-marketing-director-')).toBe( false, ); }); it('stays intentionally stricter than the approve gate (which keeps the blanket fallback)', () => { // The approve gate passes the officer via the any-permission blanket… expect(() => assertCanApproveContractStep(officerWithApprovePerm, '-marketing-director-'), ).not.toThrow(); // …but the edit gate does not — that divergence IS the fix. expect(canEditContractStep(officerWithApprovePerm, '-marketing-director-')).toBe( false, ); }); });