UNPKG

@accounter/shaam6111-generator

Version:

Fully typed application that generates, parses, and validates SHAAM 6111 tax reports.

176 lines (145 loc) • 7.45 kB
import { readFile } from 'node:fs/promises'; import path from 'node:path'; import { describe, expect, it } from 'vitest'; import { generateReport } from '../../src/generators/generate-report.js'; import { parseReport } from '../../src/parsers/parse-report.js'; import { ReportData } from '../../src/types/index.js'; import { validReportData1 } from '../fixtures/validDataSets/data1.js'; describe('Roundtrip Tests', () => { describe('Data Fixture Roundtrip', () => { it('should maintain data integrity when generating a report and parsing it back', () => { // Generate a report from the fixture data const generatedReport = generateReport(validReportData1, false); // Parse the generated report back to data const parsedData = parseReport(generatedReport, false); // Check that the parsed data matches the original // Note: We need to normalize some fields for comparison because they might have // different string vs number representations or formatting differences // Header section comparison using a utility function const headerFields: Array<keyof ReportData['header']> = [ 'taxFileNumber', 'taxYear', 'idNumber', 'industryCode', 'businessType', 'reportingMethod', 'accountingMethod', 'accountingSystem', 'includesProfitLoss', 'includesTaxAdjustment', 'includesBalanceSheet', ]; headerFields.map(field => { expect(parsedData.header[field]).toBe(validReportData1.header[field]); }); // Helper function for comparing sections function compareSections( parsed: ReportData, original: ReportData, sectionName: 'profitAndLoss' | 'taxAdjustment' | 'balanceSheet', ) { expect(parsed[sectionName].length).toBe(original[sectionName].length); for (let i = 0; i < original[sectionName].length; i++) { expect(parsed[sectionName][i].code).toBe(original[sectionName][i].code); expect(parsed[sectionName][i].amount).toBe(original[sectionName][i].amount); } } // Profit and Loss section comparison compareSections(parsedData, validReportData1, 'profitAndLoss'); // Tax Adjustment section comparison compareSections(parsedData, validReportData1, 'taxAdjustment'); // Balance Sheet section comparison compareSections(parsedData, validReportData1, 'balanceSheet'); // Entity type comparison expect(parsedData.individualOrCompany).toBe(validReportData1.individualOrCompany); }); }); describe('Report Fixture Roundtrip', () => { it('should maintain data integrity when parsing a report and generating it back', async () => { // Read the fixture report const reportFixturePath = path.join( __dirname, '..', 'fixtures', 'validReports', 'report1.txt', ); const originalReport = await readFile(reportFixturePath, 'utf-8'); // Parse the report to data const parsedData = parseReport(originalReport, false); // Generate a new report from the parsed data const regeneratedReport = generateReport(parsedData, false); // The regenerated report should match the original report // Note: There might be some normalization differences, so we compare important sections // Compare the overall length expect(regeneratedReport.length).toBe(originalReport.length); // Check that key data points are preserved // Header section (first ~150 chars) expect(regeneratedReport.substring(0, 150)).toBe(originalReport.substring(0, 150)); // Sample important fields from profit/loss, tax adjustment, and balance sheet // Check codes from different sections by their positions const checkPositions = [ // Some positions where specific codes should appear 513, // Start of profit/loss 3213, // Start of tax adjustment 5913, // Start of balance sheet ]; for (const pos of checkPositions) { // Check 18-char segments at strategic positions expect(regeneratedReport.substring(pos, pos + 18)).toBe( originalReport.substring(pos, pos + 18), ); } }); }); describe('End-to-End Data Preservation', () => { it('should preserve all significant data through multiple conversions', () => { // Start with the fixture data const originalData: ReportData = validReportData1; // Convert to report string const report = generateReport(originalData, false); // Convert back to data const firstPassData = parseReport(report, false); // Convert to report string again const secondReport = generateReport(firstPassData, false); // Convert back to data again const secondPassData = parseReport(secondReport, false); // After multiple conversions, the data should still match the original expect(secondPassData.header.taxFileNumber).toBe(originalData.header.taxFileNumber); expect(secondPassData.header.taxYear).toBe(originalData.header.taxYear); // Check that profit/loss codes and amounts are preserved expect(secondPassData.profitAndLoss.length).toBe(originalData.profitAndLoss.length); const originalCode6666 = originalData.profitAndLoss.find(entry => entry.code === 6666); const finalCode6666 = secondPassData.profitAndLoss.find(entry => entry.code === 6666); expect(originalCode6666).toBeDefined(); expect(finalCode6666).toBeDefined(); expect(finalCode6666?.amount).toBe(originalCode6666?.amount); // Check that tax adjustment codes and amounts are preserved const originalCode100 = originalData.taxAdjustment.find(entry => entry.code === 100); const finalCode100 = secondPassData.taxAdjustment.find(entry => entry.code === 100); expect(originalCode100).toBeDefined(); expect(finalCode100).toBeDefined(); expect(finalCode100?.amount).toBe(originalCode100?.amount); // Check that balance sheet codes and amounts are preserved const originalCode7800 = originalData.balanceSheet.find(entry => entry.code === 7800); const finalCode7800 = secondPassData.balanceSheet.find(entry => entry.code === 7800); expect(originalCode7800).toBeDefined(); expect(finalCode7800).toBeDefined(); expect(finalCode7800?.amount).toBe(originalCode7800?.amount); // Key validation values are preserved // Rule 3.7: The profit/loss code 6666 (net profit) must equal tax adjustment code 100 (adjusted income) expect(originalCode6666?.amount).toBe(originalCode100?.amount); // Rule 3.7 expect(finalCode6666?.amount).toBe(finalCode100?.amount); // Rule 3.7 still holds // Rule 3.8: The sum of profit/loss codes 1450 (total assets) and 2095 (total liabilities) // must equal balance sheet code 7800 (total balance) const originalSum = (originalData.profitAndLoss.find(e => e.code === 1450)?.amount || 0) + (originalData.profitAndLoss.find(e => e.code === 2095)?.amount || 0); const finalSum = (secondPassData.profitAndLoss.find(e => e.code === 1450)?.amount || 0) + (secondPassData.profitAndLoss.find(e => e.code === 2095)?.amount || 0); expect(originalSum).toBe(originalCode7800?.amount); expect(finalSum).toBe(finalCode7800?.amount); }); }); });