import { tap, expect } from '@push.rocks/tapbundle'; import { FacturXDecoder } from '../ts/formats/cii/facturx/facturx.decoder.js'; import { FacturXEncoder } from '../ts/formats/cii/facturx/facturx.encoder.js'; import { FacturXValidator } from '../ts/formats/cii/facturx/facturx.validator.js'; import type { TInvoice } from '../ts/interfaces/common.js'; import { ValidationLevel } from '../ts/interfaces/common.js'; import * as fs from 'fs/promises'; import * as path from 'path'; // Test for circular encoding/decoding of Factur-X tap.test('Factur-X should maintain data integrity through encode/decode cycle', async () => { // Create a sample invoice const invoice = createSampleInvoice(); // Create encoder const encoder = new FacturXEncoder(); // Encode to XML const xml = await encoder.encode(invoice); // Save XML for inspection const testDir = path.join(process.cwd(), 'test', 'output'); await fs.mkdir(testDir, { recursive: true }); await fs.writeFile(path.join(testDir, 'facturx-circular-encoded.xml'), xml); // Create decoder const decoder = new FacturXDecoder(xml); // Decode XML const decodedInvoice = await decoder.decode(); // Check that decoded invoice is not null expect(decodedInvoice).toBeTruthy(); // Check that key properties match expect(decodedInvoice.id).toEqual(invoice.id); expect(decodedInvoice.from.name).toEqual(invoice.from.name); expect(decodedInvoice.to.name).toEqual(invoice.to.name); // Create validator const validator = new FacturXValidator(xml); // Validate XML const result = validator.validate(ValidationLevel.SYNTAX); // Check that validation passed expect(result.valid).toBeTrue(); expect(result.errors).toHaveLength(0); }); /** * Creates a sample invoice for testing * @returns Sample invoice */ function createSampleInvoice(): TInvoice { return { type: 'invoice', id: 'INV-2023-001', invoiceId: 'INV-2023-001', invoiceType: 'debitnote', date: new Date('2023-01-01').getTime(), status: 'invoice', versionInfo: { type: 'final', version: '1.0.0' }, language: 'en', incidenceId: 'INV-2023-001', from: { type: 'company', name: 'Supplier Company', description: 'Supplier', address: { streetName: 'Supplier Street', houseNumber: '123', postalCode: '12345', city: 'Supplier City', country: 'DE', countryCode: 'DE' }, status: 'active', foundedDate: { year: 2000, month: 1, day: 1 }, registrationDetails: { vatId: 'DE123456789', registrationId: 'HRB12345', registrationName: 'Supplier Company GmbH' } }, to: { type: 'company', name: 'Customer Company', description: 'Customer', address: { streetName: 'Customer Street', houseNumber: '456', postalCode: '54321', city: 'Customer City', country: 'DE', countryCode: 'DE' }, status: 'active', foundedDate: { year: 2005, month: 6, day: 15 }, registrationDetails: { vatId: 'DE987654321', registrationId: 'HRB54321', registrationName: 'Customer Company GmbH' } }, subject: 'Invoice INV-2023-001', items: [ { position: 1, name: 'Product A', articleNumber: 'PROD-A', unitType: 'EA', unitQuantity: 2, unitNetPrice: 100, vatPercentage: 19 }, { position: 2, name: 'Service B', articleNumber: 'SERV-B', unitType: 'HUR', unitQuantity: 5, unitNetPrice: 80, vatPercentage: 19 } ], dueInDays: 30, reverseCharge: false, currency: 'EUR', notes: ['Thank you for your business'], objectActions: [] } as TInvoice; } // Run the tests tap.start();