import { expect, tap } from '@git.zone/tstest/tapbundle';
import { EInvoice } from '../../../ts/index.js';
tap.test('ENC-09: Encoding Errors - should handle encoding errors gracefully', async () => {
console.log('Testing encoding error handling...\n');
// Test 1: Invalid encoding declaration
const testInvalidEncoding = async () => {
const invalidEncodingXml = `
2.1
INVALID-ENCODING-TEST
2025-01-25
EUR
`;
try {
const einvoice = new EInvoice();
await einvoice.fromXmlString(invalidEncodingXml);
console.log(`Test 1 - Invalid encoding declaration:`);
console.log(` XML with invalid encoding parsed: Yes`);
console.log(` Parser gracefully handled invalid encoding: Yes`);
return { handled: true, error: null };
} catch (error) {
console.log(`Test 1 - Invalid encoding declaration:`);
console.log(` Invalid encoding error: ${error.message}`);
console.log(` Error handled gracefully: Yes`);
return { handled: true, error: error.message };
}
};
// Test 2: Malformed XML encoding
const testMalformedXml = async () => {
const malformedXml = `
2.1
MALFORMED-TEST
2025-01-25
EUR
Company with & unescaped ampersand
`;
try {
const einvoice = new EInvoice();
await einvoice.fromXmlString(malformedXml);
console.log(`\nTest 2 - Malformed XML characters:`);
console.log(` Malformed XML parsed: Yes`);
console.log(` Parser recovered from malformed content: Yes`);
return { handled: true, error: null };
} catch (error) {
console.log(`\nTest 2 - Malformed XML characters:`);
console.log(` Malformed XML error: ${error.message}`);
console.log(` Error handled gracefully: Yes`);
return { handled: true, error: error.message };
}
};
// Test 3: Missing encoding declaration
const testMissingEncoding = async () => {
const noEncodingXml = `
2.1
NO-ENCODING-TEST
2025-01-25
EUR
Test Company
`;
try {
const einvoice = new EInvoice();
await einvoice.fromXmlString(noEncodingXml);
const success = einvoice.from?.name === 'Test Company';
console.log(`\nTest 3 - Missing encoding declaration:`);
console.log(` XML without encoding parsed: ${success ? 'Yes' : 'No'}`);
console.log(` Default encoding assumed (UTF-8): ${success ? 'Yes' : 'No'}`);
return { handled: success, error: null };
} catch (error) {
console.log(`\nTest 3 - Missing encoding declaration:`);
console.log(` Missing encoding error: ${error.message}`);
return { handled: false, error: error.message };
}
};
// Test 4: Invalid byte sequences
const testInvalidByteSequences = async () => {
// This test simulates invalid UTF-8 byte sequences
const invalidUtf8Xml = `
2.1
INVALID-BYTES-TEST
2025-01-25
EUR
Company with invalid char: \uFFFE
`;
try {
const einvoice = new EInvoice();
await einvoice.fromXmlString(invalidUtf8Xml);
console.log(`\nTest 4 - Invalid byte sequences:`);
console.log(` XML with invalid characters handled: Yes`);
console.log(` Parser recovered gracefully: Yes`);
return { handled: true, error: null };
} catch (error) {
console.log(`\nTest 4 - Invalid byte sequences:`);
console.log(` Invalid byte sequence error: ${error.message}`);
console.log(` Error handled gracefully: Yes`);
return { handled: true, error: error.message };
}
};
// Test 5: BOM (Byte Order Mark) handling
const testBomHandling = async () => {
// BOM character at the beginning of UTF-8 document
const bomXml = `\uFEFF
2.1
BOM-TEST
2025-01-25
EUR
BOM Test Company
`;
try {
const einvoice = new EInvoice();
await einvoice.fromXmlString(bomXml);
const bomHandled = einvoice.from?.name === 'BOM Test Company';
console.log(`\nTest 5 - BOM handling:`);
console.log(` BOM character handled: ${bomHandled ? 'Yes' : 'No'}`);
console.log(` XML with BOM parsed correctly: ${bomHandled ? 'Yes' : 'No'}`);
return { handled: bomHandled, error: null };
} catch (error) {
console.log(`\nTest 5 - BOM handling:`);
console.log(` BOM handling error: ${error.message}`);
return { handled: false, error: error.message };
}
};
// Test 6: Graceful fallback to UTF-8
const testUtf8Fallback = async () => {
try {
const einvoice = new EInvoice();
einvoice.id = 'UTF8-FALLBACK-TEST';
einvoice.issueDate = new Date(2025, 0, 25);
einvoice.subject = 'UTF-8 fallback test with special chars: éñü';
einvoice.from = {
type: 'company',
name: 'Test Company with éñüß',
description: 'Testing UTF-8 fallback',
address: {
streetName: 'Test Street',
houseNumber: '1',
postalCode: '12345',
city: 'Test City',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2020, month: 1, day: 1 },
registrationDetails: {
vatId: 'DE123456789',
registrationId: 'HRB 12345',
registrationName: 'Commercial Register'
}
};
einvoice.to = {
type: 'person',
name: 'Test',
surname: 'Customer',
salutation: 'Mr' as const,
sex: 'male' as const,
title: 'Doctor' as const,
description: 'Test customer',
address: {
streetName: 'Customer Street',
houseNumber: '2',
postalCode: '54321',
city: 'Customer City',
country: 'DE'
}
};
einvoice.items = [{
position: 1,
name: 'Test Product with éñü',
articleNumber: 'UTF8-001',
unitType: 'EA',
unitQuantity: 1,
unitNetPrice: 100,
vatPercentage: 19
}];
// Generate XML and verify UTF-8 handling
const xmlString = await einvoice.toXmlString('ubl');
const newInvoice = new EInvoice();
await newInvoice.fromXmlString(xmlString);
const fallbackWorking = (newInvoice.id === 'UTF8-FALLBACK-TEST' ||
newInvoice.invoiceId === 'UTF8-FALLBACK-TEST' ||
newInvoice.accountingDocId === 'UTF8-FALLBACK-TEST') &&
newInvoice.from?.name?.includes('éñüß');
console.log(`\nTest 6 - UTF-8 fallback:`);
console.log(` UTF-8 encoding works: ${fallbackWorking ? 'Yes' : 'No'}`);
console.log(` Special characters preserved: ${newInvoice.from?.name?.includes('éñüß') ? 'Yes' : 'No'}`);
return { handled: fallbackWorking, error: null };
} catch (error) {
console.log(`\nTest 6 - UTF-8 fallback:`);
console.log(` UTF-8 fallback error: ${error.message}`);
return { handled: false, error: error.message };
}
};
// Run all tests
const invalidEncodingResult = await testInvalidEncoding();
const malformedResult = await testMalformedXml();
const missingEncodingResult = await testMissingEncoding();
const invalidBytesResult = await testInvalidByteSequences();
const bomResult = await testBomHandling();
const utf8FallbackResult = await testUtf8Fallback();
console.log(`\n=== Encoding Error Handling Test Summary ===`);
console.log(`Invalid encoding declaration: ${invalidEncodingResult.handled ? 'Handled' : 'Not handled'}`);
console.log(`Malformed XML characters: ${malformedResult.handled ? 'Handled' : 'Not handled'}`);
console.log(`Missing encoding declaration: ${missingEncodingResult.handled ? 'Handled' : 'Not handled'}`);
console.log(`Invalid byte sequences: ${invalidBytesResult.handled ? 'Handled' : 'Not handled'}`);
console.log(`BOM handling: ${bomResult.handled ? 'Working' : 'Issues'}`);
console.log(`UTF-8 fallback: ${utf8FallbackResult.handled ? 'Working' : 'Issues'}`);
// Test passes if basic error handling and UTF-8 fallback work
expect(missingEncodingResult.handled || invalidEncodingResult.handled).toBeTrue();
expect(utf8FallbackResult.handled).toBeTrue();
});
// Run the test
tap.start();