import { tap, expect } from '@push.rocks/tapbundle'; import { XInvoice } from '../ts/classes.xinvoice.js'; import { ValidationLevel } from '../ts/interfaces/common.js'; import type { ExportFormat } from '../ts/interfaces/common.js'; // Basic XInvoice tests tap.test('XInvoice should have the correct default properties', async () => { const xinvoice = new XInvoice(); expect(xinvoice.type).toEqual('invoice'); expect(xinvoice.invoiceType).toEqual('debitnote'); expect(xinvoice.status).toEqual('invoice'); expect(xinvoice.from).toBeTruthy(); expect(xinvoice.to).toBeTruthy(); expect(xinvoice.items).toBeArray(); expect(xinvoice.currency).toEqual('EUR'); }); // Test XML export functionality tap.test('XInvoice should export XML in the correct format', async () => { const xinvoice = new XInvoice(); xinvoice.id = 'TEST-XML-EXPORT'; xinvoice.invoiceId = 'TEST-XML-EXPORT'; xinvoice.from.name = 'Test Seller'; xinvoice.to.name = 'Test Buyer'; // Add an item xinvoice.items.push({ position: 1, name: 'Test Product', articleNumber: 'TP-001', unitType: 'EA', unitQuantity: 2, unitNetPrice: 100, vatPercentage: 19 }); // Export as Factur-X const xml = await xinvoice.exportXml('facturx'); // Check that the XML contains the expected elements expect(xml).toInclude('CrossIndustryInvoice'); expect(xml).toInclude('TEST-XML-EXPORT'); expect(xml).toInclude('Test Seller'); expect(xml).toInclude('Test Buyer'); expect(xml).toInclude('Test Product'); }); // Test XML loading functionality tap.test('XInvoice should load XML correctly', async () => { // Create a sample XML string const sampleXml = `<?xml version="1.0" encoding="UTF-8"?> <rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"> <rsm:ExchangedDocumentContext> <ram:GuidelineSpecifiedDocumentContextParameter> <ram:ID>urn:cen.eu:en16931:2017</ram:ID> </ram:GuidelineSpecifiedDocumentContextParameter> </rsm:ExchangedDocumentContext> <rsm:ExchangedDocument> <ram:ID>TEST-XML-LOAD</ram:ID> <ram:TypeCode>380</ram:TypeCode> <ram:IssueDateTime> <udt:DateTimeString format="102">20230101</udt:DateTimeString> </ram:IssueDateTime> </rsm:ExchangedDocument> <rsm:SupplyChainTradeTransaction> <ram:ApplicableHeaderTradeAgreement> <ram:SellerTradeParty> <ram:Name>XML Seller</ram:Name> <ram:PostalTradeAddress> <ram:LineOne>Seller Street</ram:LineOne> <ram:LineTwo>123</ram:LineTwo> <ram:PostcodeCode>12345</ram:PostcodeCode> <ram:CityName>Seller City</ram:CityName> <ram:CountryID>DE</ram:CountryID> </ram:PostalTradeAddress> </ram:SellerTradeParty> <ram:BuyerTradeParty> <ram:Name>XML Buyer</ram:Name> <ram:PostalTradeAddress> <ram:LineOne>Buyer Street</ram:LineOne> <ram:LineTwo>456</ram:LineTwo> <ram:PostcodeCode>54321</ram:PostcodeCode> <ram:CityName>Buyer City</ram:CityName> <ram:CountryID>DE</ram:CountryID> </ram:PostalTradeAddress> </ram:BuyerTradeParty> </ram:ApplicableHeaderTradeAgreement> <ram:ApplicableHeaderTradeSettlement> <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode> </ram:ApplicableHeaderTradeSettlement> </rsm:SupplyChainTradeTransaction> </rsm:CrossIndustryInvoice>`; // Create XInvoice from XML const xinvoice = await XInvoice.fromXml(sampleXml); // Check that the XInvoice instance has the expected properties expect(xinvoice.id).toEqual('TEST-XML-LOAD'); expect(xinvoice.from.name).toEqual('XML Seller'); expect(xinvoice.to.name).toEqual('XML Buyer'); expect(xinvoice.currency).toEqual('EUR'); }); // Test circular encoding/decoding tap.test('XInvoice should maintain data integrity through export/import cycle', async () => { // Create a sample invoice const originalInvoice = new XInvoice(); originalInvoice.id = 'TEST-CIRCULAR'; originalInvoice.invoiceId = 'TEST-CIRCULAR'; originalInvoice.from.name = 'Circular Seller'; originalInvoice.to.name = 'Circular Buyer'; // Add an item originalInvoice.items.push({ position: 1, name: 'Circular Product', articleNumber: 'CP-001', unitType: 'EA', unitQuantity: 3, unitNetPrice: 150, vatPercentage: 19 }); // Export as Factur-X const xml = await originalInvoice.exportXml('facturx'); // Create a new XInvoice from the XML const importedInvoice = await XInvoice.fromXml(xml); // Check that key properties match expect(importedInvoice.id).toEqual(originalInvoice.id); expect(importedInvoice.from.name).toEqual(originalInvoice.from.name); expect(importedInvoice.to.name).toEqual(originalInvoice.to.name); // Check that items match expect(importedInvoice.items).toHaveLength(1); expect(importedInvoice.items[0].name).toEqual('Circular Product'); expect(importedInvoice.items[0].unitQuantity).toEqual(3); expect(importedInvoice.items[0].unitNetPrice).toEqual(150); }); // Test validation tap.test('XInvoice should validate XML correctly', async () => { const xinvoice = new XInvoice(); xinvoice.id = 'TEST-VALIDATION'; xinvoice.invoiceId = 'TEST-VALIDATION'; xinvoice.from.name = 'Validation Seller'; xinvoice.to.name = 'Validation Buyer'; // Export as Factur-X const xml = await xinvoice.exportXml('facturx'); // Set the XML string for validation xinvoice['xmlString'] = xml; // Validate the XML const result = await xinvoice.validate(ValidationLevel.SYNTAX); // Check that validation passed expect(result.valid).toBeTrue(); expect(result.errors).toHaveLength(0); }); // Run the tests tap.start();