UNPKG

@accounter/client

Version:
155 lines (134 loc) 6.13 kB
import { describe, expect, it } from 'vitest'; import { isLegacyTemplateNodes, migrateLegacyTemplateNodes } from '../utils/legacy-migration.js'; import type { LegacyTemplateNode } from '../utils/legacy-migration.js'; import { REPORT_ROOT } from '../utils/report-tree.js'; import type { DynamicReportQuery } from '../../../../gql/graphql.js'; // ── fixture helpers ─────────────────────────────────────────────────────────── type BusinessSum = Extract< NonNullable<DynamicReportQuery['businessTransactionsSumFromLedgerRecords']>, { __typename?: 'BusinessTransactionsSumFromLedgerRecordsSuccessfulResult' } >['businessTransactionsSum'][number]; function legacyBranch( id: string | number, parent: string | number, opts: { sortCode?: number; descendantFinancialEntities?: string[]; descendantSortCodes?: number[]; } = {}, ): LegacyTemplateNode { return { id, parent, text: String(id), droppable: true, data: { isOpen: false, sortCode: opts.sortCode ?? null, descendantFinancialEntities: opts.descendantFinancialEntities ?? null, descendantSortCodes: opts.descendantSortCodes ?? null, mergedSortCodes: null, }, }; } function legacyLeaf(id: string, parent: string | number): LegacyTemplateNode { return { id, parent, text: id, droppable: false, data: { isOpen: false } }; } function bizSum(id: string, name: string, totalRaw: number): BusinessSum { return { business: { __typename: 'LtdFinancialEntity', id, name, sortCode: null }, credit: { __typename: 'FinancialAmount', formatted: '', raw: 0 }, debit: { __typename: 'FinancialAmount', formatted: '', raw: 0 }, total: { __typename: 'FinancialAmount', formatted: '', raw: totalRaw }, } as BusinessSum; } const UUID_A = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'; const UUID_B = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'; // ── tests ───────────────────────────────────────────────────────────────────── describe('isLegacyTemplateNodes', () => { it('returns true when any node.data has descendantSortCodes key', () => { const nodes = [legacyBranch('br-1', 'report', { descendantSortCodes: [100] })]; expect(isLegacyTemplateNodes(nodes)).toBe(true); }); it('returns false for new-format nodes (no descendantSortCodes key)', () => { const nodes: LegacyTemplateNode[] = [ { id: 'br-1', parent: 'report', text: 'Branch', droppable: true, data: { isOpen: false } }, ]; expect(isLegacyTemplateNodes(nodes)).toBe(false); }); }); describe('migrateLegacyTemplateNodes', () => { describe('sort-code branch + 2 UUIDs in descendantFinancialEntities, both in businessSums', () => { const nodes = [ legacyBranch('br-sc', 'report', { sortCode: 100, descendantSortCodes: [100], descendantFinancialEntities: [UUID_A, UUID_B], }), ]; const sums = [bizSum(UUID_A, 'Alpha Corp', 200), bizSum(UUID_B, 'Beta Ltd', -80)]; const result = migrateLegacyTemplateNodes(nodes, sums); it('branch is present with nodeType sort-code-branch', () => { const branch = result.find(n => n.id === 'br-sc'); expect(branch).toBeDefined(); expect(branch!.data.nodeType).toBe('sort-code-branch'); }); it('branch has no hint arrays in output data', () => { const branch = result.find(n => n.id === 'br-sc'); expect(branch!.data).not.toHaveProperty('descendantFinancialEntities'); expect(branch!.data).not.toHaveProperty('descendantSortCodes'); expect(branch!.data).not.toHaveProperty('mergedSortCodes'); }); it('two explicit leaf nodes are inserted with correct parent', () => { const leafA = result.find(n => n.id === UUID_A); const leafB = result.find(n => n.id === UUID_B); expect(leafA).toBeDefined(); expect(leafA!.parent).toBe('br-sc'); expect(leafA!.data.nodeType).toBe('financial-entity'); expect(leafB).toBeDefined(); expect(leafB!.parent).toBe('br-sc'); }); it('leaf text is hydrated from businessSums', () => { expect(result.find(n => n.id === UUID_A)!.text).toBe('Alpha Corp'); expect(result.find(n => n.id === UUID_B)!.text).toBe('Beta Ltd'); }); }); describe('UUID in descendantFinancialEntities but NOT in businessSums', () => { const MISSING = 'cccccccc-cccc-cccc-cccc-cccccccccccc'; const nodes = [ legacyBranch('br-1', 'report', { descendantSortCodes: [50], descendantFinancialEntities: [UUID_A, MISSING], }), ]; const sums = [bizSum(UUID_A, 'Present', 10)]; const result = migrateLegacyTemplateNodes(nodes, sums); it('missing UUID is silently dropped', () => { expect(result.find(n => n.id === MISSING)).toBeUndefined(); }); it('present UUID is still inserted', () => { expect(result.find(n => n.id === UUID_A)).toBeDefined(); }); }); describe('synthetic branch (no sortCode)', () => { it('nodeType is synthetic-branch', () => { const nodes = [ legacyBranch('synth', 'report', { descendantSortCodes: [10] }), ]; const result = migrateLegacyTemplateNodes(nodes, []); expect(result.find(n => n.id === 'synth')!.data.nodeType).toBe('synthetic-branch'); }); }); describe('parent: 0 → REPORT_ROOT', () => { it('branch with parent 0 gets parent = REPORT_ROOT', () => { const nodes = [legacyBranch('br-1', 0, { descendantSortCodes: [] })]; const result = migrateLegacyTemplateNodes(nodes, []); expect(result.find(n => n.id === 'br-1')!.parent).toBe(REPORT_ROOT); }); it('explicit leaf with parent 0 gets parent = REPORT_ROOT', () => { const nodes = [legacyLeaf(UUID_A, 0)]; const result = migrateLegacyTemplateNodes(nodes, [bizSum(UUID_A, 'Root Leaf', 5)]); expect(result.find(n => n.id === UUID_A)!.parent).toBe(REPORT_ROOT); }); }); });