chore(tests): guard text and keyboard lookups
- Replace non-null assertions in keyboard, text editing, and legacy fig import coverage - Add explicit store guards and expectDefined for optional test data - Validate check, legacy fig import, and keyboard E2E coverage
This commit is contained in:
parent
ac5bb4add3
commit
eba56fbe38
|
|
@ -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
|
||||
|
|
@ -19,11 +20,19 @@ test.afterAll(async () => {
|
|||
})
|
||||
|
||||
function getActiveTool() {
|
||||
return page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.activeTool)
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.activeTool
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
function getPageChildren() {
|
||||
|
|
@ -40,7 +49,19 @@ function getPageChildren() {
|
|||
}
|
||||
|
||||
function getUIVisible() {
|
||||
return page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.showUI)
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.showUI
|
||||
})
|
||||
}
|
||||
|
||||
function getZoom() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.zoom
|
||||
})
|
||||
}
|
||||
|
||||
test.describe('tool switching', () => {
|
||||
|
|
@ -125,11 +146,13 @@ test.describe('z-order shortcuts', () => {
|
|||
await canvas.drawRect(100, 100, 60, 60)
|
||||
|
||||
const childrenBefore = await getPageChildren()
|
||||
const firstId = childrenBefore[0].id
|
||||
const firstId = expectDefined(childrenBefore[0], 'first page child').id
|
||||
|
||||
// Select the first (bottom) node
|
||||
await page.evaluate((id) => {
|
||||
window.__OPEN_PENCIL_STORE__!.select([id])
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.select([id])
|
||||
}, firstId)
|
||||
await canvas.waitForRender()
|
||||
|
||||
|
|
@ -142,11 +165,13 @@ test.describe('z-order shortcuts', () => {
|
|||
|
||||
test('[ sends to back', async () => {
|
||||
const children = await getPageChildren()
|
||||
const lastId = children[children.length - 1].id
|
||||
const lastId = expectDefined(children.at(-1), 'last page child').id
|
||||
|
||||
// Select the last (top) node
|
||||
await page.evaluate((id) => {
|
||||
window.__OPEN_PENCIL_STORE__!.select([id])
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.select([id])
|
||||
}, lastId)
|
||||
await canvas.waitForRender()
|
||||
|
||||
|
|
@ -169,7 +194,7 @@ test.describe('group/ungroup shortcuts', () => {
|
|||
const children = await getPageChildren()
|
||||
const group = children.find((c) => c.type === 'GROUP')
|
||||
expect(group).toBeTruthy()
|
||||
expect(group!.childIds.length).toBeGreaterThanOrEqual(2)
|
||||
expect(group?.childIds.length).toBeGreaterThanOrEqual(2)
|
||||
})
|
||||
|
||||
test('⌘⇧G ungroups', async () => {
|
||||
|
|
@ -229,7 +254,7 @@ test.describe('zoom shortcuts', () => {
|
|||
await page.keyboard.press('Meta+0')
|
||||
await canvas.waitForRender()
|
||||
|
||||
const zoomAfter = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.zoom)
|
||||
const zoomAfter = await getZoom()
|
||||
expect(zoomAfter).toBe(1)
|
||||
})
|
||||
|
||||
|
|
@ -237,7 +262,7 @@ test.describe('zoom shortcuts', () => {
|
|||
await page.keyboard.press('Meta+1')
|
||||
await canvas.waitForRender()
|
||||
|
||||
const zoom = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.zoom)
|
||||
const zoom = await getZoom()
|
||||
expect(zoom).toBeGreaterThan(0)
|
||||
expect(zoom).toBeLessThanOrEqual(1)
|
||||
})
|
||||
|
|
@ -248,7 +273,7 @@ test.describe('zoom shortcuts', () => {
|
|||
await page.keyboard.press('Meta+2')
|
||||
await canvas.waitForRender()
|
||||
|
||||
const zoom = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.zoom)
|
||||
const zoom = await getZoom()
|
||||
expect(zoom).toBeGreaterThan(0)
|
||||
expect(zoom).toBeLessThanOrEqual(1)
|
||||
})
|
||||
|
|
@ -257,7 +282,7 @@ test.describe('zoom shortcuts', () => {
|
|||
await page.keyboard.press('Shift+1')
|
||||
await canvas.waitForRender()
|
||||
|
||||
const zoom = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.zoom)
|
||||
const zoom = await getZoom()
|
||||
expect(zoom).toBeGreaterThan(0)
|
||||
expect(zoom).toBeLessThanOrEqual(1)
|
||||
})
|
||||
|
|
@ -268,7 +293,7 @@ test.describe('zoom shortcuts', () => {
|
|||
await page.keyboard.press('Shift+2')
|
||||
await canvas.waitForRender()
|
||||
|
||||
const zoom = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.zoom)
|
||||
const zoom = await getZoom()
|
||||
expect(zoom).toBeGreaterThan(0)
|
||||
expect(zoom).toBeLessThanOrEqual(1)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -55,7 +56,11 @@ function getPageChildren() {
|
|||
test('pressing T activates text tool', async () => {
|
||||
await page.keyboard.press('t')
|
||||
|
||||
const tool = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.activeTool)
|
||||
const tool = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.activeTool
|
||||
})
|
||||
expect(tool).toBe('TEXT')
|
||||
})
|
||||
|
||||
|
|
@ -73,8 +78,7 @@ test('clicking with text tool creates a text node', async () => {
|
|||
|
||||
test('text node is selected after creation', async () => {
|
||||
const node = await getSelectedNode()
|
||||
expect(node).toBeTruthy()
|
||||
expect(node!.type).toBe('TEXT')
|
||||
expect(node?.type).toBe('TEXT')
|
||||
})
|
||||
|
||||
test('typography section appears for text node', async () => {
|
||||
|
|
@ -92,9 +96,8 @@ test('typography section appears for text node', async () => {
|
|||
|
||||
test('text node has default font properties', async () => {
|
||||
const node = await getSelectedNode()
|
||||
expect(node).toBeTruthy()
|
||||
expect(node!.fontSize).toBeGreaterThan(0)
|
||||
expect(node!.fontFamily).toBeTruthy()
|
||||
expect(node?.fontSize).toBeGreaterThan(0)
|
||||
expect(node?.fontFamily).toBeTruthy()
|
||||
})
|
||||
|
||||
test('creating text via store works', async () => {
|
||||
|
|
@ -111,8 +114,8 @@ test('creating text via store works', async () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const node = await getSelectedNode()
|
||||
expect(node!.text).toBe('Hello World')
|
||||
expect(node!.fontSize).toBe(24)
|
||||
expect(node?.text).toBe('Hello World')
|
||||
expect(node?.fontSize).toBe(24)
|
||||
})
|
||||
|
||||
test('undo removes text node', async () => {
|
||||
|
|
@ -130,10 +133,10 @@ test('frame tool creates FRAME node', async () => {
|
|||
await canvas.drag(400, 100, 600, 250)
|
||||
await canvas.waitForRender()
|
||||
|
||||
const node = await getSelectedNode()
|
||||
expect(node!.type).toBe('FRAME')
|
||||
expect(node!.width).toBeGreaterThan(0)
|
||||
expect(node!.height).toBeGreaterThan(0)
|
||||
const node = expectDefined(await getSelectedNode(), 'selected frame')
|
||||
expect(node.type).toBe('FRAME')
|
||||
expect(node.width).toBeGreaterThan(0)
|
||||
expect(node.height).toBeGreaterThan(0)
|
||||
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
|
@ -154,13 +157,17 @@ test('Enter key opens text editing and selects all without erasing', async () =>
|
|||
await canvas.waitForRender()
|
||||
|
||||
const before = await getSelectedNode()
|
||||
expect(before!.text).toBe('Keep this text')
|
||||
expect(before!.type).toBe('TEXT')
|
||||
expect(before?.text).toBe('Keep this text')
|
||||
expect(before?.type).toBe('TEXT')
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
const editing = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.editingTextId)
|
||||
const editing = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.editingTextId
|
||||
})
|
||||
expect(editing).toBe(textId)
|
||||
|
||||
const after = await page.evaluate(() => {
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
function doc(): NodeChange {
|
||||
return {
|
||||
guid: { sessionID: 0, localID: 0 },
|
||||
|
|
@ -125,8 +127,9 @@ describe('fig-import: gradient fills', () => {
|
|||
expect(n.fills).toHaveLength(1)
|
||||
expect(n.fills[0].type).toBe('GRADIENT_LINEAR')
|
||||
expect(n.fills[0].gradientStops).toHaveLength(2)
|
||||
expect(n.fills[0].gradientStops![0].color.r).toBe(1)
|
||||
expect(n.fills[0].gradientStops![1].color.b).toBe(1)
|
||||
const gradientStops = expectDefined(n.fills[0].gradientStops, 'linear gradient stops')
|
||||
expect(gradientStops[0]?.color.r).toBe(1)
|
||||
expect(gradientStops[1]?.color.b).toBe(1)
|
||||
expect(n.fills[0].gradientTransform).toBeDefined()
|
||||
})
|
||||
|
||||
|
|
@ -182,7 +185,7 @@ describe('fig-import: image fills', () => {
|
|||
const n = graph.getChildren(graph.getPages()[0].id)[0]
|
||||
expect(n.fills[0].type).toBe('IMAGE')
|
||||
expect(n.fills[0].imageHash).toBeDefined()
|
||||
expect(n.fills[0].imageHash!.length).toBe(40)
|
||||
expect(n.fills[0].imageHash?.length).toBe(40)
|
||||
expect(n.fills[0].imageScaleMode).toBe('FILL')
|
||||
})
|
||||
|
||||
|
|
@ -350,9 +353,10 @@ describe('fig-import: arc data', () => {
|
|||
])
|
||||
const n = graph.getChildren(graph.getPages()[0].id)[0]
|
||||
expect(n.arcData).toBeDefined()
|
||||
expect(n.arcData!.startingAngle).toBe(0)
|
||||
expect(n.arcData!.endingAngle).toBeCloseTo(Math.PI)
|
||||
expect(n.arcData!.innerRadius).toBe(0)
|
||||
const arcData = expectDefined(n.arcData, 'ellipse arc data')
|
||||
expect(arcData.startingAngle).toBe(0)
|
||||
expect(arcData.endingAngle).toBeCloseTo(Math.PI)
|
||||
expect(arcData.innerRadius).toBe(0)
|
||||
})
|
||||
|
||||
test('donut (inner radius)', () => {
|
||||
|
|
@ -368,7 +372,7 @@ describe('fig-import: arc data', () => {
|
|||
} as Partial<NodeChange>)
|
||||
])
|
||||
const n = graph.getChildren(graph.getPages()[0].id)[0]
|
||||
expect(n.arcData!.innerRadius).toBe(0.5)
|
||||
expect(n.arcData?.innerRadius).toBe(0.5)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -554,13 +558,19 @@ describe('fig-import: variable asset refs', () => {
|
|||
})
|
||||
])
|
||||
|
||||
const primary = [...graph.variables.values()].find((v) => v.name === 'Primary')!
|
||||
const resolved = graph.resolveColorVariable(primary.id)!
|
||||
const primary = expectDefined(
|
||||
[...graph.variables.values()].find((v) => v.name === 'Primary'),
|
||||
'Primary variable'
|
||||
)
|
||||
const resolved = expectDefined(graph.resolveColorVariable(primary.id), 'resolved Primary color')
|
||||
expect(resolved.r).toBeCloseTo(0.14)
|
||||
expect(resolved.g).toBeCloseTo(0.39)
|
||||
expect(resolved.b).toBeCloseTo(0.92)
|
||||
|
||||
const text = [...graph.getAllNodes()].find((n) => n.type === 'TEXT' && n.text === 'browse')!
|
||||
const text = expectDefined(
|
||||
[...graph.getAllNodes()].find((n) => n.type === 'TEXT' && n.text === 'browse'),
|
||||
'browse text node'
|
||||
)
|
||||
expect(text.fills[0].color.r).toBeCloseTo(0.14)
|
||||
expect(text.fills[0].color.g).toBeCloseTo(0.39)
|
||||
expect(text.fills[0].color.b).toBeCloseTo(0.92)
|
||||
|
|
|
|||
Loading…
Reference in a new issue