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