Files
dbis_core-lite/tests/compliance/dual-control.test.ts
2026-02-09 21:51:45 -08:00

137 lines
4.8 KiB
TypeScript

import { DualControl } from '@/orchestration/dual-control/dual-control';
import { PaymentRepository } from '@/repositories/payment-repository';
import { PaymentStatus } from '@/models/payment';
import { TestHelpers } from '../utils/test-helpers';
import { PaymentRequest } from '@/gateway/validation/payment-validation';
import { PaymentType, Currency } from '@/models/payment';
import { v4 as uuidv4 } from 'uuid';
describe('Dual Control Compliance', () => {
let paymentRepository: PaymentRepository;
let makerOperator: any;
let checkerOperator: any;
let paymentId: string;
beforeAll(async () => {
paymentRepository = new PaymentRepository();
});
beforeEach(async () => {
await TestHelpers.cleanDatabase();
// Create operators for each test
makerOperator = await TestHelpers.createTestOperator('TEST_MAKER', 'MAKER' as any);
checkerOperator = await TestHelpers.createTestOperator('TEST_CHECKER', 'CHECKER' as any);
// Create a payment in PENDING_APPROVAL status
const paymentRequest: PaymentRequest = {
type: PaymentType.CUSTOMER_CREDIT_TRANSFER,
amount: 1000,
currency: Currency.USD,
senderAccount: 'ACC001',
senderBIC: 'TESTBIC1',
receiverAccount: 'ACC002',
receiverBIC: 'TESTBIC2',
beneficiaryName: 'Test Beneficiary',
};
paymentId = await paymentRepository.create(
paymentRequest,
makerOperator.id,
`TEST-DUAL-${Date.now()}`
);
});
afterAll(async () => {
await TestHelpers.cleanDatabase();
});
describe('canApprove', () => {
it('should allow CHECKER to approve payment', async () => {
const result = await DualControl.canApprove(paymentId, checkerOperator.id);
expect(result.allowed).toBe(true);
});
it('should allow ADMIN to approve payment', async () => {
const adminOperator = await TestHelpers.createTestOperator('TEST_ADMIN', 'ADMIN' as any);
const result = await DualControl.canApprove(paymentId, adminOperator.id);
expect(result.allowed).toBe(true);
});
it('should reject if MAKER tries to approve their own payment', async () => {
const result = await DualControl.canApprove(paymentId, makerOperator.id);
expect(result.allowed).toBe(false);
// MAKER role is checked first, so error will be about role, not "same as maker"
expect(result.reason).toBeDefined();
expect(result.reason).toContain('CHECKER role');
});
it('should reject if payment is not in PENDING_APPROVAL status', async () => {
// Create a fresh payment for this test to avoid state issues
const freshPaymentRequest: PaymentRequest = {
type: PaymentType.CUSTOMER_CREDIT_TRANSFER,
amount: 2000,
currency: Currency.USD,
senderAccount: 'ACC005',
senderBIC: 'TESTBIC5',
receiverAccount: 'ACC006',
receiverBIC: 'TESTBIC6',
beneficiaryName: 'Test Beneficiary Status',
};
const freshPaymentId = await paymentRepository.create(
freshPaymentRequest,
makerOperator.id,
`TEST-DUAL-STATUS-${Date.now()}`
);
await paymentRepository.updateStatus(freshPaymentId, PaymentStatus.APPROVED);
const result = await DualControl.canApprove(freshPaymentId, checkerOperator.id);
expect(result.allowed).toBe(false);
expect(result.reason).toBeDefined();
expect(result.reason).toMatch(/status|PENDING_APPROVAL/i);
});
it('should reject if payment does not exist', async () => {
const result = await DualControl.canApprove(uuidv4(), checkerOperator.id);
expect(result.allowed).toBe(false);
expect(result.reason).toContain('not found');
});
});
describe('enforceDualControl', () => {
it('should enforce maker and checker are different', async () => {
// Create payment by maker
const paymentRequest: PaymentRequest = {
type: PaymentType.CUSTOMER_CREDIT_TRANSFER,
amount: 2000,
currency: Currency.USD,
senderAccount: 'ACC003',
senderBIC: 'TESTBIC3',
receiverAccount: 'ACC004',
receiverBIC: 'TESTBIC4',
beneficiaryName: 'Test Beneficiary 2',
};
const newPaymentId = await paymentRepository.create(
paymentRequest,
makerOperator.id,
`TEST-DUAL2-${Date.now()}`
);
// Try to approve with same maker - should fail
const canApprove = await DualControl.canApprove(newPaymentId, makerOperator.id);
expect(canApprove.allowed).toBe(false);
});
it('should require checker role', async () => {
const makerOnly = await TestHelpers.createTestOperator('TEST_MAKER_ONLY', 'MAKER' as any);
const result = await DualControl.canApprove(paymentId, makerOnly.id);
// Should fail because maker-only cannot approve
expect(result.allowed).toBe(false);
});
});
});