import { describe, expect, it } from 'bun:test' import { renderJSX, sceneNodeToJSX } from '@open-pencil/core' import { getNodeOrThrow, childIdAt } from '#tests/helpers/assert' import { makeSceneGraph } from '#tests/helpers/scene' describe('text props round-trip', () => { it('lineHeight renders and exports', async () => { const g = makeSceneGraph() const [result] = await renderJSX(g, 'Hello') const n = getNodeOrThrow(g, result.id) expect(n.lineHeight).toBe(24) const jsx = sceneNodeToJSX(n.id, g) expect(jsx).toContain('lineHeight={24}') }) it('letterSpacing renders and exports', async () => { const g = makeSceneGraph() const [result] = await renderJSX(g, 'Spaced') const n = getNodeOrThrow(g, result.id) expect(n.letterSpacing).toBe(2) const jsx = sceneNodeToJSX(n.id, g) expect(jsx).toContain('letterSpacing={2}') }) it('textDecoration renders and exports', async () => { const g = makeSceneGraph() const [result] = await renderJSX(g, 'Link') const n = getNodeOrThrow(g, result.id) expect(n.textDecoration).toBe('UNDERLINE') const jsx = sceneNodeToJSX(n.id, g) expect(jsx).toContain('textDecoration="underline"') }) it('textCase renders and exports', async () => { const g = makeSceneGraph() const [result] = await renderJSX(g, 'label') const n = getNodeOrThrow(g, result.id) expect(n.textCase).toBe('UPPER') const jsx = sceneNodeToJSX(n.id, g) expect(jsx).toContain('textCase="upper"') }) it('maxLines renders with truncation', async () => { const g = makeSceneGraph() const [result] = await renderJSX(g, 'Long text here') const n = getNodeOrThrow(g, result.id) expect(n.maxLines).toBe(2) expect(n.textTruncation).toBe('ENDING') const jsx = sceneNodeToJSX(n.id, g) expect(jsx).toContain('maxLines={2}') }) it('truncate without maxLines', async () => { const g = makeSceneGraph() const [result] = await renderJSX(g, 'Overflow') const n = getNodeOrThrow(g, result.id) expect(n.textTruncation).toBe('ENDING') const jsx = sceneNodeToJSX(n.id, g) expect(jsx).toContain('truncate') }) it('accepts Figma-style text aliases', async () => { const g = makeSceneGraph() const [result] = await renderJSX( g, '' ) const n = getNodeOrThrow(g, result.id) expect(n.text).toBe('Alias text') expect(n.fontSize).toBe(24) expect(n.fontFamily).toBe('Inter') expect(n.fontWeight).toBe(700) expect(n.textAlignHorizontal).toBe('CENTER') expect(n.textAlignVertical).toBe('CENTER') expect(n.fills[0]?.type).toBe('SOLID') }) it('accepts characters as a text content alias', async () => { const g = makeSceneGraph() const [result] = await renderJSX(g, '') const n = getNodeOrThrow(g, result.id) expect(n.text).toBe('Characters text') }) it('prefers text children over text prop alias', async () => { const g = makeSceneGraph() const [result] = await renderJSX(g, 'Child text') const n = getNodeOrThrow(g, result.id) expect(n.text).toBe('Child text') }) it('defaults omit text props', async () => { const g = makeSceneGraph() const [result] = await renderJSX(g, 'Plain') const n = getNodeOrThrow(g, result.id) expect(n.lineHeight).toBeNull() expect(n.letterSpacing).toBe(0) expect(n.textDecoration).toBe('NONE') expect(n.textCase).toBe('ORIGINAL') expect(n.maxLines).toBeNull() const jsx = sceneNodeToJSX(n.id, g) expect(jsx).not.toContain('lineHeight') expect(jsx).not.toContain('letterSpacing') expect(jsx).not.toContain('textDecoration') expect(jsx).not.toContain('textCase') expect(jsx).not.toContain('maxLines') expect(jsx).not.toContain('truncate') }) it('text w="fill" in flex="col" exports as w="fill" not w={computed}', async () => { const g = makeSceneGraph() const [result] = await renderJSX( g, ` Hello World ` ) const card = getNodeOrThrow(g, result.id) const title = getNodeOrThrow(g, childIdAt(card, 0)) expect(title.layoutAlignSelf).toBe('STRETCH') expect(title.textAutoResize).toBe('HEIGHT') const jsx = sceneNodeToJSX(title.id, g) expect(jsx).toContain('w="fill"') expect(jsx).not.toMatch(/w=\{/) }) it('text grow={1} in flex="row" exports as grow not w={computed}', async () => { const g = makeSceneGraph() const [result] = await renderJSX( g, ` Label Some value text ` ) const row = getNodeOrThrow(g, result.id) const value = getNodeOrThrow(g, childIdAt(row, 1)) expect(value.layoutGrow).toBe(1) const jsx = sceneNodeToJSX(value.id, g) expect(jsx).toContain('grow={1}') expect(jsx).not.toMatch(/\bw=\{\d+\}/) }) })