zatca-phase2
Version:
ZATCA Phase 2 e-invoicing integration for Node.js
145 lines (126 loc) • 5.05 kB
JavaScript
/**
* Unit tests for XML module
*/
const { expect } = require('chai');
const xml = require('../../lib/xml');
describe('XML Module', () => {
describe('generateInvoiceXml', () => {
it('should generate valid XML for an invoice', () => {
const invoice = {
uuid: '123e4567-e89b-12d3-a456-426614174000',
invoiceNumber: 'INV-123',
issueDate: new Date('2023-04-15T12:00:00Z'),
supplyDate: new Date('2023-04-15T12:00:00Z'),
supplierName: 'Test Supplier',
supplierTaxNumber: '123456789012345',
customerName: 'Test Customer',
customerTaxNumber: '987654321098765',
totalAmount: 115.00,
vatAmount: 15.00,
items: [
{
name: 'Test Product',
quantity: 1,
unitPrice: 100.00,
taxRate: 15,
taxAmount: 15.00,
totalAmount: 115.00
}
]
};
const result = xml.generateInvoiceXml(invoice);
// Basic validations
expect(result).to.be.a('string');
expect(result).to.include('<?xml version="1.0" encoding="UTF-8"?>');
expect(result).to.include('<Invoice');
expect(result).to.include('<cbc:ID>INV-123</cbc:ID>');
expect(result).to.include('<cbc:UUID>123e4567-e89b-12d3-a456-426614174000</cbc:UUID>');
expect(result).to.include('Test Supplier');
expect(result).to.include('Test Customer');
expect(result).to.include('123456789012345'); // supplier tax number
expect(result).to.include('987654321098765'); // customer tax number
expect(result).to.include('Test Product');
// XML structure validation
expect(result).to.include('<cbc:TaxAmount currencyID="SAR">15.00</cbc:TaxAmount>');
expect(result).to.include('<cbc:PayableAmount currencyID="SAR">115.00</cbc:PayableAmount>');
});
it('should throw error for invalid invoice data', () => {
const invalidInvoice = {
// Missing required fields
invoiceNumber: 'INV-123'
};
expect(() => xml.generateInvoiceXml(invalidInvoice)).to.throw();
});
});
describe('generateCreditNoteXml', () => {
it('should generate valid XML for a credit note', () => {
const creditNote = {
uuid: '223e4567-e89b-12d3-a456-426614174000',
invoiceNumber: 'CN-123',
issueDate: new Date('2023-04-16T12:00:00Z'),
supplyDate: new Date('2023-04-16T12:00:00Z'),
supplierName: 'Test Supplier',
supplierTaxNumber: '123456789012345',
customerName: 'Test Customer',
customerTaxNumber: '987654321098765',
totalAmount: -115.00,
vatAmount: -15.00,
items: [
{
name: 'Test Product',
quantity: -1,
unitPrice: 100.00,
taxRate: 15,
taxAmount: -15.00,
totalAmount: -115.00
}
]
};
const originalInvoice = {
uuid: '123e4567-e89b-12d3-a456-426614174000',
invoiceNumber: 'INV-123',
issueDate: new Date('2023-04-15T12:00:00Z')
};
const reason = 'Customer returned the product';
const result = xml.generateCreditNoteXml(creditNote, originalInvoice, reason);
// Basic validations
expect(result).to.be.a('string');
expect(result).to.include('<?xml version="1.0" encoding="UTF-8"?>');
expect(result).to.include('<CreditNote');
expect(result).to.include('<cbc:ID>CN-123</cbc:ID>');
expect(result).to.include('<cbc:UUID>223e4567-e89b-12d3-a456-426614174000</cbc:UUID>');
expect(result).to.include('Test Supplier');
expect(result).to.include('Test Customer');
expect(result).to.include(reason);
expect(result).to.include('INV-123'); // reference to original invoice
// Specific credit note validations
expect(result).to.include('<cbc:CreditNoteTypeCode>381</cbc:CreditNoteTypeCode>');
expect(result).to.include('<cac:BillingReference>');
});
it('should throw error for invalid credit note data', () => {
const invalidCreditNote = {
// Missing required fields
invoiceNumber: 'CN-123'
};
const originalInvoice = {
invoiceNumber: 'INV-123',
issueDate: new Date()
};
expect(() => xml.generateCreditNoteXml(invalidCreditNote, originalInvoice, 'reason')).to.throw();
});
});
describe('calculateInvoiceHash', () => {
it('should generate a valid SHA-256 hash', () => {
const sampleXml = '<Invoice>Test content</Invoice>';
const hash = xml.calculateInvoiceHash(sampleXml);
expect(hash).to.be.a('string');
expect(hash).to.match(/^[a-f0-9]{64}$/); // SHA-256 hash format (64 hex chars)
// Verify hash is deterministic
const hash2 = xml.calculateInvoiceHash(sampleXml);
expect(hash).to.equal(hash2);
// Verify hash changes with content
const hash3 = xml.calculateInvoiceHash('<Invoice>Different content</Invoice>');
expect(hash).to.not.equal(hash3);
});
});
});