chore(tests): guard more test lookups
- Remove non-null assertions from context menu, panels, perf, properties, MCP, SVG, undo, and instance override tests - Add explicit store, renderer, node, and bounding-box guards - Validate affected engine and E2E tests
This commit is contained in:
parent
017c55cbf5
commit
3387b5bb6b
|
|
@ -1,5 +1,6 @@
|
|||
import { expect, test, type Page } from '@playwright/test'
|
||||
|
||||
import { expectDefined } from '#tests/helpers/assert'
|
||||
import { CanvasHelper } from '#tests/helpers/canvas'
|
||||
|
||||
let page: Page
|
||||
|
|
@ -33,12 +34,16 @@ function getPageChildren() {
|
|||
}
|
||||
|
||||
function getSelectedCount() {
|
||||
return page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.selectedIds.size)
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.selectedIds.size
|
||||
})
|
||||
}
|
||||
|
||||
async function rightClickShape(x: number, y: number) {
|
||||
const box = await canvas.canvas.boundingBox()
|
||||
await page.mouse.click(box!.x + x, box!.y + y, { button: 'right' })
|
||||
const box = expectDefined(await canvas.canvas.boundingBox(), 'canvas bounds')
|
||||
await page.mouse.click(box.x + x, box.y + y, { button: 'right' })
|
||||
}
|
||||
|
||||
function contextMenu() {
|
||||
|
|
@ -104,17 +109,23 @@ test('toggle visibility via context menu', async () => {
|
|||
await canvas.click(250, 230)
|
||||
await canvas.waitForRender()
|
||||
|
||||
const nodeId = await page.evaluate(() => [...window.__OPEN_PENCIL_STORE__!.state.selectedIds][0])
|
||||
const nodeId = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return [...store.state.selectedIds][0]
|
||||
})
|
||||
|
||||
await rightClickShape(250, 230)
|
||||
await contextItem('context-toggle-visibility').click()
|
||||
await canvas.waitForRender()
|
||||
|
||||
const hidden = await page.evaluate((id) => {
|
||||
const n = window.__OPEN_PENCIL_STORE__!.graph.getNode(id)
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const n = store.graph.getNode(id)
|
||||
return n ? { visible: n.visible } : null
|
||||
}, nodeId)
|
||||
expect(hidden!.visible).toBe(false)
|
||||
expect(hidden?.visible).toBe(false)
|
||||
|
||||
// Toggle back: select via store since invisible nodes can't be hit-tested
|
||||
await page.evaluate(() => {
|
||||
|
|
@ -125,10 +136,12 @@ test('toggle visibility via context menu', async () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const restored = await page.evaluate((id) => {
|
||||
const n = window.__OPEN_PENCIL_STORE__!.graph.getNode(id)
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const n = store.graph.getNode(id)
|
||||
return n ? { visible: n.visible } : null
|
||||
}, nodeId)
|
||||
expect(restored!.visible).toBe(true)
|
||||
expect(restored?.visible).toBe(true)
|
||||
})
|
||||
|
||||
test('toggle lock via context menu', async () => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { test, expect, type Page } from '@playwright/test'
|
||||
|
||||
import { expectDefined } from '#tests/helpers/assert'
|
||||
import { CanvasHelper } from '#tests/helpers/canvas'
|
||||
|
||||
let page: Page
|
||||
|
|
@ -27,8 +28,10 @@ test('layers panel resize increases width', async () => {
|
|||
const handleBox = await handle.boundingBox()
|
||||
expect(handleBox).not.toBeNull()
|
||||
|
||||
const cx = handleBox!.x + handleBox!.width / 2
|
||||
const cy = handleBox!.y + handleBox!.height / 2
|
||||
const handleBounds = expectDefined(handleBox, 'splitter handle bounds')
|
||||
const beforeBounds = expectDefined(before, 'layers panel bounds')
|
||||
const cx = handleBounds.x + handleBounds.width / 2
|
||||
const cy = handleBounds.y + handleBounds.height / 2
|
||||
|
||||
await page.mouse.move(cx, cy)
|
||||
await page.mouse.down()
|
||||
|
|
@ -36,22 +39,28 @@ test('layers panel resize increases width', async () => {
|
|||
await page.mouse.up()
|
||||
await canvas.waitForRender()
|
||||
|
||||
const after = await panel.boundingBox()
|
||||
expect(after!.width).toBeGreaterThan(before!.width + 40)
|
||||
const after = expectDefined(await panel.boundingBox(), 'resized layers panel bounds')
|
||||
expect(after.width).toBeGreaterThan(beforeBounds.width + 40)
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
||||
test('panel width persists after page reload', async () => {
|
||||
// Allow Reka's auto-save debounce to flush before recording the width
|
||||
await page.waitForTimeout(300)
|
||||
const recordedWidth = (await page.locator('[data-test-id="layers-panel"]').boundingBox())!.width
|
||||
const recordedWidth = expectDefined(
|
||||
await page.locator('[data-test-id="layers-panel"]').boundingBox(),
|
||||
'persisted layers panel bounds'
|
||||
).width
|
||||
|
||||
await page.reload()
|
||||
canvas = new CanvasHelper(page)
|
||||
await canvas.waitForInit()
|
||||
|
||||
const after = await page.locator('[data-test-id="layers-panel"]').boundingBox()
|
||||
expect(Math.abs(after!.width - recordedWidth)).toBeLessThanOrEqual(2)
|
||||
const after = expectDefined(
|
||||
await page.locator('[data-test-id="layers-panel"]').boundingBox(),
|
||||
'reloaded layers panel bounds'
|
||||
)
|
||||
expect(Math.abs(after.width - recordedWidth)).toBeLessThanOrEqual(2)
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ test.describe('Render performance', () => {
|
|||
{
|
||||
type: 'SOLID',
|
||||
color: {
|
||||
r: arr[i * 3]! / 255,
|
||||
g: arr[i * 3 + 1]! / 255,
|
||||
b: arr[i * 3 + 2]! / 255,
|
||||
r: (arr[i * 3] ?? 0) / 255,
|
||||
g: (arr[i * 3 + 1] ?? 0) / 255,
|
||||
b: (arr[i * 3 + 2] ?? 0) / 255,
|
||||
a: 1
|
||||
},
|
||||
visible: true,
|
||||
|
|
@ -89,7 +89,8 @@ test.describe('Render performance', () => {
|
|||
const results = await helper.page.evaluate((iterations: number) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const renderer = store.renderer!
|
||||
const renderer = store.renderer
|
||||
if (!renderer) throw new Error('OpenPencil renderer not initialized')
|
||||
|
||||
function setupRenderer() {
|
||||
renderer.dpr = window.devicePixelRatio || 1
|
||||
|
|
@ -119,11 +120,15 @@ test.describe('Render performance', () => {
|
|||
const panMs = performance.now() - panStart
|
||||
|
||||
// Benchmark 2: Scene change (cache miss every frame)
|
||||
const nodes = [...store.graph.getNode(store.state.currentPageId)!.childIds]
|
||||
const pageNode = store.graph.getNode(store.state.currentPageId)
|
||||
if (!pageNode) throw new Error(`Page ${store.state.currentPageId} not found`)
|
||||
const nodes = [...pageNode.childIds]
|
||||
setupRenderer()
|
||||
const sceneStart = performance.now()
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const node = store.graph.getNode(nodes[i % nodes.length]!)
|
||||
const nodeId = nodes[i % nodes.length]
|
||||
if (!nodeId) throw new Error('Benchmark node id not found')
|
||||
const node = store.graph.getNode(nodeId)
|
||||
if (node) store.graph.updateNode(node.id, { x: node.x + 0.1 })
|
||||
store.state.sceneVersion++
|
||||
renderer.render(store.graph, store.state.selectedIds, {}, store.state.sceneVersion)
|
||||
|
|
@ -177,7 +182,8 @@ test.describe('Render performance', () => {
|
|||
({ count, iterations }) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const renderer = store.renderer!
|
||||
const renderer = store.renderer
|
||||
if (!renderer) throw new Error('OpenPencil renderer not initialized')
|
||||
const graph = store.graph
|
||||
const pageId = store.state.currentPageId
|
||||
|
||||
|
|
@ -225,7 +231,9 @@ test.describe('Render performance', () => {
|
|||
setupRenderer()
|
||||
const sceneStart = performance.now()
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const node = graph.getNode(shadowIds[i % shadowIds.length]!)
|
||||
const nodeId = shadowIds[i % shadowIds.length]
|
||||
if (!nodeId) throw new Error('Shadow benchmark node id not found')
|
||||
const node = graph.getNode(nodeId)
|
||||
if (node) graph.updateNode(node.id, { x: node.x + 0.1 })
|
||||
store.state.sceneVersion++
|
||||
renderer.render(graph, store.state.selectedIds, {}, store.state.sceneVersion)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { expect, test, type Page } from '@playwright/test'
|
||||
|
||||
import { expectDefined } from '#tests/helpers/assert'
|
||||
import { CanvasHelper } from '#tests/helpers/canvas'
|
||||
import { getPageChildren, getSelectedNode } from '#tests/helpers/store'
|
||||
|
||||
|
|
@ -23,8 +24,7 @@ test('ScrubInput drag changes X position', async () => {
|
|||
await canvas.clearCanvas()
|
||||
await canvas.drawRect(100, 100, 80, 80)
|
||||
const before = await getSelectedNode(page)
|
||||
expect(before).not.toBeNull()
|
||||
const initialX = before!.x
|
||||
const initialX = expectDefined(before, 'selected rectangle before drag').x
|
||||
|
||||
const xScrub = page
|
||||
.locator('[data-test-id="position-section"] [data-test-id="scrub-input"]')
|
||||
|
|
@ -32,7 +32,7 @@ test('ScrubInput drag changes X position', async () => {
|
|||
await canvas.dragScrubInput(xScrub, 50)
|
||||
|
||||
const after = await getSelectedNode(page)
|
||||
expect(after!.x).not.toBe(initialX)
|
||||
expect(after?.x).not.toBe(initialX)
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ test('corner radius uniform sets cornerRadius', async () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const node = await getSelectedNode(page)
|
||||
expect(node!.cornerRadius).toBe(12)
|
||||
expect(node?.cornerRadius).toBe(12)
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
||||
|
|
@ -86,8 +86,8 @@ test('fill gradient switch changes fill type', async () => {
|
|||
await page.locator('[data-test-id="fill-picker-tab-gradient"]').click()
|
||||
await canvas.waitForRender()
|
||||
|
||||
const node = await getSelectedNode(page)
|
||||
expect(node!.fills[0].type).toBe('GRADIENT_LINEAR')
|
||||
const node = expectDefined(await getSelectedNode(page), 'gradient-filled node')
|
||||
expect(node.fills[0]?.type).toBe('GRADIENT_LINEAR')
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ test('flip horizontal sets flipX', async () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const node = await getSelectedNode(page)
|
||||
expect(node!.flipX).toBe(true)
|
||||
expect(node?.flipX).toBe(true)
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
||||
|
|
@ -260,13 +260,13 @@ test('clip content checkbox toggles clipsContent', async () => {
|
|||
await canvas.pressKey('Shift+a')
|
||||
await canvas.waitForRender()
|
||||
|
||||
const before = await getSelectedNode(page)
|
||||
const initialValue = before!.clipsContent
|
||||
const before = expectDefined(await getSelectedNode(page), 'selected frame before clipping')
|
||||
const initialValue = before.clipsContent
|
||||
|
||||
await page.locator('[data-test-id="clip-content-checkbox"]').click()
|
||||
await canvas.waitForRender()
|
||||
|
||||
const after = await getSelectedNode(page)
|
||||
expect(after!.clipsContent).toBe(!initialValue)
|
||||
expect(after?.clipsContent).toBe(!initialValue)
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { describe, test, expect } from 'bun:test'
|
|||
|
||||
import { createEditor } from '@open-pencil/core/editor'
|
||||
|
||||
import { getNodeOrThrow } from '#tests/helpers/assert'
|
||||
|
||||
describe('create shape undo/redo', () => {
|
||||
test('batched create+resize undoes in one step', () => {
|
||||
const editor = createEditor()
|
||||
|
|
@ -13,8 +15,8 @@ describe('create shape undo/redo', () => {
|
|||
editor.commitResize(id, { x: 100, y: 100, width: 0, height: 0 })
|
||||
editor.undo.commitBatch()
|
||||
|
||||
expect(editor.graph.getNode(id)!.width).toBe(200)
|
||||
expect(editor.graph.getNode(id)!.height).toBe(150)
|
||||
expect(getNodeOrThrow(editor.graph, id).width).toBe(200)
|
||||
expect(getNodeOrThrow(editor.graph, id).height).toBe(150)
|
||||
|
||||
// Single undo removes the shape entirely
|
||||
editor.undo.undo()
|
||||
|
|
@ -22,11 +24,11 @@ describe('create shape undo/redo', () => {
|
|||
|
||||
// Single redo restores with full dimensions
|
||||
editor.undo.redo()
|
||||
expect(editor.graph.getNode(id)).not.toBeUndefined()
|
||||
expect(editor.graph.getNode(id)!.width).toBe(200)
|
||||
expect(editor.graph.getNode(id)!.height).toBe(150)
|
||||
expect(editor.graph.getNode(id)!.x).toBe(100)
|
||||
expect(editor.graph.getNode(id)!.y).toBe(100)
|
||||
const restored = getNodeOrThrow(editor.graph, id)
|
||||
expect(restored.width).toBe(200)
|
||||
expect(restored.height).toBe(150)
|
||||
expect(restored.x).toBe(100)
|
||||
expect(restored.y).toBe(100)
|
||||
})
|
||||
|
||||
test('redo after create+move+duplicate restores correct state', () => {
|
||||
|
|
@ -46,7 +48,7 @@ describe('create shape undo/redo', () => {
|
|||
|
||||
// Undo move
|
||||
editor.undo.undo()
|
||||
expect(editor.graph.getNode(id)!.x).toBe(50)
|
||||
expect(getNodeOrThrow(editor.graph, id).x).toBe(50)
|
||||
|
||||
// Undo create (single step)
|
||||
editor.undo.undo()
|
||||
|
|
@ -54,10 +56,10 @@ describe('create shape undo/redo', () => {
|
|||
|
||||
// Redo create (single step, full dimensions)
|
||||
editor.undo.redo()
|
||||
expect(editor.graph.getNode(id)!.width).toBe(120)
|
||||
expect(getNodeOrThrow(editor.graph, id).width).toBe(120)
|
||||
|
||||
// Redo move
|
||||
editor.undo.redo()
|
||||
expect(editor.graph.getNode(id)!.x).toBe(200)
|
||||
expect(getNodeOrThrow(editor.graph, id).x).toBe(200)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { describe, expect, test } from 'bun:test'
|
|||
|
||||
import { ALL_TOOLS, FigmaAPI, SceneGraph, computeAllLayouts, parseFigFile } from '@open-pencil/core'
|
||||
|
||||
import { expectDefined } from '#tests/helpers/assert'
|
||||
|
||||
describe('MCP tool execution', () => {
|
||||
function setup() {
|
||||
const graph = new SceneGraph()
|
||||
|
|
@ -59,12 +61,11 @@ describe('MCP tool execution', () => {
|
|||
expect(result.type).toBe('FRAME')
|
||||
expect(result.name).toBe('TestFrame')
|
||||
|
||||
const node = api.getNodeById(result.id)
|
||||
expect(node).not.toBeNull()
|
||||
expect(node!.x).toBe(10)
|
||||
expect(node!.y).toBe(20)
|
||||
expect(node!.width).toBe(300)
|
||||
expect(node!.height).toBe(200)
|
||||
const node = expectDefined(api.getNodeById(result.id), 'created frame')
|
||||
expect(node.x).toBe(10)
|
||||
expect(node.y).toBe(20)
|
||||
expect(node.width).toBe(300)
|
||||
expect(node.height).toBe(200)
|
||||
})
|
||||
|
||||
test('set_fill applies color', () => {
|
||||
|
|
@ -78,7 +79,7 @@ describe('MCP tool execution', () => {
|
|||
}) as { id: string }
|
||||
|
||||
findTool('set_fill').execute(api, { id: frame.id, color: '#ff0000' })
|
||||
const node = api.getNodeById(frame.id)!
|
||||
const node = expectDefined(api.getNodeById(frame.id), 'filled rectangle')
|
||||
expect(node.fills).toHaveLength(1)
|
||||
expect(node.fills[0].color.r).toBeCloseTo(1)
|
||||
expect(node.fills[0].color.g).toBeCloseTo(0)
|
||||
|
|
@ -102,7 +103,7 @@ describe('MCP tool execution', () => {
|
|||
padding: 24
|
||||
})
|
||||
|
||||
const node = api.getNodeById(frame.id)!
|
||||
const node = expectDefined(api.getNodeById(frame.id), 'layout frame')
|
||||
expect(node.layoutMode).toBe('VERTICAL')
|
||||
expect(node.itemSpacing).toBe(16)
|
||||
expect(node.paddingTop).toBe(24)
|
||||
|
|
@ -133,9 +134,11 @@ describe('MCP tool execution', () => {
|
|||
const tree = findTool('get_page_tree').execute(api, {}) as {
|
||||
children: { id: string; children?: unknown[] }[]
|
||||
}
|
||||
const parentNode = tree.children.find((c: { id: string }) => c.id === parent.id)
|
||||
expect(parentNode).toBeDefined()
|
||||
expect(parentNode!.children).toBeArray()
|
||||
const parentNode = expectDefined(
|
||||
tree.children.find((c: { id: string }) => c.id === parent.id),
|
||||
'parent tree node'
|
||||
)
|
||||
expect(parentNode.children).toBeArray()
|
||||
})
|
||||
|
||||
test('delete_node removes node', () => {
|
||||
|
|
@ -195,7 +198,7 @@ describe('MCP tool execution', () => {
|
|||
|
||||
const clone = findTool('clone_node').execute(api, { id: frame.id }) as { id: string }
|
||||
expect(clone.id).not.toBe(frame.id)
|
||||
const clonedNode = api.getNodeById(clone.id)!
|
||||
const clonedNode = expectDefined(api.getNodeById(clone.id), 'cloned node')
|
||||
expect(clonedNode.width).toBe(100)
|
||||
expect(clonedNode.height).toBe(50)
|
||||
})
|
||||
|
|
@ -224,7 +227,7 @@ describe('MCP tool execution', () => {
|
|||
expect(result.updated).toContain('cornerRadius')
|
||||
expect(result.updated).toContain('name')
|
||||
|
||||
const node = api.getNodeById(frame.id)!
|
||||
const node = expectDefined(api.getNodeById(frame.id), 'updated node')
|
||||
expect(node.x).toBe(50)
|
||||
expect(node.opacity).toBe(0.5)
|
||||
expect(node.cornerRadius).toBe(8)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { describe, test, expect } from 'bun:test'
|
|||
|
||||
import { importNodeChanges, type NodeChange } from '@open-pencil/core'
|
||||
|
||||
import { expectDefined } from '#tests/helpers/assert'
|
||||
|
||||
const ID = { m00: 1, m01: 0, m02: 0, m10: 0, m11: 1, m12: 0 }
|
||||
const SIZE = { x: 100, y: 100 }
|
||||
|
||||
|
|
@ -85,7 +87,10 @@ function swapOverrideFixture(opts?: { customName?: string }): NodeChange[] {
|
|||
describe('instance swap overrides', () => {
|
||||
test('swap override renames icon and reclones children', () => {
|
||||
const graph = importNodeChanges(swapOverrideFixture())
|
||||
const page = graph.getPages().find((p) => p.name === 'Page1')!
|
||||
const page = expectDefined(
|
||||
graph.getPages().find((p) => p.name === 'Page1'),
|
||||
'Page1'
|
||||
)
|
||||
const button = graph.getChildren(page.id)[0]
|
||||
expect(button.name).toBe('ButtonInstance')
|
||||
|
||||
|
|
@ -100,7 +105,10 @@ describe('instance swap overrides', () => {
|
|||
|
||||
test('swap override preserves user-given name', () => {
|
||||
const graph = importNodeChanges(swapOverrideFixture({ customName: 'MyCustomIcon' }))
|
||||
const page = graph.getPages().find((p) => p.name === 'Page1')!
|
||||
const page = expectDefined(
|
||||
graph.getPages().find((p) => p.name === 'Page1'),
|
||||
'Page1'
|
||||
)
|
||||
const button = graph.getChildren(page.id)[0]
|
||||
const icon = graph.getChildren(button.id)[0]
|
||||
|
||||
|
|
@ -138,11 +146,16 @@ describe('instance swap overrides', () => {
|
|||
]
|
||||
|
||||
const graph = importNodeChanges(nodes)
|
||||
const page = graph.getPages().find((p) => p.name === 'Page1')!
|
||||
const page = expectDefined(
|
||||
graph.getPages().find((p) => p.name === 'Page1'),
|
||||
'Page1'
|
||||
)
|
||||
const children = graph.getChildren(page.id)
|
||||
|
||||
const wrapper = children.find((c) => c.name === 'WrapperInstance')!
|
||||
expect(wrapper).toBeDefined()
|
||||
const wrapper = expectDefined(
|
||||
children.find((c) => c.name === 'WrapperInstance'),
|
||||
'wrapper instance'
|
||||
)
|
||||
|
||||
// WrapperInstance > ButtonInstance > icon
|
||||
const wrapperButton = graph.getChildren(wrapper.id)[0]
|
||||
|
|
@ -168,14 +181,23 @@ describe('instance swap overrides', () => {
|
|||
]
|
||||
|
||||
const graph = importNodeChanges(nodes)
|
||||
const page = graph.getPages().find((p) => p.name === 'Page1')!
|
||||
const page = expectDefined(
|
||||
graph.getPages().find((p) => p.name === 'Page1'),
|
||||
'Page1'
|
||||
)
|
||||
const children = graph.getChildren(page.id)
|
||||
|
||||
const swapped = children.find((c) => c.name === 'ButtonInstance')!
|
||||
const swapped = expectDefined(
|
||||
children.find((c) => c.name === 'ButtonInstance'),
|
||||
'swapped button instance'
|
||||
)
|
||||
const swappedIcon = graph.getChildren(swapped.id)[0]
|
||||
expect(swappedIcon.name).toBe('IconB')
|
||||
|
||||
const defaultBtn = children.find((c) => c.name === 'ButtonDefault')!
|
||||
const defaultBtn = expectDefined(
|
||||
children.find((c) => c.name === 'ButtonDefault'),
|
||||
'default button instance'
|
||||
)
|
||||
const defaultIcon = graph.getChildren(defaultBtn.id)[0]
|
||||
expect(defaultIcon.name).toBe('IconA')
|
||||
})
|
||||
|
|
@ -226,7 +248,10 @@ describe('instance swap overrides', () => {
|
|||
]
|
||||
|
||||
const graph = importNodeChanges(nodes)
|
||||
const page = graph.getPages().find((p) => p.name === 'Page1')!
|
||||
const page = expectDefined(
|
||||
graph.getPages().find((p) => p.name === 'Page1'),
|
||||
'Page1'
|
||||
)
|
||||
const container = graph.getChildren(page.id)[0]
|
||||
|
||||
// ContainerInstance > ButtonSwapped > icon
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { describe, test, expect, beforeEach } from 'bun:test'
|
|||
import { FigmaAPI, SceneGraph } from '@open-pencil/core'
|
||||
import { importSvg } from '@open-pencil/core/tools'
|
||||
|
||||
import { expectDefined, getNodeOrThrow } from '#tests/helpers/assert'
|
||||
|
||||
let graph: SceneGraph
|
||||
let figma: FigmaAPI
|
||||
|
||||
|
|
@ -20,16 +22,17 @@ describe('import_svg', () => {
|
|||
expect(result.id).toBeDefined()
|
||||
expect(result.type).toBe('FRAME')
|
||||
|
||||
const frame = graph.getNode(result.id)
|
||||
expect(frame).not.toBeUndefined()
|
||||
expect(frame!.width).toBe(24)
|
||||
expect(frame!.height).toBe(24)
|
||||
const frame = getNodeOrThrow(graph, result.id)
|
||||
expect(frame.width).toBe(24)
|
||||
expect(frame.height).toBe(24)
|
||||
|
||||
const children = graph.getChildren(result.id)
|
||||
expect(children.length).toBe(1)
|
||||
expect(children[0].type).toBe('VECTOR')
|
||||
expect(children[0].vectorNetwork).toBeDefined()
|
||||
expect(children[0].vectorNetwork!.vertices.length).toBeGreaterThan(0)
|
||||
expect(
|
||||
expectDefined(children[0].vectorNetwork, 'imported vector network').vertices.length
|
||||
).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
test('imports multiple shapes', async () => {
|
||||
|
|
@ -51,9 +54,9 @@ describe('import_svg', () => {
|
|||
svg: '<svg viewBox="0 0 200 100"><path d="M0 0 L200 100"/></svg>'
|
||||
})) as { id: string }
|
||||
|
||||
const frame = graph.getNode(result.id)
|
||||
expect(frame!.width).toBe(200)
|
||||
expect(frame!.height).toBe(100)
|
||||
const frame = getNodeOrThrow(graph, result.id)
|
||||
expect(frame.width).toBe(200)
|
||||
expect(frame.height).toBe(100)
|
||||
})
|
||||
|
||||
test('uses width/height attributes when no viewBox', async () => {
|
||||
|
|
@ -61,9 +64,9 @@ describe('import_svg', () => {
|
|||
svg: '<svg width="48" height="48"><path d="M0 0 L48 48"/></svg>'
|
||||
})) as { id: string }
|
||||
|
||||
const frame = graph.getNode(result.id)
|
||||
expect(frame!.width).toBe(48)
|
||||
expect(frame!.height).toBe(48)
|
||||
const frame = getNodeOrThrow(graph, result.id)
|
||||
expect(frame.width).toBe(48)
|
||||
expect(frame.height).toBe(48)
|
||||
})
|
||||
|
||||
test('sets custom name', async () => {
|
||||
|
|
@ -116,9 +119,9 @@ describe('import_svg', () => {
|
|||
y: 200
|
||||
})) as { id: string }
|
||||
|
||||
const frame = graph.getNode(result.id)
|
||||
expect(frame!.x).toBe(100)
|
||||
expect(frame!.y).toBe(200)
|
||||
const frame = getNodeOrThrow(graph, result.id)
|
||||
expect(frame.x).toBe(100)
|
||||
expect(frame.y).toBe(200)
|
||||
})
|
||||
|
||||
test('returns error for empty SVG', async () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue