import { MessageService } from '@/messaging/message-service'; import { MessageRepository } from '@/repositories/message-repository'; import { PaymentRepository } from '@/repositories/payment-repository'; import { PaymentTransaction, PaymentType, PaymentStatus } from '@/models/payment'; import { MessageType } from '@/models/message'; import { TestHelpers } from '../../utils/test-helpers'; describe('MessageService', () => { let messageService: MessageService; let messageRepository: MessageRepository; let paymentRepository: PaymentRepository; let testPayment: PaymentTransaction; beforeAll(async () => { messageRepository = new MessageRepository(); paymentRepository = new PaymentRepository(); messageService = new MessageService(messageRepository, paymentRepository); }); beforeEach(async () => { await TestHelpers.cleanDatabase(); // Create test payment with ledger transaction ID const operator = await TestHelpers.createTestOperator('TEST_MSG_SVC', 'MAKER' as any); const paymentRequest = TestHelpers.createTestPaymentRequest(); const paymentId = await paymentRepository.create( paymentRequest, operator.id, `TEST-MSG-${Date.now()}` ); const payment = await paymentRepository.findById(paymentId); if (!payment) { throw new Error('Failed to create test payment'); } // Update payment with internal transaction ID (required for message generation) await paymentRepository.update(paymentId, { internalTransactionId: 'test-txn-123', status: PaymentStatus.LEDGER_POSTED, }); testPayment = (await paymentRepository.findById(paymentId))!; }); afterAll(async () => { await TestHelpers.cleanDatabase(); }); describe('generateMessage', () => { it('should generate PACS.008 message for CUSTOMER_CREDIT_TRANSFER', async () => { const payment: PaymentTransaction = { ...testPayment, type: PaymentType.CUSTOMER_CREDIT_TRANSFER, internalTransactionId: 'test-txn-001', }; const result = await messageService.generateMessage(payment); expect(result.messageId).toBeDefined(); expect(result.uetr).toBeDefined(); expect(result.msgId).toBeDefined(); expect(result.xml).toBeDefined(); expect(result.hash).toBeDefined(); expect(result.xml).toContain('pacs.008'); expect(result.xml).toContain('FIToFICstmrCdtTrf'); }); it('should generate PACS.009 message for FI_TO_FI', async () => { const payment: PaymentTransaction = { ...testPayment, type: PaymentType.FI_TO_FI, internalTransactionId: 'test-txn-002', }; const result = await messageService.generateMessage(payment); expect(result.messageId).toBeDefined(); expect(result.uetr).toBeDefined(); expect(result.msgId).toBeDefined(); expect(result.xml).toBeDefined(); expect(result.xml).toContain('pacs.009'); expect(result.xml).toContain('FICdtTrf'); }); it('should fail if ledger posting not found', async () => { const paymentWithoutLedger: PaymentTransaction = { ...testPayment, internalTransactionId: undefined, }; await expect( messageService.generateMessage(paymentWithoutLedger) ).rejects.toThrow('Ledger posting not found'); }); it('should store message in repository', async () => { const payment: PaymentTransaction = { ...testPayment, internalTransactionId: 'test-txn-003', }; const result = await messageService.generateMessage(payment); const storedMessage = await messageRepository.findById(result.messageId); expect(storedMessage).not.toBeNull(); expect(storedMessage?.messageType).toBe(MessageType.PACS_008); expect(storedMessage?.uetr).toBe(result.uetr); expect(storedMessage?.xmlContent).toBe(result.xml); }); it('should update payment with message information', async () => { const payment: PaymentTransaction = { ...testPayment, internalTransactionId: 'test-txn-004', }; const result = await messageService.generateMessage(payment); const updatedPayment = await paymentRepository.findById(payment.id); expect(updatedPayment?.uetr).toBe(result.uetr); expect(updatedPayment?.isoMessageId).toBe(result.messageId); expect(updatedPayment?.isoMessageHash).toBe(result.hash); }); }); describe('getMessage', () => { it('should retrieve message by ID', async () => { const payment: PaymentTransaction = { ...testPayment, internalTransactionId: 'test-txn-005', }; const generated = await messageService.generateMessage(payment); const retrieved = await messageService.getMessage(generated.messageId); expect(retrieved).not.toBeNull(); expect(retrieved?.id).toBe(generated.messageId); expect(retrieved?.xmlContent).toBe(generated.xml); }); it('should return null for non-existent message', async () => { const message = await messageService.getMessage('non-existent-id'); expect(message).toBeNull(); }); }); describe('getMessageByPaymentId', () => { it('should retrieve message by payment ID', async () => { const payment: PaymentTransaction = { ...testPayment, internalTransactionId: 'test-txn-006', }; const generated = await messageService.generateMessage(payment); const retrieved = await messageService.getMessageByPaymentId(payment.id); expect(retrieved).not.toBeNull(); expect(retrieved?.paymentId).toBe(payment.id); expect(retrieved?.id).toBe(generated.messageId); }); it('should return null if no message exists for payment', async () => { const operator = await TestHelpers.createTestOperator('TEST_NOMSG', 'MAKER' as any); const paymentRequest = TestHelpers.createTestPaymentRequest(); const paymentId = await paymentRepository.create( paymentRequest, operator.id, `TEST-NOMSG-${Date.now()}` ); const message = await messageService.getMessageByPaymentId(paymentId); expect(message).toBeNull(); }); }); });