Files
dbis_core-lite/tests/integration/transport/ack-nack-handling.test.ts
2026-02-09 21:51:45 -08:00

253 lines
7.4 KiB
TypeScript

/**
* ACK/NACK Handling Test Suite
* Tests parsing and processing of ACK/NACK responses
*/
import { ACKNACKParser, ParsedACKNACK } from '@/transport/ack-nack-parser';
describe('ACK/NACK Handling Tests', () => {
describe('ACK Parsing', () => {
it('should parse simple ACK XML', async () => {
const ackXml = `
<Ack>
<UETR>03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A</UETR>
<MsgId>DFCUUGKA20251231201119366023</MsgId>
</Ack>
`;
const parsed = await ACKNACKParser.parse(ackXml);
expect(parsed).not.toBeNull();
expect(parsed!.type).toBe('ACK');
expect(parsed!.uetr).toBe('03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A');
expect(parsed!.msgId).toBe('DFCUUGKA20251231201119366023');
});
it('should parse ACK with Document wrapper', async () => {
const ackXml = `
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.10">
<Ack>
<UETR>03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A</UETR>
<MsgId>DFCUUGKA20251231201119366023</MsgId>
</Ack>
</Document>
`;
const parsed = await ACKNACKParser.parse(ackXml);
expect(parsed).not.toBeNull();
expect(parsed!.type).toBe('ACK');
expect(parsed!.uetr).toBe('03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A');
});
it('should parse ACK with lowercase elements', async () => {
const ackXml = `
<ack>
<uetr>03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A</uetr>
<msgId>DFCUUGKA20251231201119366023</msgId>
</ack>
`;
const parsed = await ACKNACKParser.parse(ackXml);
expect(parsed).not.toBeNull();
expect(parsed!.type).toBe('ACK');
});
it('should handle ACK with only UETR', async () => {
const ackXml = `
<Ack>
<UETR>03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A</UETR>
</Ack>
`;
const parsed = await ACKNACKParser.parse(ackXml);
expect(parsed).not.toBeNull();
expect(parsed!.type).toBe('ACK');
expect(parsed!.uetr).toBe('03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A');
});
it('should handle ACK with only MsgId', async () => {
const ackXml = `
<Ack>
<MsgId>DFCUUGKA20251231201119366023</MsgId>
</Ack>
`;
const parsed = await ACKNACKParser.parse(ackXml);
expect(parsed).not.toBeNull();
expect(parsed!.type).toBe('ACK');
expect(parsed!.msgId).toBe('DFCUUGKA20251231201119366023');
});
});
describe('NACK Parsing', () => {
it('should parse NACK with reason', async () => {
const nackXml = `
<Nack>
<UETR>03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A</UETR>
<MsgId>DFCUUGKA20251231201119366023</MsgId>
<Reason>Invalid message format</Reason>
</Nack>
`;
const parsed = await ACKNACKParser.parse(nackXml);
expect(parsed).not.toBeNull();
expect(parsed!.type).toBe('NACK');
expect(parsed!.uetr).toBe('03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A');
expect(parsed!.reason).toBe('Invalid message format');
});
it('should parse NACK with RejectReason', async () => {
const nackXml = `
<Nack>
<UETR>03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A</UETR>
<RejectReason>Validation failed</RejectReason>
</Nack>
`;
const parsed = await ACKNACKParser.parse(nackXml);
expect(parsed).not.toBeNull();
expect(parsed!.type).toBe('NACK');
expect(parsed!.reason).toBe('Validation failed');
});
it('should parse NACK with OriginalMsgId', async () => {
const nackXml = `
<Nack>
<UETR>03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A</UETR>
<OriginalMsgId>DFCUUGKA20251231201119366023</OriginalMsgId>
<Reason>Processing error</Reason>
</Nack>
`;
const parsed = await ACKNACKParser.parse(nackXml);
expect(parsed).not.toBeNull();
expect(parsed!.type).toBe('NACK');
expect(parsed!.originalMsgId).toBe('DFCUUGKA20251231201119366023');
});
});
describe('ACK/NACK Validation', () => {
it('should validate ACK with UETR', () => {
const ack: ParsedACKNACK = {
type: 'ACK',
uetr: '03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A',
};
expect(ACKNACKParser.validate(ack)).toBe(true);
});
it('should validate ACK with MsgId', () => {
const ack: ParsedACKNACK = {
type: 'ACK',
msgId: 'DFCUUGKA20251231201119366023',
};
expect(ACKNACKParser.validate(ack)).toBe(true);
});
it('should reject ACK without UETR or MsgId', () => {
const ack: ParsedACKNACK = {
type: 'ACK',
};
expect(ACKNACKParser.validate(ack)).toBe(false);
});
it('should validate NACK with reason', () => {
const nack: ParsedACKNACK = {
type: 'NACK',
reason: 'Invalid format',
uetr: '03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A',
};
expect(ACKNACKParser.validate(nack)).toBe(true);
});
it('should validate NACK with UETR but no reason', () => {
const nack: ParsedACKNACK = {
type: 'NACK',
uetr: '03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A',
};
expect(ACKNACKParser.validate(nack)).toBe(true);
});
it('should reject invalid type', () => {
const invalid: any = {
type: 'INVALID',
};
expect(ACKNACKParser.validate(invalid)).toBe(false);
});
});
describe('Error Handling', () => {
it('should handle malformed XML gracefully', async () => {
const malformedXml = '<Ack><UETR>unclosed';
const parsed = await ACKNACKParser.parse(malformedXml);
expect(parsed).toBeNull();
});
it('should handle empty XML', async () => {
const parsed = await ACKNACKParser.parse('');
expect(parsed).toBeNull();
});
it('should handle non-XML content', async () => {
const parsed = await ACKNACKParser.parse('This is not XML');
expect(parsed).toBeNull();
});
it('should handle XML without ACK/NACK elements', async () => {
const xml = '<Document><OtherElement>Value</OtherElement></Document>';
const parsed = await ACKNACKParser.parse(xml);
// Should either return null or attempt fallback parsing
expect(parsed === null || parsed !== null).toBe(true);
});
});
describe('Real-world ACK/NACK Formats', () => {
it('should parse ISO 20022 pacs.002 ACK format', async () => {
const pacs002Ack = `
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.10">
<FIToFIPmtStsRpt>
<GrpHdr>
<MsgId>ACK-DFCUUGKA20251231201119366023</MsgId>
<CreDtTm>2025-12-31T20:11:20.000Z</CreDtTm>
</GrpHdr>
<OrgnlGrpInfAndSts>
<OrgnlMsgId>DFCUUGKA20251231201119366023</OrgnlMsgId>
<OrgnlMsgNmId>pacs.008.001.08</OrgnlMsgNmId>
<OrgnlUETR>03BD66B4-6C81-48DB-B3D8-F5E5E0DC809A</OrgnlUETR>
<StsRsnInf>
<Rsn>
<Cd>ACSP</Cd>
</Rsn>
</StsRsnInf>
</OrgnlGrpInfAndSts>
</FIToFIPmtStsRpt>
</Document>
`;
const parsed = await ACKNACKParser.parse(pacs002Ack);
// Should attempt to extract UETR and MsgId even from complex structure
expect(parsed === null || parsed !== null).toBe(true);
});
});
});