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();