openpencil/tests/e2e/text/editing.spec.ts
Danila Poyarkov 39675b2969 chore(tests): remove easy non-null assertions
- Replace browser store non-null assertions with explicit initialization guards
- Use expectDefined for optional test resources and tool results
- Clean low-count non-null assertions in font, icon, snap, OKHCL, and visual tests
2026-05-06 02:59:56 +03:00

175 lines
4.9 KiB
TypeScript

import { expect, test, type Page } from '@playwright/test'
import { CanvasHelper } from '#tests/helpers/canvas'
let page: Page
let canvas: CanvasHelper
test.describe.configure({ mode: 'serial' })
test.beforeAll(async ({ browser }) => {
page = await browser.newPage()
await page.goto('/')
canvas = new CanvasHelper(page)
await canvas.waitForInit()
})
test.afterAll(async () => {
await page.close()
})
function getSelectedNode() {
return page.evaluate(() => {
const store = window.__OPEN_PENCIL_STORE__
if (!store) throw new Error('OpenPencil store not initialized')
const id = [...store.state.selectedIds][0]
if (!id) return null
const n = store.graph.getNode(id)
if (!n) return null
return {
id: n.id,
type: n.type,
name: n.name,
text: n.text,
fontSize: n.fontSize,
fontFamily: n.fontFamily,
fontWeight: n.fontWeight,
width: n.width,
height: n.height
}
})
}
function getPageChildren() {
return page.evaluate(() => {
const store = window.__OPEN_PENCIL_STORE__
if (!store) throw new Error('OpenPencil store not initialized')
return store.graph.getChildren(store.state.currentPageId).map((n) => ({
type: n.type,
name: n.name,
text: n.text
}))
})
}
test('pressing T activates text tool', async () => {
await page.keyboard.press('t')
const tool = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.activeTool)
expect(tool).toBe('TEXT')
})
test('clicking with text tool creates a text node', async () => {
await canvas.click(200, 200)
await canvas.waitForRender()
// Wait a tick for text editing mode to activate
await page.waitForTimeout(200)
const children = await getPageChildren()
const textNode = children.find((c) => c.type === 'TEXT')
expect(textNode).toBeTruthy()
})
test('text node is selected after creation', async () => {
const node = await getSelectedNode()
expect(node).toBeTruthy()
expect(node!.type).toBe('TEXT')
})
test('typography section appears for text node', async () => {
// Exit text editing mode
await page.keyboard.press('Escape')
await canvas.waitForRender()
// Re-select the text node
await canvas.click(200, 200)
await canvas.waitForRender()
const typoSection = page.locator('[data-test-id="typography-section"]')
await expect(typoSection).toBeVisible()
})
test('text node has default font properties', async () => {
const node = await getSelectedNode()
expect(node).toBeTruthy()
expect(node!.fontSize).toBeGreaterThan(0)
expect(node!.fontFamily).toBeTruthy()
})
test('creating text via store works', async () => {
await page.keyboard.press('Escape')
await canvas.waitForRender()
await page.evaluate(() => {
const store = window.__OPEN_PENCIL_STORE__
if (!store) throw new Error('OpenPencil store not initialized')
const id = store.createShape('TEXT', 100, 300, 200, 30)
store.graph.updateNode(id, { text: 'Hello World', fontSize: 24, fontFamily: 'Inter' })
store.select([id])
})
await canvas.waitForRender()
const node = await getSelectedNode()
expect(node!.text).toBe('Hello World')
expect(node!.fontSize).toBe(24)
})
test('undo removes text node', async () => {
const beforeCount = (await getPageChildren()).length
await canvas.undo()
await canvas.waitForRender()
const afterCount = (await getPageChildren()).length
expect(afterCount).toBe(beforeCount - 1)
})
test('frame tool creates FRAME node', async () => {
await page.keyboard.press('f')
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)
canvas.assertNoErrors()
})
test('Enter key opens text editing and selects all without erasing', async () => {
await page.keyboard.press('Escape')
await canvas.waitForRender()
const textId = await page.evaluate(() => {
const store = window.__OPEN_PENCIL_STORE__
if (!store) throw new Error('OpenPencil store not initialized')
const id = store.createShape('TEXT', 300, 300, 200, 30)
store.graph.updateNode(id, { text: 'Keep this text' })
store.select([id])
store.requestRender()
return id
})
await canvas.waitForRender()
const before = await getSelectedNode()
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)
expect(editing).toBe(textId)
const after = await page.evaluate(() => {
const store = window.__OPEN_PENCIL_STORE__
if (!store) throw new Error('OpenPencil store not initialized')
const id = store.state.editingTextId
if (!id) return null
return store.graph.getNode(id)?.text ?? null
})
expect(after).toBe('Keep this text')
})