diff --git a/frontend/src/lib/person/genealogy/layout/buildLayout.test.ts b/frontend/src/lib/person/genealogy/layout/buildLayout.test.ts index 21d5b958..cdc5f611 100644 --- a/frontend/src/lib/person/genealogy/layout/buildLayout.test.ts +++ b/frontend/src/lib/person/genealogy/layout/buildLayout.test.ts @@ -501,4 +501,42 @@ describe('buildLayout — ancestor centring invariant (#724)', () => { forest.roots.forEach(walk); } }); + + it('no two nodes on the same row overlap (canonical + synthetic)', () => { + const cases: [string, PersonNodeDTO[], RelationshipDTO[]][] = [ + ['canonical', fixtureNodes, fixtureEdges], + [ + 'synthetic deep', + [ + node('R', 'R', 0), + node('p1', 'p1', 1), + node('p2', 'p2', 1), + node('g1', 'g1', 2), + node('g2', 'g2', 2) + ], + [ + parentEdge('R', 'p1'), + parentEdge('R', 'p2'), + parentEdge('p1', 'g1'), + parentEdge('p1', 'g2') + ] + ] + ]; + + for (const [label, nodes, edges] of cases) { + const layout = buildLayout(nodes, edges); + const entries = [...layout.positions.entries()]; + for (let i = 0; i < entries.length; i++) { + for (let j = i + 1; j < entries.length; j++) { + const [, a] = entries[i]; + const [, b] = entries[j]; + if (a.y !== b.y) continue; + expect( + Math.abs(a.x - b.x), + `${label}: ${entries[i][0]} vs ${entries[j][0]} overlap on y=${a.y}` + ).toBeGreaterThanOrEqual(NODE_W + COL_GAP); + } + } + } + }); });