125 lines
4.1 KiB
TypeScript
125 lines
4.1 KiB
TypeScript
import { LedgerService } from '@/ledger/transactions/ledger-service';
|
|
import { PaymentRepository } from '@/repositories/payment-repository';
|
|
import { PaymentTransaction } from '@/models/payment';
|
|
import { MockLedgerAdapter } from '@/ledger/mock/mock-ledger-adapter';
|
|
import { TestHelpers } from '../../utils/test-helpers';
|
|
import { LedgerAdapter } from '@/ledger/adapter/types';
|
|
|
|
describe('LedgerService', () => {
|
|
let ledgerService: LedgerService;
|
|
let paymentRepository: PaymentRepository;
|
|
let mockAdapter: LedgerAdapter;
|
|
let testPayment: PaymentTransaction;
|
|
|
|
beforeAll(async () => {
|
|
paymentRepository = new PaymentRepository();
|
|
mockAdapter = new MockLedgerAdapter();
|
|
ledgerService = new LedgerService(paymentRepository, mockAdapter);
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
await TestHelpers.cleanDatabase();
|
|
|
|
const operator = await TestHelpers.createTestOperator('TEST_LEDGER', 'MAKER' as any);
|
|
const paymentRequest = TestHelpers.createTestPaymentRequest();
|
|
const paymentId = await paymentRepository.create(
|
|
paymentRequest,
|
|
operator.id,
|
|
`TEST-LEDGER-${Date.now()}`
|
|
);
|
|
|
|
const payment = await paymentRepository.findById(paymentId);
|
|
if (!payment) {
|
|
throw new Error('Failed to create test payment');
|
|
}
|
|
testPayment = payment;
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await TestHelpers.cleanDatabase();
|
|
});
|
|
|
|
describe('debitAndReserve', () => {
|
|
it('should debit and reserve funds for payment', async () => {
|
|
const transactionId = await ledgerService.debitAndReserve(testPayment);
|
|
|
|
expect(transactionId).toBeDefined();
|
|
expect(typeof transactionId).toBe('string');
|
|
|
|
const updatedPayment = await paymentRepository.findById(testPayment.id);
|
|
expect(updatedPayment?.internalTransactionId).toBe(transactionId);
|
|
});
|
|
|
|
it('should return existing transaction ID if already posted', async () => {
|
|
// First reservation
|
|
const transactionId1 = await ledgerService.debitAndReserve(testPayment);
|
|
|
|
// Second attempt should return same transaction ID
|
|
const paymentWithTxn = await paymentRepository.findById(testPayment.id);
|
|
const transactionId2 = await ledgerService.debitAndReserve(paymentWithTxn!);
|
|
|
|
expect(transactionId2).toBe(transactionId1);
|
|
});
|
|
|
|
it('should fail if insufficient funds', async () => {
|
|
const largePayment: PaymentTransaction = {
|
|
...testPayment,
|
|
amount: 10000000, // Very large amount
|
|
};
|
|
|
|
// Mock adapter should throw error for insufficient funds
|
|
await expect(
|
|
ledgerService.debitAndReserve(largePayment)
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
it('should update payment status after reservation', async () => {
|
|
await ledgerService.debitAndReserve(testPayment);
|
|
|
|
const updatedPayment = await paymentRepository.findById(testPayment.id);
|
|
expect(updatedPayment?.internalTransactionId).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('releaseReserve', () => {
|
|
it('should release reserved funds', async () => {
|
|
// First reserve funds
|
|
await ledgerService.debitAndReserve(testPayment);
|
|
|
|
// Then release
|
|
await ledgerService.releaseReserve(testPayment.id);
|
|
|
|
// Should complete without error
|
|
expect(true).toBe(true);
|
|
});
|
|
|
|
it('should handle payment without transaction ID gracefully', async () => {
|
|
// Payment without internal transaction ID
|
|
await expect(
|
|
ledgerService.releaseReserve(testPayment.id)
|
|
).resolves.not.toThrow();
|
|
});
|
|
|
|
it('should fail if payment not found', async () => {
|
|
await expect(
|
|
ledgerService.releaseReserve('non-existent-payment-id')
|
|
).rejects.toThrow('Payment not found');
|
|
});
|
|
});
|
|
|
|
describe('getTransaction', () => {
|
|
it('should retrieve transaction by ID', async () => {
|
|
const transactionId = await ledgerService.debitAndReserve(testPayment);
|
|
const transaction = await ledgerService.getTransaction(transactionId);
|
|
|
|
expect(transaction).toBeDefined();
|
|
});
|
|
|
|
it('should return null for non-existent transaction', async () => {
|
|
const transaction = await ledgerService.getTransaction('non-existent-txn-id');
|
|
expect(transaction).toBeNull();
|
|
});
|
|
});
|
|
});
|
|
|