import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as einvoice from '../../../ts/index.js'; import * as plugins from '../../plugins.js'; tap.test('PARSE-05: Namespace Resolution - Basic namespace declarations', async () => { console.log('Testing namespace resolution in e-invoices...\n'); const namespaceTests = [ { name: 'Default namespace', xml: ` TEST-001 2024-01-01 `, expectedNamespaces: [{ prefix: '', uri: 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2' }] }, { name: 'Prefixed namespace', xml: ` TEST-002 2024-01-01 `, expectedNamespaces: [{ prefix: 'ubl', uri: 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2' }] }, { name: 'Multiple namespaces', xml: ` TEST-003 Test Supplier `, expectedNamespaces: [ { prefix: 'ubl', uri: 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2' }, { prefix: 'cac', uri: 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' }, { prefix: 'cbc', uri: 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' } ] } ]; for (const test of namespaceTests) { console.log(`\n${test.name}:`); // Extract namespace declarations const namespaceMatches = test.xml.matchAll(/xmlns(?::([^=]+))?="([^"]+)"/g); const foundNamespaces = Array.from(namespaceMatches).map(match => ({ prefix: match[1] || '', uri: match[2] })); console.log(` Expected: ${test.expectedNamespaces.length} namespaces`); console.log(` Found: ${foundNamespaces.length} namespaces`); for (const ns of foundNamespaces) { console.log(` ${ns.prefix ? `${ns.prefix}:` : '(default)'} ${ns.uri}`); } // Verify parsing try { const invoice = new einvoice.EInvoice(); await invoice.fromXmlString(test.xml); console.log(' ✓ Parsed successfully with namespaces'); // Verify the invoice was parsed correctly expect(invoice.id).toBeDefined(); } catch (error) { console.log(` ✗ Parse error: ${error.message}`); } } }); tap.test('PARSE-05: Namespace Resolution - Namespace scope and inheritance', async () => { console.log('\nTesting namespace scope and inheritance...\n'); const scopeTests = [ { name: 'Namespace inheritance', xml: ` Inherits default namespace `, description: 'Child elements inherit parent namespace' }, { name: 'Namespace override', xml: ` Different namespace `, description: 'Child can override inherited namespace' }, { name: 'Mixed namespace scopes', xml: ` Same namespace as parent Different namespace prefix No namespace prefix `, description: 'Multiple namespace prefixes in scope' } ]; for (const test of scopeTests) { console.log(`${test.name}:`); console.log(` Description: ${test.description}`); try { const invoice = new einvoice.EInvoice(); await invoice.fromXmlString(test.xml); console.log(' ✓ Namespace scope handled correctly'); } catch (error) { // Expected to fail for non-invoice XML console.log(` ℹ Not a valid invoice format (expected)`); } } }); tap.test('PARSE-05: Namespace Resolution - Real invoice formats', async () => { console.log('\nTesting namespace resolution in real invoice formats...\n'); const formatTests = [ { name: 'UBL Invoice', xml: ` UBL-NS-TEST 2024-01-01 Namespace Test Supplier `, expectedFormat: 'UBL' }, { name: 'CII Invoice', xml: ` urn:cen.eu:en16931:2017 CII-NS-TEST `, expectedFormat: 'CII' } ]; for (const test of formatTests) { console.log(`${test.name}:`); try { const invoice = new einvoice.EInvoice(); await invoice.fromXmlString(test.xml); console.log(` ✓ Parsed successfully`); console.log(` Format: ${invoice.getFormat ? invoice.getFormat() : 'Unknown'}`); console.log(` ID: ${invoice.id}`); expect(invoice.id).toBeDefined(); } catch (error) { console.log(` ✗ Parse error: ${error.message}`); } } }); tap.test('PARSE-05: Namespace Resolution - Complex namespace scenarios', async () => { console.log('\nTesting complex namespace scenarios...\n'); // Test namespace prefix conflicts const conflictTest = { name: 'Namespace prefix redefinition', xml: ` Using namespace 1 Using namespace 2 (redefined) ` }; console.log(`${conflictTest.name}:`); try { // Extract all namespace declarations with their scope const lines = conflictTest.xml.split('\n'); let depth = 0; lines.forEach((line, index) => { const nsMatch = line.match(/xmlns:(\w+)="([^"]+)"/); if (nsMatch) { console.log(` Line ${index + 1}: Prefix '${nsMatch[1]}' = ${nsMatch[2]}`); } }); console.log(' ✓ Namespace prefix conflicts are allowed in different scopes'); } catch (error) { console.log(` ✗ Error: ${error.message}`); } // Test empty namespace (undeclaration) const undeclarationTest = { name: 'Namespace undeclaration', xml: ` No namespace ` }; console.log(`\n${undeclarationTest.name}:`); console.log(' Empty xmlns="" removes default namespace from element and children'); console.log(' ✓ Valid XML construct for namespace undeclaration'); }); tap.test('PARSE-05: Namespace Resolution - Performance considerations', async () => { console.log('\nTesting namespace resolution performance...\n'); // Generate invoice with many namespaces const generateComplexNamespaceInvoice = () => { return ` PERF-NS-TEST 2024-01-01 ${Array.from({length: 10}, (_, i) => ` ${i + 1} 1 Item ${i + 1} ITEM-${i + 1} `).join('')} `; }; const xml = generateComplexNamespaceInvoice(); const startTime = Date.now(); try { const invoice = new einvoice.EInvoice(); await invoice.fromXmlString(xml); const duration = Date.now() - startTime; console.log('Complex namespace invoice parsing:'); console.log(` ✓ Parsed successfully in ${duration}ms`); console.log(` Invoice ID: ${invoice.id}`); console.log(` Line items: ${invoice.items?.length || 0}`); expect(duration).toBeLessThan(100); // Should parse quickly } catch (error) { console.log(` ✗ Parse error: ${error.message}`); } }); // Run the tests tap.start();