From ddb46af32f42541ef8cd3b79d9b2588389eb2ec9 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Thu, 2 Jul 2026 10:16:08 +0300 Subject: [PATCH] test(layout): place auto-layout reflow cases by domain --- tests/engine/editor/clipboard/delete.test.ts | 31 +++++++++ .../state.test.ts} | 26 +------ .../figma-oracle-regressions.test.ts | 69 ------------------- .../auto-layout/hidden-children/basic.test.ts | 35 ++++++++++ .../layout/auto-layout/vertical/basic.test.ts | 29 +++++++- 5 files changed, 96 insertions(+), 94 deletions(-) create mode 100644 tests/engine/editor/clipboard/delete.test.ts rename tests/engine/editor/{auto-layout-reflow.test.ts => structure/state.test.ts} (63%) delete mode 100644 tests/engine/layout/auto-layout/figma-oracle-regressions.test.ts diff --git a/tests/engine/editor/clipboard/delete.test.ts b/tests/engine/editor/clipboard/delete.test.ts new file mode 100644 index 000000000..7c434190b --- /dev/null +++ b/tests/engine/editor/clipboard/delete.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, test } from 'bun:test' + +import { createEditor } from '@open-pencil/core/editor' +import { computeAllLayouts } from '@open-pencil/core/layout' + +import { getNodeOrThrow } from '#tests/helpers/assert' +import { autoFrame, rect } from '#tests/helpers/layout' + +describe('deleteSelected', () => { + test('reflows fixed vertical auto-layout siblings', () => { + const editor = createEditor() + const page = editor.state.currentPageId + const frame = autoFrame(editor.graph, page, { + layoutMode: 'VERTICAL', + width: 300, + height: 300, + itemSpacing: 0 + }) + rect(editor.graph, frame.id, 300, 40) + const body = rect(editor.graph, frame.id, 300, 100, { layoutGrow: 1 }) + const footerA = rect(editor.graph, frame.id, 300, 40) + const footerB = rect(editor.graph, frame.id, 300, 40) + computeAllLayouts(editor.graph, page) + + editor.select([footerB.id]) + editor.deleteSelected() + + expect(getNodeOrThrow(editor.graph, body.id).height).toBe(220) + expect(getNodeOrThrow(editor.graph, footerA.id).y).toBe(260) + }) +}) diff --git a/tests/engine/editor/auto-layout-reflow.test.ts b/tests/engine/editor/structure/state.test.ts similarity index 63% rename from tests/engine/editor/auto-layout-reflow.test.ts rename to tests/engine/editor/structure/state.test.ts index 46340e570..8c7597a2e 100644 --- a/tests/engine/editor/auto-layout-reflow.test.ts +++ b/tests/engine/editor/structure/state.test.ts @@ -4,31 +4,9 @@ import { createEditor } from '@open-pencil/core/editor' import { computeAllLayouts } from '@open-pencil/core/layout' import { getNodeOrThrow } from '#tests/helpers/assert' -import { autoFrame, rect } from '#tests/helpers/layout' - -describe('editor auto-layout reflow', () => { - test('deleteSelected reflows fixed vertical auto-layout siblings', () => { - const editor = createEditor() - const page = editor.state.currentPageId - const frame = autoFrame(editor.graph, page, { - layoutMode: 'VERTICAL', - width: 300, - height: 300, - itemSpacing: 0 - }) - rect(editor.graph, frame.id, 300, 40) - const body = rect(editor.graph, frame.id, 300, 100, { layoutGrow: 1 }) - const footerA = rect(editor.graph, frame.id, 300, 40) - const footerB = rect(editor.graph, frame.id, 300, 40) - computeAllLayouts(editor.graph, page) - - editor.select([footerB.id]) - editor.deleteSelected() - - expect(getNodeOrThrow(editor.graph, body.id).height).toBe(220) - expect(getNodeOrThrow(editor.graph, footerA.id).y).toBe(260) - }) +import { rect } from '#tests/helpers/layout' +describe('structure state actions', () => { test('toggleNodeVisibility reflows HUG auto-layout instance slots', () => { const editor = createEditor() const page = editor.state.currentPageId diff --git a/tests/engine/layout/auto-layout/figma-oracle-regressions.test.ts b/tests/engine/layout/auto-layout/figma-oracle-regressions.test.ts deleted file mode 100644 index 681e5c25e..000000000 --- a/tests/engine/layout/auto-layout/figma-oracle-regressions.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { describe, expect, test } from 'bun:test' - -import { computeAllLayouts, SceneGraph } from '@open-pencil/core' - -import { getNodeOrThrow } from '#tests/helpers/assert' -import { autoFrame, pageId, rect } from '#tests/helpers/layout' - -describe('Figma auto-layout oracle regressions', () => { - test('deleting a trailing child reflows fill siblings in fixed vertical auto-layout', () => { - const graph = new SceneGraph() - const page = pageId(graph) - const frame = autoFrame(graph, page, { - layoutMode: 'VERTICAL', - width: 300, - height: 300, - itemSpacing: 0 - }) - rect(graph, frame.id, 300, 40, { name: 'header h40' }) - const body = rect(graph, frame.id, 300, 100, { name: 'body fill', layoutGrow: 1 }) - const footerA = rect(graph, frame.id, 300, 40, { name: 'footerA h40' }) - const footerB = rect(graph, frame.id, 300, 40, { name: 'footerB h40' }) - - computeAllLayouts(graph, page) - expect(getNodeOrThrow(graph, body.id).height).toBe(180) - expect(getNodeOrThrow(graph, footerA.id).y).toBe(220) - - graph.deleteNode(footerB.id) - computeAllLayouts(graph, page) - - expect(getNodeOrThrow(graph, body.id).height).toBe(220) - expect(getNodeOrThrow(graph, footerA.id).y).toBe(260) - expect(getNodeOrThrow(graph, frame.id).height).toBe(300) - }) - - test('hidden child in HUG auto-layout instance is excluded from layout', () => { - const graph = new SceneGraph() - const page = pageId(graph) - const component = graph.createNode('COMPONENT', page, { - name: 'Optional slot component', - layoutMode: 'VERTICAL', - primaryAxisSizing: 'HUG', - counterAxisSizing: 'FIXED', - width: 300, - height: 1, - itemSpacing: 0 - }) - rect(graph, component.id, 300, 40, { name: 'Slot / Pinned at Top' }) - rect(graph, component.id, 300, 74, { name: 'Slot / Content' }) - rect(graph, component.id, 300, 40, { name: 'Slot / Pinned at Bottom' }) - const instance = graph.createInstance(component.id, page, { x: 360, y: 0 }) - if (!instance) throw new Error('Expected instance to be created') - - computeAllLayouts(graph, page) - expect(getNodeOrThrow(graph, instance.id).height).toBe(154) - const content = graph.getChildren(instance.id).find((child) => child.name === 'Slot / Content') - const bottom = graph - .getChildren(instance.id) - .find((child) => child.name === 'Slot / Pinned at Bottom') - if (!content || !bottom) throw new Error('Expected instance slot children') - expect(getNodeOrThrow(graph, bottom.id).y).toBe(114) - - graph.updateNode(content.id, { visible: false }) - computeAllLayouts(graph, page) - - expect(getNodeOrThrow(graph, instance.id).height).toBe(80) - expect(getNodeOrThrow(graph, bottom.id).y).toBe(40) - expect(getNodeOrThrow(graph, content.id).height).toBe(74) - }) -}) diff --git a/tests/engine/layout/auto-layout/hidden-children/basic.test.ts b/tests/engine/layout/auto-layout/hidden-children/basic.test.ts index 2091b96df..e7ccda833 100644 --- a/tests/engine/layout/auto-layout/hidden-children/basic.test.ts +++ b/tests/engine/layout/auto-layout/hidden-children/basic.test.ts @@ -87,4 +87,39 @@ describe('hidden children', () => { expect(innerNode.height).toBe(50) expect(children[1].x).toBe(0) }) + + test('hidden children in HUG auto-layout instances collapse layout', () => { + const graph = new SceneGraph() + const page = pageId(graph) + const component = graph.createNode('COMPONENT', page, { + name: 'Optional slot component', + layoutMode: 'VERTICAL', + primaryAxisSizing: 'HUG', + counterAxisSizing: 'FIXED', + width: 300, + height: 1, + itemSpacing: 0 + }) + rect(graph, component.id, 300, 40, { name: 'Slot / Pinned at Top' }) + rect(graph, component.id, 300, 74, { name: 'Slot / Content' }) + rect(graph, component.id, 300, 40, { name: 'Slot / Pinned at Bottom' }) + const instance = graph.createInstance(component.id, page, { x: 360, y: 0 }) + if (!instance) throw new Error('Expected instance to be created') + + computeLayout(graph, instance.id) + expect(getNodeOrThrow(graph, instance.id).height).toBe(154) + const content = graph.getChildren(instance.id).find((child) => child.name === 'Slot / Content') + const bottom = graph + .getChildren(instance.id) + .find((child) => child.name === 'Slot / Pinned at Bottom') + if (!content || !bottom) throw new Error('Expected instance slot children') + expect(getNodeOrThrow(graph, bottom.id).y).toBe(114) + + graph.updateNode(content.id, { visible: false }) + computeLayout(graph, instance.id) + + expect(getNodeOrThrow(graph, instance.id).height).toBe(80) + expect(getNodeOrThrow(graph, bottom.id).y).toBe(40) + expect(getNodeOrThrow(graph, content.id).height).toBe(74) + }) }) diff --git a/tests/engine/layout/auto-layout/vertical/basic.test.ts b/tests/engine/layout/auto-layout/vertical/basic.test.ts index 60a86daaa..f612b536d 100644 --- a/tests/engine/layout/auto-layout/vertical/basic.test.ts +++ b/tests/engine/layout/auto-layout/vertical/basic.test.ts @@ -1,7 +1,8 @@ import { describe, expect, test } from 'bun:test' -import { computeLayout, SceneGraph } from '@open-pencil/core' +import { computeAllLayouts, computeLayout, SceneGraph } from '@open-pencil/core' +import { getNodeOrThrow } from '#tests/helpers/assert' import { autoFrame, pageId, rect } from '#tests/helpers/layout' describe('vertical basic', () => { @@ -43,4 +44,30 @@ describe('vertical basic', () => { expect(children[1].y).toBe(56) expect(children[2].y).toBe(112) }) + + test('deleting a trailing child reflows fill siblings in fixed vertical auto-layout', () => { + const graph = new SceneGraph() + const page = pageId(graph) + const frame = autoFrame(graph, page, { + layoutMode: 'VERTICAL', + width: 300, + height: 300, + itemSpacing: 0 + }) + rect(graph, frame.id, 300, 40, { name: 'header h40' }) + const body = rect(graph, frame.id, 300, 100, { name: 'body fill', layoutGrow: 1 }) + const footerA = rect(graph, frame.id, 300, 40, { name: 'footerA h40' }) + const footerB = rect(graph, frame.id, 300, 40, { name: 'footerB h40' }) + + computeAllLayouts(graph, page) + expect(getNodeOrThrow(graph, body.id).height).toBe(180) + expect(getNodeOrThrow(graph, footerA.id).y).toBe(220) + + graph.deleteNode(footerB.id) + computeAllLayouts(graph, page) + + expect(getNodeOrThrow(graph, body.id).height).toBe(220) + expect(getNodeOrThrow(graph, footerA.id).y).toBe(260) + expect(getNodeOrThrow(graph, frame.id).height).toBe(300) + }) })