@accounter/client
Version:
Accounter client application
146 lines (130 loc) • 4.97 kB
text/typescript
import { describe, expect, it } from 'vitest';
import { serializeReportTree } from '../utils/template-serialization.js';
import { REPORT_ROOT } from '../utils/report-tree.js';
import { BANK_ROOT } from '../utils/bank-tree.js';
import type { CustomData, FlatNode } from '../utils/types.js';
function branch(
id: string,
parent: string,
opts: { hebrewText?: string; sortCode?: number } = {},
): FlatNode<CustomData> {
return {
id,
parent,
text: `Branch ${id}`,
droppable: true,
data: {
nodeType: 'synthetic-branch',
isOpen: true,
...opts,
},
};
}
function sortCodeBranch(id: string, parent: string, sortCode: number): FlatNode<CustomData> {
return {
id,
parent,
text: `Sort Code ${sortCode}`,
droppable: true,
data: { nodeType: 'sort-code-branch', isOpen: false, sortCode },
};
}
function entity(
id: string,
parent: string,
opts: { value?: number; entityType?: 'business' | 'person' } = {},
): FlatNode<CustomData> {
return {
id,
parent,
text: `Entity ${id}`,
droppable: false,
data: {
nodeType: 'financial-entity',
isOpen: false,
value: opts.value ?? 100,
entityType: opts.entityType ?? 'business',
},
};
}
describe('serializeReportTree', () => {
it('returns valid JSON', () => {
const nodes = [branch('br-1', REPORT_ROOT), entity('e-1', 'br-1')];
const json = serializeReportTree(nodes);
expect(() => JSON.parse(json)).not.toThrow();
});
it('value field is absent from serialized entity nodes', () => {
const nodes = [entity('e-1', REPORT_ROOT)];
const parsed: { data: Record<string, unknown> }[] = JSON.parse(serializeReportTree(nodes));
expect(parsed[0].data).not.toHaveProperty('value');
});
it('entityType field is absent from serialized entity nodes', () => {
const nodes = [entity('e-1', REPORT_ROOT, { entityType: 'person' })];
const parsed: { data: Record<string, unknown> }[] = JSON.parse(serializeReportTree(nodes));
expect(parsed[0].data).not.toHaveProperty('entityType');
});
it('hebrewText is present when set', () => {
const nodes = [branch('br-1', REPORT_ROOT, { hebrewText: 'שלום' })];
const parsed: { data: { hebrewText?: string } }[] = JSON.parse(serializeReportTree(nodes));
expect(parsed[0].data.hebrewText).toBe('שלום');
});
it('hebrewText is absent when not set', () => {
const nodes = [branch('br-1', REPORT_ROOT)];
const parsed: { data: Record<string, unknown> }[] = JSON.parse(serializeReportTree(nodes));
expect(parsed[0].data).not.toHaveProperty('hebrewText');
});
it('bank nodes (parent = bank root) are excluded', () => {
const nodes = [
branch('br-report', REPORT_ROOT),
entity('e-report', 'br-report'),
branch('br-bank', BANK_ROOT),
entity('e-bank', 'br-bank'),
];
const parsed: { id: string }[] = JSON.parse(serializeReportTree(nodes));
const ids = parsed.map(n => n.id);
expect(ids).toContain('br-report');
expect(ids).toContain('e-report');
expect(ids).not.toContain('br-bank');
expect(ids).not.toContain('e-bank');
});
it('bank nodes with parent = BANK_ROOT are excluded even if mixed with report nodes', () => {
const nodes = [
entity('e-bank-root', BANK_ROOT),
entity('e-report-root', REPORT_ROOT),
];
const parsed: { id: string }[] = JSON.parse(serializeReportTree(nodes));
expect(parsed.map(n => n.id)).toEqual(['e-report-root']);
});
it('isOpen is preserved', () => {
const nodes = [
{ ...branch('br-1', REPORT_ROOT), data: { nodeType: 'synthetic-branch' as const, isOpen: true } },
];
const parsed: { data: { isOpen: boolean } }[] = JSON.parse(serializeReportTree(nodes));
expect(parsed[0].data.isOpen).toBe(true);
});
it('nodeType is preserved', () => {
const nodes = [sortCodeBranch('sc-1', REPORT_ROOT, 100), entity('e-1', 'sc-1')];
const parsed: { id: string; data: { nodeType: string } }[] = JSON.parse(
serializeReportTree(nodes),
);
expect(parsed.find(n => n.id === 'sc-1')!.data.nodeType).toBe('sort-code-branch');
});
it('sortCode is preserved for sort-code branches', () => {
const nodes = [sortCodeBranch('sc-1', REPORT_ROOT, 42)];
const parsed: { data: { sortCode?: number } }[] = JSON.parse(serializeReportTree(nodes));
expect(parsed[0].data.sortCode).toBe(42);
});
it('empty input returns empty array JSON', () => {
expect(serializeReportTree([])).toBe('[]');
});
it('preserves nested branch parent IDs', () => {
const nodes = [
branch('parent-br', REPORT_ROOT),
branch('child-br', 'parent-br'),
entity('e-1', 'child-br'),
];
const parsed: { id: string; parent: string }[] = JSON.parse(serializeReportTree(nodes));
expect(parsed.find(n => n.id === 'child-br')!.parent).toBe('parent-br');
expect(parsed.find(n => n.id === 'e-1')!.parent).toBe('child-br');
});
});