import { expect, tap } from '@git.zone/tstest/tapbundle';
import * as einvoice from '../../../ts/index.js';
import * as plugins from '../../plugins.js';
tap.test('PARSE-08: XPath evaluation for e-invoice data extraction', async () => {
console.log('Testing XPath-like data extraction from e-invoices...\n');
// Test extracting specific fields from different invoice formats
const invoiceExtractionTests = [
{
name: 'UBL Invoice field extraction',
xml: `
UBL-XPATH-001
2024-01-15
2024-02-15
XPath Test Supplier
123 Test Street
Berlin
10115
DE
XPath Test Customer
1
10
100.00
Test Product A
Detailed description of product A
2
5.5
55.00
Test Product B
184.45
`,
expectedData: {
id: 'UBL-XPATH-001',
issueDate: '2024-01-15',
dueDate: '2024-02-15',
supplierName: 'XPath Test Supplier',
customerName: 'XPath Test Customer',
lineItemCount: 2,
totalAmount: 184.45
}
},
{
name: 'CII Invoice field extraction',
xml: `
CII-XPATH-001
380
20240115
CII XPath Supplier
CII XPath Customer
`,
expectedData: {
id: 'CII-XPATH-001',
supplierName: 'CII XPath Supplier',
customerName: 'CII XPath Customer'
}
}
];
for (const test of invoiceExtractionTests) {
console.log(`\n${test.name}:`);
try {
const invoice = new einvoice.EInvoice();
await invoice.fromXmlString(test.xml);
console.log(' ✓ Invoice parsed successfully');
// Extract and verify data
const extractedData: any = {
id: invoice.id,
issueDate: invoice.issueDate instanceof Date ?
invoice.issueDate.toISOString().split('T')[0] :
invoice.issueDate,
supplierName: invoice.from?.name,
customerName: invoice.to?.name,
lineItemCount: invoice.items?.length || 0
};
if (invoice.dueDate) {
extractedData.dueDate = invoice.dueDate instanceof Date ?
invoice.dueDate.toISOString().split('T')[0] :
invoice.dueDate;
}
if (invoice.totalGross) {
extractedData.totalAmount = invoice.totalGross;
}
console.log(' Extracted data:');
Object.entries(extractedData).forEach(([key, value]) => {
if (value !== undefined) {
console.log(` ${key}: ${value}`);
}
});
// Verify expected data
if (test.expectedData) {
Object.entries(test.expectedData).forEach(([key, expectedValue]) => {
if (extractedData[key] !== undefined) {
expect(extractedData[key]).toEqual(expectedValue);
}
});
}
} catch (error) {
console.log(` ✗ Error: ${error.message}`);
}
}
});
tap.test('PARSE-08: Complex data extraction scenarios', async () => {
console.log('\nTesting complex data extraction scenarios...\n');
// Test extracting nested and repeated data
const complexInvoice = `
COMPLEX-001
2024-01-01
First note
Second note
Third note with special chars: €, ñ, 中文
1234567890123
123456789
Complex Supplier Corp
John Doe
+49 30 12345678
john.doe@supplier.com
${Array.from({length: 5}, (_, i) => `
${i + 1}
${(i + 1) * 2}
${((i + 1) * 50).toFixed(2)}
false
${(i * 5).toFixed(2)}
Discount ${i + 1}
Product ${String.fromCharCode(65 + i)}
12345678-${i}
`).join('')}
`;
try {
const invoice = new einvoice.EInvoice();
await invoice.fromXmlString(complexInvoice);
console.log('Complex invoice extraction results:');
console.log(` Invoice ID: ${invoice.id}`);
console.log(` Notes count: ${invoice.notes?.length || 0}`);
if (invoice.notes && invoice.notes.length > 0) {
console.log(' Notes:');
invoice.notes.forEach((note, index) => {
console.log(` ${index + 1}: ${note}`);
});
}
console.log(` Supplier identifiers: ${invoice.from?.identifiers?.length || 0}`);
console.log(` Line items: ${invoice.items?.length || 0}`);
if (invoice.items && invoice.items.length > 0) {
console.log(' Line item details:');
invoice.items.forEach((item, index) => {
console.log(` Item ${index + 1}: ${item.name || 'Unknown'} - Qty: ${item.quantity || 0}`);
});
}
console.log(' ✓ Complex data extraction successful');
} catch (error) {
console.log(` ✗ Error: ${error.message}`);
}
});
tap.test('PARSE-08: Performance of data extraction', async () => {
console.log('\nTesting data extraction performance...\n');
// Generate invoice with many fields to extract
const generateDataRichInvoice = (complexity: string) => {
const itemCount = complexity === 'simple' ? 5 : complexity === 'medium' ? 50 : 200;
const noteCount = complexity === 'simple' ? 3 : complexity === 'medium' ? 10 : 30;
return `
PERF-${complexity.toUpperCase()}
2024-01-01
${Array.from({length: noteCount}, (_, i) => `
Note ${i + 1} with some content to extract`).join('')}
Performance Test Supplier
${Array.from({length: itemCount}, (_, i) => `
${i + 1}
${i + 1}
${((i + 1) * 10).toFixed(2)}
Item ${i + 1}
`).join('')}
`;
};
const complexityLevels = ['simple', 'medium', 'complex'];
for (const complexity of complexityLevels) {
const xml = generateDataRichInvoice(complexity);
const startTime = Date.now();
try {
const invoice = new einvoice.EInvoice();
await invoice.fromXmlString(xml);
// Extract various data points
const extractedData = {
id: invoice.id,
issueDate: invoice.issueDate,
supplierName: invoice.from?.name,
noteCount: invoice.notes?.length || 0,
itemCount: invoice.items?.length || 0,
firstItemName: invoice.items?.[0]?.name,
lastItemName: invoice.items?.[invoice.items.length - 1]?.name
};
const extractTime = Date.now() - startTime;
console.log(`${complexity.charAt(0).toUpperCase() + complexity.slice(1)} invoice extraction:`);
console.log(` Extraction time: ${extractTime}ms`);
console.log(` Notes extracted: ${extractedData.noteCount}`);
console.log(` Items extracted: ${extractedData.itemCount}`);
console.log(` ✓ All data points extracted successfully`);
} catch (error) {
console.log(` ✗ Error: ${error.message}`);
}
}
});
tap.test('PARSE-08: Special extraction scenarios', async () => {
console.log('\nTesting special extraction scenarios...\n');
// Test extracting data with special characters and edge cases
const specialCases = [
{
name: 'Invoice with empty fields',
xml: `
`,
expectedBehavior: 'Handle empty/whitespace fields gracefully'
},
{
name: 'Invoice with CDATA sections',
xml: `
CDATA-001
characters & symbols]]>
`,
expectedBehavior: 'Extract CDATA content correctly'
},
{
name: 'Invoice with attributes',
xml: `
ATTR-001
EUR
`,
expectedBehavior: 'Consider attribute values in extraction'
}
];
for (const testCase of specialCases) {
console.log(`${testCase.name}:`);
console.log(` Expected: ${testCase.expectedBehavior}`);
try {
const invoice = new einvoice.EInvoice();
await invoice.fromXmlString(testCase.xml);
console.log(` ID extracted: ${invoice.id || '(empty)'}`);
console.log(` Notes: ${invoice.notes?.length || 0} found`);
if (invoice.notes && invoice.notes.length > 0) {
invoice.notes.forEach((note, i) => {
console.log(` Note ${i + 1}: "${note}"`);
});
}
console.log(' ✓ Special case handled successfully');
} catch (error) {
console.log(` ℹ Parse result: ${error.message}`);
}
}
});
// Run the tests
tap.start();