einvoice/test/suite/einvoice_error-handling/test.err-02.validation-errors.ts

299 lines
9.6 KiB
TypeScript

import { expect, tap } from '@git.zone/tstest/tapbundle';
import { EInvoice } from '../../../ts/index.js';
tap.test('ERR-02: Validation Errors - should handle validation errors gracefully', async () => {
console.log('Testing validation error handling...\n');
// Test 1: Invalid XML structure
const testInvalidXmlStructure = async () => {
console.log('Test 1 - Invalid XML structure:');
let errorCaught = false;
let errorMessage = '';
try {
const einvoice = new EInvoice();
// This should fail - invalid XML structure
await einvoice.fromXmlString('<?xml version="1.0"?><Invoice>broken xml');
} catch (error) {
errorCaught = true;
errorMessage = error.message || 'Unknown error';
console.log(` Error caught: ${errorMessage}`);
}
const gracefulHandling = errorCaught && !errorMessage.includes('FATAL');
console.log(` Error was caught: ${errorCaught}`);
console.log(` Graceful handling: ${gracefulHandling}`);
return { errorCaught, gracefulHandling, errorMessage };
};
// Test 2: Invalid e-invoice format
const testInvalidEInvoiceFormat = async () => {
console.log('\nTest 2 - Invalid e-invoice format:');
let errorCaught = false;
let errorMessage = '';
try {
const einvoice = new EInvoice();
// Valid XML but not a valid e-invoice format
await einvoice.fromXmlString(`<?xml version="1.0"?>
<SomeOtherDocument>
<Field>Value</Field>
</SomeOtherDocument>`);
} catch (error) {
errorCaught = true;
errorMessage = error.message || 'Unknown error';
console.log(` Error caught: ${errorMessage}`);
}
const gracefulHandling = errorCaught && !errorMessage.includes('FATAL');
console.log(` Error was caught: ${errorCaught}`);
console.log(` Graceful handling: ${gracefulHandling}`);
return { errorCaught, gracefulHandling, errorMessage };
};
// Test 3: Missing mandatory fields
const testMissingMandatoryFields = async () => {
console.log('\nTest 3 - Missing mandatory fields:');
let errorCaught = false;
let errorMessage = '';
try {
const einvoice = new EInvoice();
// Try to export without setting mandatory fields
await einvoice.toXmlString('ubl');
} catch (error) {
errorCaught = true;
errorMessage = error.message || 'Unknown error';
console.log(` Error caught: ${errorMessage}`);
}
const gracefulHandling = errorCaught && !errorMessage.includes('FATAL');
console.log(` Error was caught: ${errorCaught}`);
console.log(` Graceful handling: ${gracefulHandling}`);
return { errorCaught, gracefulHandling, errorMessage };
};
// Test 4: Invalid field values
const testInvalidFieldValues = async () => {
console.log('\nTest 4 - Invalid field values:');
let errorCaught = false;
let errorMessage = '';
try {
const einvoice = new EInvoice();
einvoice.issueDate = new Date(2024, 0, 1);
einvoice.invoiceId = 'TEST-001';
// Invalid country code (should be 2 characters)
einvoice.from = {
type: 'company',
name: 'Test Company',
description: 'Testing invalid values',
address: {
streetName: 'Test Street',
houseNumber: '1',
postalCode: '12345',
city: 'Test City',
country: 'INVALID_COUNTRY_CODE' // This should cause validation error
},
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 Item',
articleNumber: 'TEST-001',
unitType: 'EA',
unitQuantity: 1,
unitNetPrice: 100,
vatPercentage: 19
}];
await einvoice.toXmlString('ubl');
} catch (error) {
errorCaught = true;
errorMessage = error.message || 'Unknown error';
console.log(` Error caught: ${errorMessage}`);
}
const gracefulHandling = errorCaught && !errorMessage.includes('FATAL');
console.log(` Error was caught: ${errorCaught}`);
console.log(` Graceful handling: ${gracefulHandling}`);
return { errorCaught, gracefulHandling, errorMessage };
};
// Test 5: Recovery after error
const testRecoveryAfterError = async () => {
console.log('\nTest 5 - Recovery after error:');
const einvoice = new EInvoice();
// First cause an error
try {
await einvoice.fromXmlString('<?xml version="1.0"?><InvalidXML>broken');
} catch (error) {
console.log(` Expected error occurred: ${error.message}`);
}
// Now try normal operation - should work
let canRecover = false;
try {
einvoice.issueDate = new Date(2024, 0, 1);
einvoice.invoiceId = 'RECOVERY-TEST';
einvoice.from = {
type: 'company',
name: 'Test Company',
description: 'Testing error recovery',
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',
articleNumber: 'TEST-001',
unitType: 'EA',
unitQuantity: 1,
unitNetPrice: 100,
vatPercentage: 19
}];
// Try to export after error
const xml = await einvoice.toXmlString('ubl');
canRecover = xml.includes('RECOVERY-TEST');
console.log(` Recovery successful: ${canRecover}`);
} catch (error) {
console.log(` Recovery failed: ${error.message}`);
canRecover = false;
}
return { canRecover };
};
// Test 6: Multiple error scenarios
const testMultipleErrorScenarios = async () => {
console.log('\nTest 6 - Multiple error scenarios:');
const errorScenarios = [
{
name: 'Empty XML',
xml: ''
},
{
name: 'Malformed XML',
xml: '<?xml version="1.0"?><root><unclosed>'
},
{
name: 'Wrong namespace',
xml: '<?xml version="1.0"?><WrongNamespace xmlns="http://wrong.namespace"><Field>Value</Field></WrongNamespace>'
}
];
let errorsHandled = 0;
for (const scenario of errorScenarios) {
try {
const einvoice = new EInvoice();
await einvoice.fromXmlString(scenario.xml);
console.log(` ${scenario.name}: No error thrown (unexpected)`);
} catch (error) {
console.log(` ${scenario.name}: Error caught gracefully`);
errorsHandled++;
}
}
const allHandled = errorsHandled === errorScenarios.length;
console.log(` Errors handled: ${errorsHandled}/${errorScenarios.length}`);
return { allHandled, errorsHandled };
};
// Run all tests
const result1 = await testInvalidXmlStructure();
const result2 = await testInvalidEInvoiceFormat();
const result3 = await testMissingMandatoryFields();
const result4 = await testInvalidFieldValues();
const result5 = await testRecoveryAfterError();
const result6 = await testMultipleErrorScenarios();
console.log('\n=== Validation Errors Error Handling Summary ===');
console.log(`Invalid XML structure: ${result1.errorCaught ? 'Handled' : 'Not handled'}`);
console.log(`Invalid e-invoice format: ${result2.errorCaught ? 'Handled' : 'Not handled'}`);
console.log(`Missing mandatory fields: ${result3.errorCaught ? 'Handled' : 'Not handled'}`);
console.log(`Invalid field values: ${result4.errorCaught ? 'Handled' : 'Not handled'}`);
console.log(`Recovery after error: ${result5.canRecover ? 'Successful' : 'Failed'}`);
console.log(`Multiple error scenarios: ${result6.allHandled ? 'All handled' : 'Some failed'}`);
// Test passes if core validation works (EN16931 validation and format detection)
const en16931ValidationWorks = result3.errorCaught; // Missing mandatory fields
const formatValidationWorks = result2.errorCaught; // Invalid e-invoice format
const multipleErrorHandling = result6.allHandled; // Multiple error scenarios
// Core validation should work for EN16931 compliance
expect(en16931ValidationWorks).toBeTrue(); // Must catch missing mandatory fields
expect(formatValidationWorks).toBeTrue(); // Must catch wrong document format
expect(multipleErrorHandling).toBeTrue(); // Must handle malformed XML gracefully
});
tap.start();