UNPKG

@accounter/server

Version:
558 lines (503 loc) • 18.8 kB
import { describe, expect, it } from 'vitest'; import { createBusiness } from '../factories/business.js'; import { createCharge } from '../factories/charge.js'; import { createDocument } from '../factories/document.js'; import { createFinancialAccount } from '../factories/financial-account.js'; import { createTaxCategory } from '../factories/tax-category.js'; import { createTransaction } from '../factories/transaction.js'; import { makeUUID } from '../../demo-fixtures/helpers/deterministic-uuid.js'; import type { Fixture } from './fixture-types.js'; import { assertValidFixture, validateFixture } from './fixture-validation.js'; describe('Fixture Validation', () => { describe('validateFixture', () => { it('should validate a complete valid fixture', () => { const ownerId = makeUUID('business', 'admin'); const supplierId = makeUUID('business', 'supplier'); const taxCatId = makeUUID('tax-category', 'tax-cat'); const chargeId = makeUUID('charge', 'charge'); const accountId = makeUUID('account', 'account'); const fixture: Fixture = { businesses: { businesses: [ createBusiness({ id: ownerId, name: 'Admin' }), createBusiness({ id: supplierId, name: 'Supplier' }), ], }, taxCategories: { taxCategories: [createTaxCategory({ id: taxCatId, name: 'Tax Category' })], }, accounts: { accounts: [createFinancialAccount({ accountNumber: accountId, ownerId: ownerId })], }, charges: { charges: [ createCharge({ owner_id: ownerId }, { id: chargeId, tax_category_id: taxCatId }), ], }, transactions: { transactions: [ createTransaction({ charge_id: chargeId, business_id: supplierId, amount: '-100.00', currency: 'ILS', event_date: '2024-01-15', owner_id: ownerId, }), ], }, documents: { documents: [ createDocument({ charge_id: chargeId, creditor_id: supplierId, debtor_id: ownerId, type: 'RECEIPT', total_amount: 100.0, currency_code: 'ILS', date: '2024-01-15', owner_id: ownerId, }), ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(true); }); it('should validate a minimal fixture with just charges', () => { const ownerId = makeUUID('business', 'admin'); const chargeId = makeUUID('charge', 'charge'); const taxCatId = makeUUID('tax-category', 'tax-cat'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' })], }, taxCategories: { taxCategories: [createTaxCategory({ id: taxCatId, name: 'Tax Category' })], }, charges: { charges: [ createCharge({ owner_id: ownerId }, { id: chargeId, tax_category_id: taxCatId }), ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(true); }); it('should fail when transaction references non-existent charge', () => { const ownerId = makeUUID('business', 'admin'); const supplierId = makeUUID('business', 'supplier'); const nonExistentChargeId = makeUUID('charge', 'non-existent-charge'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' }), createBusiness({ id: supplierId, name: 'Supplier' })], }, transactions: { transactions: [ createTransaction({ charge_id: nonExistentChargeId, business_id: supplierId, amount: '-100.00', currency: 'ILS', event_date: '2024-01-15', owner_id: ownerId, }), ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain( `Transaction ${fixture.transactions!.transactions[0].id} references non-existent charge: ${nonExistentChargeId}`, ); } }); it('should fail when document references non-existent charge', () => { const ownerId = makeUUID('business', 'admin'); const supplierId = makeUUID('business', 'supplier'); const nonExistentChargeId = makeUUID('charge', 'non-existent-charge'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' }), createBusiness({ id: supplierId, name: 'Supplier' })], }, documents: { documents: [ createDocument({ charge_id: nonExistentChargeId, creditor_id: supplierId, debtor_id: ownerId, type: 'INVOICE', total_amount: 100.0, currency_code: 'ILS', date: '2024-01-15', owner_id: ownerId, }), ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain( `Document ${fixture.documents!.documents[0].id} references non-existent charge: ${nonExistentChargeId}`, ); } }); it('should fail when charge references non-existent business', () => { const nonExistentBusinessId = makeUUID('business', 'non-existent-business'); const chargeId = makeUUID('charge', 'charge'); const fixture: Fixture = { charges: { charges: [ createCharge({ owner_id: nonExistentBusinessId }, { id: chargeId }), ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain( `Charge ${chargeId} references non-existent business: ${nonExistentBusinessId}`, ); } }); it('should fail when charge references non-existent tax category', () => { const ownerId = makeUUID('business', 'admin'); const chargeId = makeUUID('charge', 'charge'); const nonExistentTaxCatId = makeUUID('tax-category', 'non-existent-tax-cat'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' })], }, charges: { charges: [ createCharge( { owner_id: ownerId }, { id: chargeId, tax_category_id: nonExistentTaxCatId }, ), ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain( `Charge ${chargeId} references non-existent tax category: ${nonExistentTaxCatId}`, ); } }); it('should fail when transaction references non-existent business', () => { const ownerId = makeUUID('business', 'admin'); const chargeId = makeUUID('charge', 'charge'); const nonExistentBusinessId = makeUUID('business', 'non-existent-business'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' })], }, charges: { charges: [createCharge({ owner_id: ownerId }, { id: chargeId })], }, transactions: { transactions: [ createTransaction({ charge_id: chargeId, business_id: nonExistentBusinessId, amount: '-100.00', currency: 'ILS', event_date: '2024-01-15', owner_id: ownerId, }), ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain( `Transaction ${fixture.transactions!.transactions[0].id} references non-existent business: ${nonExistentBusinessId}`, ); } }); it('should fail when document references non-existent creditor', () => { const ownerId = makeUUID('business', 'admin'); const chargeId = makeUUID('charge', 'charge'); const nonExistentCreditorId = makeUUID('business', 'non-existent-creditor'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' })], }, charges: { charges: [createCharge({ owner_id: ownerId }, { id: chargeId })], }, documents: { documents: [ createDocument({ charge_id: chargeId, creditor_id: nonExistentCreditorId, debtor_id: ownerId, type: 'INVOICE', total_amount: 100.0, currency_code: 'ILS', date: '2024-01-15', owner_id: ownerId, }), ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain( `Document ${fixture.documents!.documents[0].id} references non-existent business: ${nonExistentCreditorId}`, ); } }); it('should fail when document references non-existent debtor', () => { const ownerId = makeUUID('business', 'admin'); const supplierId = makeUUID('business', 'supplier'); const chargeId = makeUUID('charge', 'charge'); const nonExistentDebtorId = makeUUID('business', 'non-existent-debtor'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' }), createBusiness({ id: supplierId, name: 'Supplier' })], }, charges: { charges: [createCharge({ owner_id: ownerId }, { id: chargeId })], }, documents: { documents: [ createDocument({ charge_id: chargeId, creditor_id: supplierId, debtor_id: nonExistentDebtorId, type: 'INVOICE', total_amount: 100.0, currency_code: 'ILS', date: '2024-01-15', owner_id: ownerId, }), ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain( `Document ${fixture.documents!.documents[0].id} references non-existent business: ${nonExistentDebtorId}`, ); } }); it('should fail when charge is missing owner_id', () => { const chargeId = makeUUID('charge', 'charge'); const fixture: Fixture = { charges: { charges: [ { id: chargeId, owner_id: '', // Missing type: null, accountant_status: null, user_description: null, tax_category_id: null, optional_vat: null, documents_optional_flag: null, }, ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain(`Charge ${chargeId} missing required field: owner_id`); } }); it('should fail when transaction is missing required fields', () => { const ownerId = makeUUID('business', 'admin'); const chargeId = makeUUID('charge', 'charge'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' })], }, charges: { charges: [createCharge({ owner_id: ownerId }, { id: chargeId })], }, transactions: { transactions: [ { id: makeUUID('transaction', 'tx'), account_id: makeUUID('account', 'account'), charge_id: '', // Missing source_id: makeUUID('source', 'source'), currency: '', // Missing event_date: '', // Missing amount: '', // Will be caught as missing current_balance: '0', business_id: null, // Missing is_fee: false, owner_id: ownerId, }, ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors.length).toBeGreaterThan(0); // Should have errors for missing charge_id, business_id, currency, event_date const errorText = result.errors.join('\n'); expect(errorText).toContain('charge_id'); expect(errorText).toContain('business_id'); expect(errorText).toContain('currency'); expect(errorText).toContain('event_date'); } }); it('should fail when document is missing required fields', () => { const ownerId = makeUUID('business', 'admin'); const chargeId = makeUUID('charge', 'charge'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' })], }, charges: { charges: [createCharge({ owner_id: ownerId }, { id: chargeId })], }, documents: { documents: [ { id: makeUUID('document', 'doc'), charge_id: '', // Missing creditor_id: '', // Missing debtor_id: '', // Missing type: '', // Missing total_amount: 0, // Should fail as missing (0 is not valid) currency_code: '', // Missing date: '', // Missing image_url: null, file_url: null, serial_number: null, vat_amount: null, vat_report_date_override: null, no_vat_amount: null, allocation_number: null, exchange_rate_override: null, file_hash: null, owner_id: ownerId, }, ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors.length).toBeGreaterThan(0); // Should have errors for multiple missing fields const errorText = result.errors.join('\n'); expect(errorText).toContain('charge_id'); expect(errorText).toContain('creditor_id'); expect(errorText).toContain('debtor_id'); expect(errorText).toContain('type'); expect(errorText).toContain('currency_code'); expect(errorText).toContain('date'); } }); it('should detect duplicate business IDs', () => { const duplicateId = makeUUID('business', 'duplicate-business'); const fixture: Fixture = { businesses: { businesses: [ createBusiness({ id: duplicateId, name: 'Duplicate Business' }), createBusiness({ id: duplicateId, name: 'Duplicate Business' }), // Duplicate ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain(`Duplicate business id: ${duplicateId}`); } }); it('should detect duplicate charge IDs', () => { const ownerId = makeUUID('business', 'admin'); const duplicateChargeId = makeUUID('charge', 'duplicate-charge'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' })], }, charges: { charges: [ createCharge({ owner_id: ownerId }, { id: duplicateChargeId }), createCharge({ owner_id: ownerId }, { id: duplicateChargeId }), // Duplicate ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain(`Duplicate charge id: ${duplicateChargeId}`); } }); it('should validate financial account owner reference', () => { const nonExistentOwnerId = makeUUID('business', 'non-existent-owner'); const accountNumber = makeUUID('account', 'account'); const fixture: Fixture = { accounts: { accounts: [ createFinancialAccount({ accountNumber, ownerId: nonExistentOwnerId }), ], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(false); if (!result.ok) { expect(result.errors).toContain( `Financial account ${accountNumber} references non-existent business: ${nonExistentOwnerId}`, ); } }); it('should allow financial account without owner', () => { const accountNumber = makeUUID('account', 'account'); const fixture: Fixture = { accounts: { accounts: [createFinancialAccount({ accountNumber, ownerId: null })], }, }; const result = validateFixture(fixture); expect(result.ok).toBe(true); }); }); describe('assertValidFixture', () => { it('should not throw for valid fixture', () => { const ownerId = makeUUID('business', 'admin'); const chargeId = makeUUID('charge', 'charge'); const taxCatId = makeUUID('tax-category', 'tax-cat'); const fixture: Fixture = { businesses: { businesses: [createBusiness({ id: ownerId, name: 'Admin' })], }, taxCategories: { taxCategories: [createTaxCategory({ id: taxCatId, name: 'Tax Category' })], }, charges: { charges: [ createCharge({ owner_id: ownerId }, { id: chargeId, tax_category_id: taxCatId }), ], }, }; expect(() => assertValidFixture(fixture)).not.toThrow(); }); it('should throw for invalid fixture with formatted error message', () => { const nonExistentBusinessId = makeUUID('business', 'non-existent-business'); const chargeId = makeUUID('charge', 'charge'); const fixture: Fixture = { charges: { charges: [createCharge({ owner_id: nonExistentBusinessId }, { id: chargeId })], }, }; expect(() => assertValidFixture(fixture)).toThrow('Fixture validation failed'); expect(() => assertValidFixture(fixture)).toThrow( `Charge ${chargeId} references non-existent business: ${nonExistentBusinessId}`, ); }); }); });