test(stammbaum): cover empty-graph and single-node layouts (#724)

Review follow-up (Sara/QA): the empty graph (fresh /stammbaum before data loads)
exercised the positions.size===0 viewBox fallback and the roots.length===0 early
return, both previously untested. Assert no NaN in the viewBox and MIN dimensions,
plus a single isolated node placed once at rank 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-04 14:15:30 +02:00
committed by marcel
parent b36addde22
commit e1d404609e

View File

@@ -697,3 +697,27 @@ describe('buildLayout — termination + once-only on cyclic input (#724)', () =>
for (const id of [F, A, B, C]) expect(layout.positions.get(id)).toBeDefined();
});
});
describe('buildLayout — degenerate graphs (#724)', () => {
it('empty graph yields no positions and the MIN viewBox (no NaN)', () => {
// Runs on a fresh /stammbaum visit before any data loads — must not throw
// or emit NaN into the SVG viewBox.
const layout = buildLayout([], []);
expect(layout.positions.size).toBe(0);
expect(layout.crossLinks).toEqual([]);
expect(layout.generations.size).toBe(0);
for (const v of [layout.viewX, layout.viewY, layout.viewW, layout.viewH]) {
expect(Number.isFinite(v)).toBe(true);
}
// computeViewBox falls back to MIN dimensions when there is no content.
expect(layout.viewW).toBe(1200);
expect(layout.viewH).toBe(800);
});
it('single isolated node is placed once at rank 0', () => {
const layout = buildLayout([node(PARENT, 'Solo', 0)], []);
expect(layout.positions.size).toBe(1);
expect(layout.positions.get(PARENT)).toEqual({ x: 0, y: 0 });
expect(layout.crossLinks).toEqual([]);
});
});