import { tap, expect } from '@push.rocks/tapbundle'; import { XInvoice } from '../ts/classes.xinvoice.js'; import { InvoiceFormat, ValidationLevel } from '../ts/interfaces/common.js'; import * as fs from 'fs/promises'; import * as path from 'path'; // Test other formats corpus (PEPPOL, fatturaPA) tap.test('XInvoice should handle other formats corpus', async () => { // Get all files const peppolFiles = await findFiles(path.join(process.cwd(), 'test/assets/corpus/PEPPOL'), '.xml'); // Skip problematic fatturaPA files const fatturapaDir = path.join(process.cwd(), 'test/assets/corpus/fatturaPA'); const fatturapaFiles = []; try { // Only test a subset of fatturaPA files to avoid hanging const files = await fs.readdir(fatturapaDir, { withFileTypes: true }); for (const file of files) { if (!file.isDirectory() && file.name.endsWith('.xml') && !file.name.includes('Large_Invoice')) { fatturapaFiles.push(path.join(fatturapaDir, file.name)); } } } catch (error) { console.error(`Error reading fatturaPA directory: ${error.message}`); } // Log the number of files found console.log(`Found ${peppolFiles.length} PEPPOL files`); console.log(`Found ${fatturapaFiles.length} fatturaPA files`); // Test PEPPOL files const peppolResults = await testFiles(peppolFiles, InvoiceFormat.UBL); console.log(`PEPPOL files: ${peppolResults.success} succeeded, ${peppolResults.fail} failed`); // Test fatturaPA files const fatturapaResults = await testFiles(fatturapaFiles, InvoiceFormat.UBL); console.log(`fatturaPA files: ${fatturapaResults.success} succeeded, ${fatturapaResults.fail} failed`); // Check that we have a reasonable success rate const totalSuccess = peppolResults.success + fatturapaResults.success; const totalFiles = peppolFiles.length + fatturapaFiles.length; const successRate = totalSuccess / totalFiles; console.log(`Overall success rate: ${(successRate * 100).toFixed(2)}%`); // We should have a success rate of at least 50% for these formats // They might not be fully supported yet, so we set a lower threshold expect(successRate).toBeGreaterThan(0.5); // Save the test results to a file const testDir = path.join(process.cwd(), 'test', 'output'); await fs.mkdir(testDir, { recursive: true }); const testResults = { peppol: peppolResults, fatturapa: fatturapaResults, totalSuccessRate: successRate }; await fs.writeFile( path.join(testDir, 'other-formats-corpus-results.json'), JSON.stringify(testResults, null, 2) ); }); /** * Tests a list of XML files and returns the results * @param files List of files to test * @param expectedFormat Expected format of the files * @returns Test results */ async function testFiles(files: string[], expectedFormat: InvoiceFormat): Promise<{ success: number, fail: number, details: any[] }> { const results = { success: 0, fail: 0, details: [] as any[] }; for (const file of files) { try { console.log(`Testing file: ${path.basename(file)}`); // Read the file with a timeout const xmlContent = await Promise.race([ fs.readFile(file, 'utf8'), new Promise((_, reject) => { setTimeout(() => reject(new Error('Timeout reading file')), 5000); }) ]); // Create XInvoice from XML with a timeout const xinvoice = await Promise.race([ XInvoice.fromXml(xmlContent), new Promise((_, reject) => { setTimeout(() => reject(new Error('Timeout processing XML')), 5000); }) ]); // Check that the XInvoice instance has the expected properties if (xinvoice && xinvoice.from && xinvoice.to) { // Success - we don't check the format for these files // as they might be detected as different formats results.success++; results.details.push({ file, success: true, format: xinvoice.getFormat(), error: null }); console.log(`✅ Success: ${path.basename(file)}`); } else { // Missing required properties results.fail++; results.details.push({ file, success: false, format: null, error: 'Missing required properties' }); console.log(`❌ Failed: ${path.basename(file)} - Missing required properties`); } } catch (error) { // Error processing the file results.fail++; results.details.push({ file, success: false, format: null, error: `Error: ${error.message}` }); console.log(`❌ Failed: ${path.basename(file)} - ${error.message}`); } } return results; } /** * Recursively finds files with a specific extension in a directory * @param dir Directory to search * @param extension File extension to look for * @returns Array of file paths */ async function findFiles(dir: string, extension: string): Promise { try { const files = await fs.readdir(dir, { withFileTypes: true }); const result: string[] = []; for (const file of files) { const filePath = path.join(dir, file.name); if (file.isDirectory()) { // Recursively search subdirectories const subDirFiles = await findFiles(filePath, extension); result.push(...subDirFiles); } else if (file.name.toLowerCase().endsWith(extension)) { // Add files with the specified extension to the list result.push(filePath); } } return result; } catch (error) { console.error(`Error finding files in ${dir}:`, error); return []; } } // Run the tests tap.start();