import test from 'node:test'; import assert from 'node:assert/strict'; import smallFixture from '../../../../examples/org-chart/data-expanded-small.json'; import mediumFixture from '../../../../examples/org-chart/data-expanded-medium.json'; import largeFixture from '../../../../examples/org-chart/data-expanded-large.json'; import { validateOrgChartDataset, normalizeOrgChartDataset } from '../data/index.js'; import { resolveExpandedCompanies, validateTopNodes } from './expanded-company.js'; import { createOrgChart } from './index.js'; test('fixed JSON fixtures have exact unique counts, valid ancestry and company memberships', () => { for (const [size, count, companies, depth] of [['small', 20, 3, 2], ['medium', 100, 5, 3], ['large', 300, 7, 4]] as const) { const input = structuredClone({ small: smallFixture, medium: mediumFixture, large: largeFixture }[size]); const validation = validateOrgChartDataset(input); assert.equal(validation.valid, true, JSON.stringify(validation)); if (!validation.valid) continue; const data = validation.data, normalized = normalizeOrgChartDataset(data); const resolved = resolveExpandedCompanies(data, normalized.roots, 'hanmac'); assert.equal(data.employees.length, count); assert.equal(new Set(data.employees.map(employee => employee.id)).size, count); assert.equal(resolved.companyIds.length, companies); assert.equal(resolved.issues.length, 0); for (const employee of data.employees) assert.equal(resolved.companies.get(employee.organizationId), employee.affiliationId); let maxDepth = 0; const visit = (nodes: typeof normalized.roots, level: number) => { maxDepth = Math.max(maxDepth, level); nodes.forEach(node => { if (node.children.length) visit(node.children, level + 1); }); }; visit(normalized.roots, 0); assert.equal(maxDepth, depth); assert.equal(validateTopNodes(data, normalized.roots, resolved.companies, { hanmac: { title: '회장', display: 'card' } }).length, 0); assert.ok(validateTopNodes(data, normalized.roots, resolved.companies, { hanmac: { employeeId: 'missing' } }).length); assert.ok(validateTopNodes(data, normalized.roots, resolved.companies, { hanmac: { profileImage: 'javascript:alert(1)' } }).length); } }); test('inherited identity stays stable; cross-company ancestry fails instead of mixing companies', () => { const data = structuredClone(smallFixture); delete data.organizations[1].companyId; let roots = normalizeOrgChartDataset(data).roots; assert.equal(resolveExpandedCompanies(data, roots, 'saman').companies.get(data.organizations[1].id), 'hanmac'); data.organizations[1].companyId = 'saman'; roots = normalizeOrgChartDataset(data).roots; assert.equal(resolveExpandedCompanies(data, roots, 'hanmac').issues[0]?.code, 'COMPANY_HIERARCHY'); }); test('invalid Auto view configuration fails early, leaving Fixed untouched', () => { const options = { dataSource: { load: async () => ({}) }, stylesheetUrls: { engine: '/engine.css', core: '/style.css' } }; assert.throws(() => createOrgChart({ ...options, layoutMode: 'auto', selectedCompanyIds: ['unknown'] }), /selectedCompanyIds/); assert.throws(() => createOrgChart({ ...options, layoutMode: 'auto', zoom: { min: 2 } }), /zoom/); const fixed = createOrgChart({ ...options, layoutMode: 'fixed', selectedCompanyIds: ['unknown'], companyTopNodes: { unknown: { title: 'legacy' } } }); assert.equal(fixed.getViewportState(), undefined); fixed.destroy(); });