import { tap, expect } from '@git.zone/tstest/tapbundle'; import { EInvoice } from '../../../ts/index.js'; tap.test('EDGE-10: Time Zone Edge Cases - should handle complex timezone scenarios', async () => { console.log('Testing timezone edge cases...\n'); // Test 1: Various date/time formats in UBL const testUblDateFormats = async () => { const dateFormats = [ { name: 'UTC with Z', xml: ` TZ-001 2025-01-25 14:30:00Z 380 EUR Timezone Test Supplier Test Street Test City 12345 DE Customer Customer Street Customer City 54321 DE 1 1 100.00 Test Item `, expectedTime: '14:30:00Z' }, { name: 'UTC with +00:00', xml: ` TZ-002 2025-01-25 14:30:00+00:00 380 EUR Timezone Test Supplier Test Street Test City 12345 DE Customer Customer Street Customer City 54321 DE 1 1 100.00 Test Item `, expectedTime: '14:30:00+00:00' }, { name: 'Positive timezone offset', xml: ` TZ-003 2025-01-25 20:30:00+08:00 380 EUR Timezone Test Supplier Test Street Test City 12345 SG Customer Customer Street Customer City 54321 DE 1 1 100.00 Test Item `, expectedTime: '20:30:00+08:00' } ]; const results = []; for (const test of dateFormats) { try { const einvoice = await EInvoice.fromXml(test.xml); results.push({ name: test.name, parsed: true, hasDate: !!einvoice.date, invoiceId: einvoice.id, format: einvoice.getFormat() }); } catch (error) { results.push({ name: test.name, parsed: false, error: error.message }); } } return results; }; const ublDateResults = await testUblDateFormats(); console.log('Test 1 - UBL date/time formats:'); ublDateResults.forEach(result => { console.log(` ${result.name}: ${result.parsed ? `Parsed (${result.invoiceId})` : 'Failed'}`); }); expect(ublDateResults.every(r => r.parsed)).toEqual(true); // Test 2: Date edge cases const testDateEdgeCases = async () => { const edgeCases = [ { name: 'Leap year date', date: '2024-02-29', description: 'February 29th in leap year' }, { name: 'Year boundary', date: '2024-12-31', description: 'Last day of year' }, { name: 'DST transition', date: '2025-03-30', description: 'Daylight saving time transition date' }, { name: 'Far future date', date: '2099-12-31', description: 'Date far in the future' } ]; const results = []; for (const testCase of edgeCases) { const xml = ` DATE-EDGE-${testCase.name.toUpperCase().replace(/\s+/g, '-')} ${testCase.date} 380 EUR Date Test Supplier Test Street Test City 12345 DE Customer Customer Street Customer City 54321 DE 1 1 100.00 Test Item `; try { const einvoice = await EInvoice.fromXml(xml); const dateValid = einvoice.date && !isNaN(einvoice.date); results.push({ name: testCase.name, parsed: true, dateValid, date: new Date(einvoice.date).toISOString() }); } catch (error) { results.push({ name: testCase.name, parsed: false, error: error.message }); } } return results; }; const dateEdgeResults = await testDateEdgeCases(); console.log('\nTest 2 - Date edge cases:'); dateEdgeResults.forEach(result => { console.log(` ${result.name}: ${result.parsed ? `Valid (${result.date})` : 'Failed'}`); }); expect(dateEdgeResults.every(r => r.parsed && r.dateValid)).toEqual(true); // Test 3: Invalid date formats const testInvalidDateFormats = async () => { const invalidFormats = [ { name: 'Invalid date', date: '2025-02-30', description: 'February 30th does not exist' }, { name: 'Wrong format', date: '25/01/2025', description: 'DD/MM/YYYY instead of YYYY-MM-DD' }, { name: 'Incomplete date', date: '2025-01', description: 'Missing day' }, { name: 'Text date', date: 'January 25, 2025', description: 'Text format instead of ISO' } ]; const results = []; for (const testCase of invalidFormats) { const xml = ` INVALID-DATE-${testCase.name.toUpperCase().replace(/\s+/g, '-')} ${testCase.date} 380 EUR Date Test Supplier Test Street Test City 12345 DE Customer Customer Street Customer City 54321 DE 1 1 100.00 Test Item `; try { const einvoice = await EInvoice.fromXml(xml); // Check if date was parsed or set to current date as fallback const dateSet = einvoice.date > 0; results.push({ name: testCase.name, handled: true, dateSet, invoiceId: einvoice.id }); } catch (error) { results.push({ name: testCase.name, handled: false, errorInformative: error.message.includes('date') || error.message.includes('Date') || error.message.includes('validation') }); } } return results; }; const invalidDateResults = await testInvalidDateFormats(); console.log('\nTest 3 - Invalid date formats:'); invalidDateResults.forEach(result => { console.log(` ${result.name}: ${result.handled ? 'Handled gracefully' : 'Failed'} ${result.errorInformative ? '[Informative error]' : ''}`); }); expect(invalidDateResults.every(r => r.handled || r.errorInformative)).toEqual(true); // Test 4: CII date formats const testCiiDateFormats = async () => { const ciiXml = ` urn:cen.eu:en16931:2017 CII-TZ-001 380 20250125 CII Timezone Supplier Test Street 1 Test City 12345 DE CII Customer Customer Street 2 Customer City 54321 DE EUR `; try { const einvoice = await EInvoice.fromXml(ciiXml); return { parsed: true, format: einvoice.getFormat(), hasDate: !!einvoice.date, invoiceId: einvoice.id }; } catch (error) { return { parsed: false, error: error.message }; } }; const ciiResult = await testCiiDateFormats(); console.log('\nTest 4 - CII date format:'); console.log(` CII with format 102: ${ciiResult.parsed ? `Parsed (${ciiResult.invoiceId})` : 'Failed'}`); expect(ciiResult.parsed).toEqual(true); // Test 5: Different timezone representations const testTimezoneRepresentations = async () => { const timezones = [ { tz: '-11:00', name: 'Extreme negative offset' }, { tz: '-05:00', name: 'EST' }, { tz: '+01:00', name: 'CET' }, { tz: '+05:30', name: 'IST (half hour offset)' }, { tz: '+13:00', name: 'Extreme positive offset' }, { tz: '+14:00', name: 'Maximum positive offset' } ]; const results = []; for (const { tz, name } of timezones) { const xml = ` TZ-${tz.replace(/[+:-]/g, '')} 2025-01-25 12:00:00${tz} 380 EUR TZ Test Supplier Test Street Test City 12345 DE Customer Customer Street Customer City 54321 DE 1 1 100.00 Test Item `; try { const einvoice = await EInvoice.fromXml(xml); results.push({ timezone: tz, name, parsed: true, hasDate: !!einvoice.date }); } catch (error) { results.push({ timezone: tz, name, parsed: false, error: error.message }); } } return results; }; const timezoneResults = await testTimezoneRepresentations(); console.log('\nTest 5 - Timezone representations:'); timezoneResults.forEach(result => { console.log(` ${result.name} (${result.timezone}): ${result.parsed ? 'Parsed' : 'Failed'}`); }); expect(timezoneResults.every(r => r.parsed)).toEqual(true); console.log('\n✓ All timezone edge cases handled appropriately'); }); tap.start();