chore(lint): centralize OpenPencil window API
- Route browser globals through src/app/window-api.ts instead of private __OPEN_PENCIL fields - Move E2E tests to the public window.openPencil test API - Add an oxlint rule banning direct window.__OPEN_PENCIL* access
This commit is contained in:
parent
c7d2d0d0ad
commit
8ec70330b4
|
|
@ -1096,6 +1096,33 @@ const noFunctionAliasImports = {
|
|||
}
|
||||
}
|
||||
|
||||
const noDirectOpenPencilWindowInternals = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow direct access to private OpenPencil window internals'
|
||||
}
|
||||
},
|
||||
create(context) {
|
||||
function propertyName(property) {
|
||||
if (property?.type === 'Identifier') return property.name
|
||||
if (property?.type === 'Literal' && typeof property.value === 'string') return property.value
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
MemberExpression(node) {
|
||||
const name = propertyName(node.property)
|
||||
if (!name?.startsWith('__OPEN_PENCIL')) return
|
||||
context.report({
|
||||
node,
|
||||
message:
|
||||
'Do not access window.__OPEN_PENCIL* directly. Use src/app/window-api.ts or tests/helpers/store.ts instead.'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const noTopLevelPrefixedTestFiles = createProgramFilenameRule({
|
||||
description: 'Disallow top-level test files that encode domains as filename prefixes',
|
||||
check(file) {
|
||||
|
|
@ -1151,6 +1178,7 @@ const plugin = {
|
|||
'no-function-type': noFunctionType,
|
||||
'no-reflect-delete-global-this-outside-tests': noReflectDeleteGlobalThisOutsideTests,
|
||||
'no-core-browser-globals': noCoreBrowserGlobals,
|
||||
'no-direct-open-pencil-window-internals': noDirectOpenPencilWindowInternals,
|
||||
'no-direct-graph-emitter-subscriptions': noDirectGraphEmitterSubscriptions,
|
||||
'no-on-unmounted-in-composition-roots': noOnUnmountedInCompositionRoots,
|
||||
'no-composable-state-wrappers': noComposableStateWrappers,
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@
|
|||
"open-pencil/no-function-type": "error",
|
||||
"open-pencil/no-reflect-delete-global-this-outside-tests": "error",
|
||||
"open-pencil/no-core-browser-globals": "error",
|
||||
"open-pencil/no-direct-open-pencil-window-internals": "error",
|
||||
"open-pencil/no-function-alias-imports": "error",
|
||||
"open-pencil/max-composition-root-lines": [
|
||||
"error",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import {
|
|||
} from '@/app/ai/chat/storage'
|
||||
import { createChatSessionManager } from '@/app/ai/chat/transports'
|
||||
import { getActiveEditorStore } from '@/app/editor/active-store'
|
||||
import { setOpenPencilTransportFactorySetter } from '@/app/window-api'
|
||||
|
||||
const activeTab = ref<'design' | 'code' | 'ai'>('design')
|
||||
|
||||
|
|
@ -39,9 +40,9 @@ const chatSession = createChatSessionManager({
|
|||
registerAIChatEffects(chatSession.markTransportDirty)
|
||||
|
||||
if (IS_BROWSER) {
|
||||
window.__OPEN_PENCIL_SET_TRANSPORT__ = (factory) => {
|
||||
setOpenPencilTransportFactorySetter((factory) => {
|
||||
chatSession.setOverrideTransport(factory)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function useAIChat() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { useFileDialog } from '@vueuse/core'
|
|||
|
||||
import { openFileInNewTab } from '@/app/tabs'
|
||||
import { isTauri } from '@/app/tauri/env'
|
||||
import { setOpenPencilOpenFileHandler } from '@/app/window-api'
|
||||
import { IS_BROWSER } from '@/constants'
|
||||
|
||||
const fileDialog = useFileDialog({ accept: '.fig,.pen', multiple: false, reset: true })
|
||||
|
|
@ -12,15 +13,13 @@ fileDialog.onChange((files) => {
|
|||
})
|
||||
|
||||
if (IS_BROWSER && 'window' in globalThis) {
|
||||
;(
|
||||
globalThis.window as Window & { __OPEN_PENCIL_OPEN_FILE__?: (path: string) => Promise<void> }
|
||||
).__OPEN_PENCIL_OPEN_FILE__ = async (path: string) => {
|
||||
setOpenPencilOpenFileHandler(async (path: string) => {
|
||||
const response = await fetch(path)
|
||||
const blob = await response.blob()
|
||||
const name = path.split('/').pop() ?? 'file.fig'
|
||||
const file = new File([blob], name, { type: 'application/octet-stream' })
|
||||
await openFileInNewTab(file, undefined, path)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export async function readTauriDesignFile(path: string): Promise<File> {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import type { SceneGraph } from '@open-pencil/core/scene-graph'
|
|||
import { setActiveEditorStore } from '@/app/editor/active-store'
|
||||
import { createEditorStore } from '@/app/editor/session'
|
||||
import type { EditorStore } from '@/app/editor/session'
|
||||
import { setOpenPencilStore } from '@/app/window-api'
|
||||
|
||||
export interface Tab {
|
||||
id: string
|
||||
|
|
@ -52,7 +53,7 @@ function activateTab(tab: Tab) {
|
|||
activeTabId.value = tab.id
|
||||
setActiveEditorStore(tab.store)
|
||||
triggerRef(tabsRef)
|
||||
window.__OPEN_PENCIL_STORE__ = tab.store
|
||||
setOpenPencilStore(tab.store)
|
||||
}
|
||||
|
||||
export function switchTab(tabId: string) {
|
||||
|
|
|
|||
34
src/app/window-api.ts
Normal file
34
src/app/window-api.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import type { ChatTransport, UIMessage } from 'ai'
|
||||
|
||||
import type { EditorStore } from '@/app/editor/session/create'
|
||||
|
||||
export interface OpenPencilWindowAPI {
|
||||
store?: EditorStore
|
||||
setTransport?: (factory: () => ChatTransport<UIMessage>) => void
|
||||
openFile?: (path: string) => Promise<void>
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
openPencil?: OpenPencilWindowAPI
|
||||
}
|
||||
}
|
||||
|
||||
function windowApi(): OpenPencilWindowAPI {
|
||||
window.openPencil ??= {}
|
||||
return window.openPencil
|
||||
}
|
||||
|
||||
export function setOpenPencilStore(store: EditorStore) {
|
||||
windowApi().store = store
|
||||
}
|
||||
|
||||
export function setOpenPencilTransportFactorySetter(
|
||||
setTransport: (factory: () => ChatTransport<UIMessage>) => void
|
||||
) {
|
||||
windowApi().setTransport = setTransport
|
||||
}
|
||||
|
||||
export function setOpenPencilOpenFileHandler(openFile: (path: string) => Promise<void>) {
|
||||
windowApi().openFile = openFile
|
||||
}
|
||||
6
src/global.d.ts
vendored
6
src/global.d.ts
vendored
|
|
@ -1,6 +1,4 @@
|
|||
import type { ChatTransport, UIMessage } from 'ai'
|
||||
|
||||
import type { EditorStore } from '@/app/editor/session/create'
|
||||
export {}
|
||||
|
||||
declare global {
|
||||
interface Uint8ArrayConstructor {
|
||||
|
|
@ -40,8 +38,6 @@ declare global {
|
|||
blob(): Promise<Blob>
|
||||
}[]
|
||||
>
|
||||
__OPEN_PENCIL_SET_TRANSPORT__?(factory: () => ChatTransport<UIMessage>): void
|
||||
__OPEN_PENCIL_STORE__?: EditorStore
|
||||
__TEST_WRITE_COUNT__?(): number
|
||||
__TEST_MOCK_HANDLE__?: FileSystemFileHandle
|
||||
__savedOpen?: Window['open']
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ test('Object menu shows Group/Ungroup/Component', async () => {
|
|||
|
||||
function getStoreStateNumber(key: 'selectedIds' | 'zoom') {
|
||||
return page.evaluate((stateKey) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
if (stateKey === 'selectedIds') return store.state.selectedIds.size
|
||||
return store.state.zoom
|
||||
|
|
@ -110,7 +110,7 @@ test('Duplicate via Edit menu works', async () => {
|
|||
await canvas.drawRect(300, 300, 80, 80)
|
||||
|
||||
const countBefore = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getChildren(store.state.currentPageId).length
|
||||
})
|
||||
|
|
@ -120,7 +120,7 @@ test('Duplicate via Edit menu works', async () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const countAfter = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getChildren(store.state.currentPageId).length
|
||||
})
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ test('autosave triggers after scene changes with a file handle', async () => {
|
|||
|
||||
// Check that the scene version changed
|
||||
const versionAfterDraw = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.sceneVersion
|
||||
})
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ async function expectCanvas(name: string) {
|
|||
|
||||
async function createOverlayDemo(rotation: number) {
|
||||
await page.evaluate((frameRotation) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ test('rotation preview updates frame labels before mouse up', async () => {
|
|||
await createOverlayDemo(0)
|
||||
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const frameId = [...store.state.selectedIds][0]
|
||||
store.state.rotationPreview = { nodeId: frameId, angle: 28 }
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ test('resize corner handle drag increases node dimensions', async () => {
|
|||
expect(before).not.toBeNull()
|
||||
|
||||
const viewport = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
const n = store.graph.getNode(id)
|
||||
|
|
@ -132,7 +132,7 @@ test('rotation handle drag rotates node', async () => {
|
|||
const initialRotation = before!.rotation ?? 0
|
||||
|
||||
const viewport = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
const n = store.graph.getNode(id)
|
||||
|
|
@ -185,7 +185,7 @@ async function setupFrameChild(rotation: number) {
|
|||
await canvas.clearCanvas()
|
||||
|
||||
const setup = await page.evaluate((frameRotation) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const frameId = store.createShape('FRAME', 180, 160, 240, 160)
|
||||
if (!frameId) return null
|
||||
|
|
@ -203,7 +203,7 @@ async function setupFrameChild(rotation: number) {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const state = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
const pageNode = store.graph.getNode(pageId)
|
||||
|
|
@ -243,7 +243,7 @@ test('frame children keep correct hover and click hit area without rotation', as
|
|||
const state = await setupFrameChild(0)
|
||||
|
||||
await canvas.hover(state.hitX, state.hitY)
|
||||
const hoveredId = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.hoveredNodeId)
|
||||
const hoveredId = await page.evaluate(() => window.openPencil?.store!.state.hoveredNodeId)
|
||||
expect(hoveredId).toBe(state.childId)
|
||||
|
||||
await canvas.click(state.hitX, state.hitY)
|
||||
|
|
@ -252,7 +252,7 @@ test('frame children keep correct hover and click hit area without rotation', as
|
|||
expect(selected?.id).toBe(state.childId)
|
||||
|
||||
await canvas.hover(state.missX, state.missY)
|
||||
const hoveredMiss = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.hoveredNodeId)
|
||||
const hoveredMiss = await page.evaluate(() => window.openPencil?.store!.state.hoveredNodeId)
|
||||
expect(hoveredMiss).not.toBe(state.childId)
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
|
@ -261,7 +261,7 @@ test('rotated frame children keep correct hover and click hit area', async () =>
|
|||
const state = await setupFrameChild(35)
|
||||
|
||||
await canvas.hover(state.hitX, state.hitY)
|
||||
const hoveredId = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.hoveredNodeId)
|
||||
const hoveredId = await page.evaluate(() => window.openPencil?.store!.state.hoveredNodeId)
|
||||
expect(hoveredId).toBe(state.childId)
|
||||
|
||||
await canvas.click(state.hitX, state.hitY)
|
||||
|
|
@ -270,7 +270,7 @@ test('rotated frame children keep correct hover and click hit area', async () =>
|
|||
expect(selected?.id).toBe(state.childId)
|
||||
|
||||
await canvas.hover(state.missX, state.missY)
|
||||
const hoveredMiss = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.hoveredNodeId)
|
||||
const hoveredMiss = await page.evaluate(() => window.openPencil?.store!.state.hoveredNodeId)
|
||||
expect(hoveredMiss).not.toBe(state.childId)
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
|
@ -282,7 +282,7 @@ test('rotation drag exposes live rotation preview state', async () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const viewport = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
const n = store.graph.getNode(id)
|
||||
|
|
@ -309,15 +309,13 @@ test('rotation drag exposes live rotation preview state', async () => {
|
|||
await page.mouse.move(rx + 60, ry + 60, { steps: 15 })
|
||||
await canvas.waitForRender()
|
||||
|
||||
const preview = await page.evaluate(() => window.__OPEN_PENCIL_STORE__!.state.rotationPreview)
|
||||
const preview = await page.evaluate(() => window.openPencil?.store!.state.rotationPreview)
|
||||
expect(preview).not.toBeNull()
|
||||
|
||||
await page.mouse.up()
|
||||
await canvas.waitForRender()
|
||||
|
||||
const clearedPreview = await page.evaluate(
|
||||
() => window.__OPEN_PENCIL_STORE__!.state.rotationPreview
|
||||
)
|
||||
const clearedPreview = await page.evaluate(() => window.openPencil?.store!.state.rotationPreview)
|
||||
expect(clearedPreview).toBeNull()
|
||||
canvas.assertNoErrors()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ test.afterAll(async () => {
|
|||
|
||||
async function injectMockTransport(page: Page) {
|
||||
await page.evaluate(() => {
|
||||
const setTransport = window.__OPEN_PENCIL_SET_TRANSPORT__
|
||||
const setTransport = window.openPencil?.setTransport
|
||||
if (!setTransport) throw new Error('Transport override not available')
|
||||
|
||||
let msgCounter = 0
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ test.afterAll(async () => {
|
|||
|
||||
function getPageChildCount() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getChildren(store.state.currentPageId).length
|
||||
})
|
||||
|
|
@ -28,7 +28,7 @@ function getPageChildCount() {
|
|||
|
||||
function getSelectedCount() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.selectedIds.size
|
||||
})
|
||||
|
|
@ -36,7 +36,7 @@ function getSelectedCount() {
|
|||
|
||||
function getSelectedNodes() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return [...store.state.selectedIds].map((id) => {
|
||||
const n = store.graph.getNode(id)
|
||||
|
|
@ -62,7 +62,7 @@ test('copy + paste via store duplicates a shape', async () => {
|
|||
const countBefore = await getPageChildCount()
|
||||
|
||||
await page.evaluate(async () => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const data = new DataTransfer()
|
||||
await store.writeCopyData(data)
|
||||
|
|
@ -100,7 +100,7 @@ test('⌘D duplicates in place', async () => {
|
|||
test('duplicate preserves fills', async () => {
|
||||
// Set a custom fill on the selected node
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
store.updateNodeWithUndo(
|
||||
|
|
@ -136,7 +136,7 @@ test('cut removes original', async () => {
|
|||
|
||||
// Cut via store
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const data = new DataTransfer()
|
||||
store.writeCopyData(data)
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ test('deselecting shows empty state again', async () => {
|
|||
test('selecting a frame shows Frame in JSX', async () => {
|
||||
// Create a frame via store to avoid click-targeting issues
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = store.createShape('FRAME', 300, 100, 200, 200)
|
||||
store.select([id])
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ test.afterAll(async () => {
|
|||
|
||||
async function getSelectedFill() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
if (!id) return null
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ async function selectDemoCard(page: Parameters<typeof test>[0]['page'], canvas:
|
|||
await canvas.waitForInit()
|
||||
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const nodes = Array.from(store.graph.nodes.values())
|
||||
const card =
|
||||
|
|
@ -50,7 +50,7 @@ async function selectDemoCard(page: Parameters<typeof test>[0]['page'], canvas:
|
|||
|
||||
async function getSelectedFill(page: Parameters<typeof test>[0]['page']) {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
const node = store.graph.getNode(id)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ test.afterAll(async () => {
|
|||
|
||||
function getNodeById(id: string) {
|
||||
return page.evaluate((nodeId) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const n = store.graph.getNode(nodeId)
|
||||
if (!n) return null
|
||||
|
|
@ -29,12 +29,16 @@ function getNodeById(id: string) {
|
|||
}
|
||||
|
||||
function getSelectedIds() {
|
||||
return page.evaluate(() => [...window.__OPEN_PENCIL_STORE__!.state.selectedIds])
|
||||
return page.evaluate(() => {
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return [...store.state.selectedIds]
|
||||
})
|
||||
}
|
||||
|
||||
function getPageChildren() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getChildren(store.state.currentPageId).map((n) => ({
|
||||
id: n.id,
|
||||
|
|
@ -73,7 +77,7 @@ test('component visible in layers panel', async () => {
|
|||
expect(count).toBeGreaterThan(0)
|
||||
|
||||
const types = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getChildren(store.state.currentPageId).map((n) => n.type)
|
||||
})
|
||||
|
|
@ -87,7 +91,7 @@ test('create instance from component (context menu)', async () => {
|
|||
|
||||
// Use store directly to create instance
|
||||
await page.evaluate((compId) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.createInstanceFromComponent(compId, 300, 100)
|
||||
}, comp!.id)
|
||||
|
|
@ -104,7 +108,7 @@ test('instance shows INSTANCE type in design panel', async () => {
|
|||
const instance = children.find((c) => c.type === 'INSTANCE')!
|
||||
|
||||
await page.evaluate((id) => {
|
||||
window.__OPEN_PENCIL_STORE__!.select([id])
|
||||
window.openPencil?.store!.select([id])
|
||||
}, instance.id)
|
||||
await canvas.waitForRender()
|
||||
|
||||
|
|
@ -125,13 +129,13 @@ test('instance has "Detach" button', async () => {
|
|||
test('modifying component propagates to instance', async () => {
|
||||
// Select the component
|
||||
await page.evaluate((id) => {
|
||||
window.__OPEN_PENCIL_STORE__!.select([id])
|
||||
window.openPencil?.store!.select([id])
|
||||
}, componentId)
|
||||
await canvas.waitForRender()
|
||||
|
||||
// Change component fill
|
||||
await page.evaluate((id) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.updateNodeWithUndo(
|
||||
id,
|
||||
|
|
@ -155,7 +159,7 @@ test('modifying component propagates to instance', async () => {
|
|||
const children = await getPageChildren()
|
||||
const instance = children.find((c) => c.type === 'INSTANCE')!
|
||||
const instanceNode = await page.evaluate((id) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const n = store.graph.getNode(id)
|
||||
const child = store.graph.getChildren(id)[0]
|
||||
|
|
@ -170,12 +174,12 @@ test('detach instance converts to frame', async () => {
|
|||
const instance = children.find((c) => c.type === 'INSTANCE')!
|
||||
|
||||
await page.evaluate((id) => {
|
||||
window.__OPEN_PENCIL_STORE__!.select([id])
|
||||
window.openPencil?.store!.select([id])
|
||||
}, instance.id)
|
||||
await canvas.waitForRender()
|
||||
|
||||
await page.evaluate(() => {
|
||||
window.__OPEN_PENCIL_STORE__!.detachInstance()
|
||||
window.openPencil?.store!.detachInstance()
|
||||
})
|
||||
await canvas.waitForRender()
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ test.afterAll(async () => {
|
|||
|
||||
function getPageChildren() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getChildren(store.state.currentPageId).map((n) => ({
|
||||
id: n.id,
|
||||
|
|
@ -35,7 +35,7 @@ function getPageChildren() {
|
|||
|
||||
function getSelectedCount() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.selectedIds.size
|
||||
})
|
||||
|
|
@ -110,7 +110,7 @@ test('toggle visibility via context menu', async () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const nodeId = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return [...store.state.selectedIds][0]
|
||||
})
|
||||
|
|
@ -120,7 +120,7 @@ test('toggle visibility via context menu', async () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const hidden = await page.evaluate((id) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const n = store.graph.getNode(id)
|
||||
return n ? { visible: n.visible } : null
|
||||
|
|
@ -129,14 +129,14 @@ test('toggle visibility via context menu', async () => {
|
|||
|
||||
// Toggle back: select via store since invisible nodes can't be hit-tested
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.toggleVisibility()
|
||||
})
|
||||
await canvas.waitForRender()
|
||||
|
||||
const restored = await page.evaluate((id) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const n = store.graph.getNode(id)
|
||||
return n ? { visible: n.visible } : null
|
||||
|
|
@ -192,7 +192,7 @@ test('group via context menu', async () => {
|
|||
test('ungroup via store after context-menu group', async () => {
|
||||
// Groups are click-through, so ungroup via store instead
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const group = store.graph.getChildren(store.state.currentPageId).find((n) => n.type === 'GROUP')
|
||||
if (group) store.select([group.id])
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ function effectsSection() {
|
|||
|
||||
function getNode(id: string) {
|
||||
return page.evaluate((nodeId) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const n = store.graph.getNode(nodeId)
|
||||
if (!n) return null
|
||||
|
|
@ -65,7 +65,7 @@ function getNode(id: string) {
|
|||
|
||||
function getSelectedId() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return [...store.state.selectedIds][0] ?? null
|
||||
})
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ test.afterAll(async () => {
|
|||
async function selectFrame() {
|
||||
expect(frameId, 'frameId must be set — did the Shift+A test run?').toBeTruthy()
|
||||
await page.evaluate((id: string) => {
|
||||
window.__OPEN_PENCIL_STORE__!.select([id])
|
||||
window.openPencil?.store!.select([id])
|
||||
}, frameId)
|
||||
await canvas.waitForRender()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ test.beforeEach(async () => {
|
|||
|
||||
async function rectangleCount() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return [...store.graph.nodes.values()].filter((node) => node.type === 'RECTANGLE').length
|
||||
})
|
||||
|
|
@ -36,7 +36,7 @@ async function layerItems() {
|
|||
|
||||
async function historyState() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return {
|
||||
canUndo: store.undo.canUndo,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ test('font settings popover is available from typography panel', async ({ page }
|
|||
await canvas.waitForInit()
|
||||
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = store.createShape('TEXT', 120, 120, 240, 40)
|
||||
store.updateNode(id, { characters: 'Font settings smoke' })
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ test.afterAll(async () => {
|
|||
|
||||
function getActiveTool() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.activeTool
|
||||
})
|
||||
|
|
@ -29,7 +29,7 @@ function getActiveTool() {
|
|||
|
||||
function getSelectedCount() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.selectedIds.size
|
||||
})
|
||||
|
|
@ -37,7 +37,7 @@ function getSelectedCount() {
|
|||
|
||||
function getPageChildren() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getChildren(store.state.currentPageId).map((n) => ({
|
||||
id: n.id,
|
||||
|
|
@ -50,7 +50,7 @@ function getPageChildren() {
|
|||
|
||||
function getUIVisible() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.showUI
|
||||
})
|
||||
|
|
@ -58,7 +58,7 @@ function getUIVisible() {
|
|||
|
||||
function getZoom() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.zoom
|
||||
})
|
||||
|
|
@ -150,7 +150,7 @@ test.describe('z-order shortcuts', () => {
|
|||
|
||||
// Select the first (bottom) node
|
||||
await page.evaluate((id) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.select([id])
|
||||
}, firstId)
|
||||
|
|
@ -169,7 +169,7 @@ test.describe('z-order shortcuts', () => {
|
|||
|
||||
// Select the last (top) node
|
||||
await page.evaluate((id) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.select([id])
|
||||
}, lastId)
|
||||
|
|
@ -245,7 +245,7 @@ test.describe('zoom shortcuts', () => {
|
|||
|
||||
// Set zoom to something other than 100%
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.state.zoom = 2
|
||||
})
|
||||
|
|
@ -327,7 +327,7 @@ test.describe('auto-layout shortcut', () => {
|
|||
|
||||
// Change to frame type for auto-layout
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const nodes = [...store.state.selectedIds]
|
||||
if (nodes[0]) store.updateNode(nodes[0], { type: 'FRAME' })
|
||||
|
|
@ -335,7 +335,7 @@ test.describe('auto-layout shortcut', () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const layoutBefore = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const nodes = [...store.state.selectedIds]
|
||||
return store.graph.getNode(nodes[0])?.layoutMode
|
||||
|
|
@ -346,7 +346,7 @@ test.describe('auto-layout shortcut', () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const layoutAfter = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const nodes = [...store.state.selectedIds]
|
||||
return store.graph.getNode(nodes[0])?.layoutMode
|
||||
|
|
@ -358,7 +358,7 @@ test.describe('auto-layout shortcut', () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
const layoutFinal = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const nodes = [...store.state.selectedIds]
|
||||
return store.graph.getNode(nodes[0])?.layoutMode
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ interface SceneTreeNode {
|
|||
|
||||
async function getSceneTree(): Promise<SceneTreeNode> {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) return null
|
||||
|
||||
function nodeTree(id: string): SceneTreeNode | null {
|
||||
|
|
@ -61,7 +61,7 @@ async function getSceneTree(): Promise<SceneTreeNode> {
|
|||
|
||||
async function getSelectedCount(): Promise<number> {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.selectedIds.size
|
||||
})
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ test.afterAll(async () => {
|
|||
|
||||
function getPages() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getPages().map((p) => ({ id: p.id, name: p.name }))
|
||||
})
|
||||
|
|
@ -28,7 +28,7 @@ function getPages() {
|
|||
|
||||
function getCurrentPageId() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.currentPageId
|
||||
})
|
||||
|
|
@ -36,7 +36,7 @@ function getCurrentPageId() {
|
|||
|
||||
function getPageChildCount() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getChildren(store.state.currentPageId).length
|
||||
})
|
||||
|
|
@ -126,7 +126,7 @@ test('delete current page switches to adjacent', async () => {
|
|||
const deletingId = await getCurrentPageId()
|
||||
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.deletePage(store.state.currentPageId)
|
||||
})
|
||||
|
|
@ -145,7 +145,7 @@ test('rename page via store', async () => {
|
|||
|
||||
await page.evaluate(
|
||||
([id, name]) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.renamePage(id, name)
|
||||
},
|
||||
|
|
@ -200,7 +200,7 @@ test('cannot delete the last page', async () => {
|
|||
let pages = await getPages()
|
||||
while (pages.length > 1) {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.deletePage(store.state.currentPageId)
|
||||
})
|
||||
|
|
@ -212,7 +212,7 @@ test('cannot delete the last page', async () => {
|
|||
|
||||
// Try deleting the last one — should be a no-op
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.deletePage(store.state.currentPageId)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ test.describe('Render performance', () => {
|
|||
await helper.waitForInit()
|
||||
|
||||
await page.evaluate((count: number) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const arr = new Uint8Array(count * 3)
|
||||
crypto.getRandomValues(arr)
|
||||
|
|
@ -87,7 +87,7 @@ test.describe('Render performance', () => {
|
|||
|
||||
test('benchmark: synchronous render throughput', async () => {
|
||||
const results = await helper.page.evaluate((iterations: number) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const renderer = store.renderer
|
||||
if (!renderer) throw new Error('OpenPencil renderer not initialized')
|
||||
|
|
@ -180,7 +180,7 @@ test.describe('Render performance', () => {
|
|||
|
||||
const results = await helper.page.evaluate(
|
||||
({ count, iterations }) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const renderer = store.renderer
|
||||
if (!renderer) throw new Error('OpenPencil renderer not initialized')
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ test.afterAll(async () => {
|
|||
|
||||
async function getSelectedNodeFlags() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
if (!id) return null
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ async function expectCanvas(name: string) {
|
|||
|
||||
test('drop shadow on white card', async () => {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
store.graph.createNode('FRAME', pageId, {
|
||||
|
|
@ -61,7 +61,7 @@ test('drop shadow on white card', async () => {
|
|||
|
||||
test('drop shadow with spread', async () => {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
store.graph.createNode('FRAME', pageId, {
|
||||
|
|
@ -92,7 +92,7 @@ test('drop shadow with spread', async () => {
|
|||
|
||||
test('inner shadow', async () => {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
store.graph.createNode('FRAME', pageId, {
|
||||
|
|
@ -125,7 +125,7 @@ test('inner shadow', async () => {
|
|||
|
||||
test('inner shadow with spread', async () => {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
store.graph.createNode('FRAME', pageId, {
|
||||
|
|
@ -158,7 +158,7 @@ test('inner shadow with spread', async () => {
|
|||
|
||||
test('drop shadow on ellipse', async () => {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
store.graph.createNode('ELLIPSE', pageId, {
|
||||
|
|
@ -190,7 +190,7 @@ test('drop shadow on ellipse', async () => {
|
|||
|
||||
test('combined drop and inner shadow', async () => {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
store.graph.createNode('FRAME', pageId, {
|
||||
|
|
@ -229,7 +229,7 @@ test('combined drop and inner shadow', async () => {
|
|||
|
||||
test('text drop shadow on glyphs', async () => {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
store.graph.createNode('TEXT', pageId, {
|
||||
|
|
@ -265,7 +265,7 @@ test('text drop shadow on glyphs', async () => {
|
|||
|
||||
test('layer blur', async () => {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
store.graph.createNode('RECTANGLE', pageId, {
|
||||
|
|
@ -298,7 +298,7 @@ test('layer blur', async () => {
|
|||
|
||||
test('invisible effect has no visual impact', async () => {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
store.graph.createNode('FRAME', pageId, {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ test('variable bind badge appears on fill', async () => {
|
|||
await canvas.drawRect(200, 200, 80, 80)
|
||||
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const col = store.graph.createCollection('Colors')
|
||||
const v = store.graph.createVariable('brand-red', 'COLOR', col.id, { r: 1, g: 0, b: 0, a: 1 })
|
||||
|
|
@ -116,7 +116,7 @@ test('fill color can bind an existing variable', async () => {
|
|||
await canvas.drawRect(200, 200, 80, 80)
|
||||
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const col = store.graph.createCollection('Colors')
|
||||
const variable = store.graph.createVariable('test-brand-red', 'COLOR', col.id, {
|
||||
|
|
@ -145,7 +145,7 @@ test('fill color can bind an existing variable', async () => {
|
|||
await canvas.waitForRender()
|
||||
await expect(page.locator('[data-test-id="fill-unbind-variable"]')).toBeHidden()
|
||||
const boundVariableId = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
return id ? (store.getNode(id)?.boundVariables['fills/0/color'] ?? null) : null
|
||||
|
|
@ -167,7 +167,7 @@ test('fill color can create and bind a variable', async () => {
|
|||
|
||||
await expect(page.locator('[data-test-id="fill-unbind-variable"]')).toBeVisible()
|
||||
const boundVariable = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
if (!id) return null
|
||||
|
|
@ -193,7 +193,7 @@ test('width can create, bind, and detach a number variable', async () => {
|
|||
|
||||
await expect(page.locator('[data-test-id="layout-width-unbind-variable"]')).toBeVisible()
|
||||
const boundVariable = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
if (!id) return null
|
||||
|
|
@ -212,7 +212,7 @@ test('width can create, bind, and detach a number variable', async () => {
|
|||
|
||||
await expect(page.locator('[data-test-id="layout-width-unbind-variable"]')).toBeHidden()
|
||||
const directWidth = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
const node = id ? store.getNode(id) : null
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ test.afterAll(async () => {
|
|||
|
||||
function getSelectedNode() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
if (!id) return null
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
await helper.waitForInit()
|
||||
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageId = store.state.currentPageId
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
// We simulate this by calling invalidateScenePicture() to force the next
|
||||
// render to re-record, then verify hover on/off doesn't lose text.
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
// Simulate what loadFonts() does: invalidate the cached picture
|
||||
store.renderer!.invalidateScenePicture()
|
||||
|
|
@ -85,7 +85,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
|
||||
// Extra render to stabilize the SkPicture cache
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.requestRender()
|
||||
})
|
||||
|
|
@ -96,7 +96,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
|
||||
// Hover frame → un-hover: replays the newly recorded picture
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pg = store.graph.getNode(store.state.currentPageId)!
|
||||
const frame = pg.childIds.find((id: string) => store.graph.getNode(id)?.type === 'FRAME')
|
||||
|
|
@ -105,7 +105,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
await helper.waitForRender()
|
||||
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.setHoveredNode(null)
|
||||
})
|
||||
|
|
@ -118,7 +118,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
test('text survives hover on/off cycle', async () => {
|
||||
// 1. Baseline: no hover — this records the SkPicture cache
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.setHoveredNode(null)
|
||||
store.requestRender()
|
||||
|
|
@ -126,7 +126,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
await helper.waitForRender()
|
||||
// Extra render cycle to ensure SkPicture cache is fully recorded
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.requestRender()
|
||||
})
|
||||
|
|
@ -135,7 +135,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
|
||||
// 2. Hover a frame — uses requestRepaint (only renderVersion, not sceneVersion)
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const page = store.graph.getNode(store.state.currentPageId)!
|
||||
const frame = page.childIds.find((id: string) => store.graph.getNode(id)?.type === 'FRAME')
|
||||
|
|
@ -145,7 +145,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
|
||||
// 3. Hover off — should replay cached SkPicture (the critical transition)
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.setHoveredNode(null)
|
||||
})
|
||||
|
|
@ -160,7 +160,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
test('text survives multiple hover cycles', async () => {
|
||||
// Rapid hover on/off using the real setHoveredNode path (requestRepaint)
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const page = store.graph.getNode(store.state.currentPageId)!
|
||||
const frame = page.childIds.find((id: string) => store.graph.getNode(id)?.type === 'FRAME')
|
||||
|
|
@ -178,7 +178,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
test('text survives real mouse hover on/off', async () => {
|
||||
// Use actual mouse movement instead of programmatic setHoveredNode
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.setHoveredNode(null)
|
||||
store.requestRender()
|
||||
|
|
@ -194,7 +194,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
|
||||
// Move mouse to empty area (far from any node)
|
||||
await helper.page.mouse.move(box!.x + 800, box!.y + 600)
|
||||
await helper.page.evaluate(() => window.__OPEN_PENCIL_STORE__!.setHoveredNode(null))
|
||||
await helper.page.evaluate(() => window.openPencil?.store!.setHoveredNode(null))
|
||||
await helper.waitForRender()
|
||||
await helper.page.waitForTimeout(100)
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
test('text survives scene change then hover cycle', async () => {
|
||||
// Mutate scene to invalidate picture cache
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const page = store.graph.getNode(store.state.currentPageId)!
|
||||
const frame = page.childIds.find((id: string) => store.graph.getNode(id)?.type === 'FRAME')
|
||||
|
|
@ -217,7 +217,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
|
||||
// Hover on then off using real path
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const page = store.graph.getNode(store.state.currentPageId)!
|
||||
const frame = page.childIds.find((id: string) => store.graph.getNode(id)?.type === 'FRAME')
|
||||
|
|
@ -226,7 +226,7 @@ test.describe('SkPicture scene caching', () => {
|
|||
await helper.waitForRender()
|
||||
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.setHoveredNode(null)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ test.afterAll(async () => {
|
|||
async function createRects() {
|
||||
await canvas.clearCanvas()
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.createShape('RECTANGLE', 100, 100, 80, 80)
|
||||
const b = store.createShape('RECTANGLE', 300, 100, 80, 80)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ async function chooseFormat(page: Page, label: 'RGB' | 'HSL' | 'HSB' | 'OkHCL')
|
|||
|
||||
async function getSelectedStroke(page: Page) {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
const node = store.graph.getNode(id)
|
||||
|
|
@ -88,7 +88,7 @@ test('stroke picker hsb saturation and brightness sliders update stroke color on
|
|||
await canvas.waitForInit()
|
||||
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const nodes = Array.from(store.graph.nodes.values())
|
||||
const card =
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ test.afterAll(async () => {
|
|||
|
||||
function getSelectedNode() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
if (!id) return null
|
||||
|
|
@ -43,7 +43,7 @@ function getSelectedNode() {
|
|||
|
||||
function getPageChildren() {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getChildren(store.state.currentPageId).map((n) => ({
|
||||
type: n.type,
|
||||
|
|
@ -57,7 +57,7 @@ test('pressing T activates text tool', async () => {
|
|||
await page.keyboard.press('t')
|
||||
|
||||
const tool = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.activeTool
|
||||
})
|
||||
|
|
@ -105,7 +105,7 @@ test('creating text via store works', async () => {
|
|||
await canvas.waitForRender()
|
||||
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.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' })
|
||||
|
|
@ -146,7 +146,7 @@ test('Enter key opens text editing and selects all without erasing', async () =>
|
|||
await canvas.waitForRender()
|
||||
|
||||
const textId = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.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' })
|
||||
|
|
@ -164,14 +164,14 @@ test('Enter key opens text editing and selects all without erasing', async () =>
|
|||
await page.waitForTimeout(200)
|
||||
|
||||
const editing = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.editingTextId
|
||||
})
|
||||
expect(editing).toBe(textId)
|
||||
|
||||
const after = await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = store.state.editingTextId
|
||||
if (!id) return null
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ test.beforeAll(async ({ browser }) => {
|
|||
await canvas.clearCanvas()
|
||||
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.state.zoom = 1
|
||||
store.state.panX = 0
|
||||
|
|
@ -54,7 +54,7 @@ test('bold button toggles fontWeight to 700 then back to 400', async () => {
|
|||
|
||||
// ensure starting weight is 400 via undo-safe store method
|
||||
await page.evaluate(async (id: string) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.updateNodeWithUndo(id, { fontWeight: 400 }, 'reset')
|
||||
store.state.sceneVersion++
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ test('draw section in full editor without browser errors', async () => {
|
|||
await expect
|
||||
.poll(async () => {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
const selectedId = [...store.state.selectedIds][0]
|
||||
return selectedId ? store.graph.getNode(selectedId)?.type : null
|
||||
})
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ test.afterAll(async () => {
|
|||
|
||||
async function createColorVariable(name: string) {
|
||||
return page.evaluate((varName: string) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const existing = [...store.graph.variableCollections.values()]
|
||||
const col = existing.length > 0 ? existing[0] : store.graph.createCollection('Test Collection')
|
||||
|
|
@ -44,7 +44,7 @@ test('variables dialog opens', async () => {
|
|||
|
||||
test('search filters variable rows', async () => {
|
||||
await page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const col = [...store.graph.variableCollections.values()][0]
|
||||
store.graph.createVariable('beta-spacing', 'FLOAT', col.id, 8)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ test.describe('Zoom and pan', () => {
|
|||
await helper.waitForInit()
|
||||
|
||||
await page.evaluate((count: number) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const cols = Math.ceil(Math.sqrt(count))
|
||||
for (let i = 0; i < count; i++) {
|
||||
|
|
@ -40,7 +40,7 @@ test.describe('Zoom and pan', () => {
|
|||
|
||||
test('wheel zoom updates viewport correctly', async () => {
|
||||
const before = await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return { panX: store.state.panX, panY: store.state.panY, zoom: store.state.zoom }
|
||||
})
|
||||
|
|
@ -55,7 +55,7 @@ test.describe('Zoom and pan', () => {
|
|||
await helper.page.waitForTimeout(50)
|
||||
|
||||
const after = await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return { panX: store.state.panX, panY: store.state.panY, zoom: store.state.zoom }
|
||||
})
|
||||
|
|
@ -66,7 +66,7 @@ test.describe('Zoom and pan', () => {
|
|||
|
||||
test('wheel pan updates viewport correctly', async () => {
|
||||
const before = await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return { panX: store.state.panX, panY: store.state.panY }
|
||||
})
|
||||
|
|
@ -80,7 +80,7 @@ test.describe('Zoom and pan', () => {
|
|||
await helper.page.waitForTimeout(50)
|
||||
|
||||
const after = await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return { panX: store.state.panX, panY: store.state.panY }
|
||||
})
|
||||
|
|
@ -102,7 +102,7 @@ test.describe('Zoom and pan', () => {
|
|||
await helper.page.waitForTimeout(50)
|
||||
|
||||
const state = await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return { zoom: store.state.zoom }
|
||||
})
|
||||
|
|
@ -114,7 +114,7 @@ test.describe('Zoom and pan', () => {
|
|||
|
||||
test('shallowReactive: selection replace triggers UI update', async () => {
|
||||
const result = await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageNode = store.graph.getNode(store.state.currentPageId)
|
||||
if (!pageNode) throw new Error(`Page ${store.state.currentPageId} not found`)
|
||||
|
|
@ -139,7 +139,7 @@ test.describe('Zoom and pan', () => {
|
|||
test('useRafFn loop picks up renderVersion changes', async () => {
|
||||
// Ensure clean state, wait for any pending renders
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.state.panX = 0
|
||||
store.state.panY = 0
|
||||
|
|
@ -153,7 +153,7 @@ test.describe('Zoom and pan', () => {
|
|||
|
||||
// Change fill color — always visible
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageNode = store.graph.getNode(store.state.currentPageId)
|
||||
if (!pageNode) throw new Error(`Page ${store.state.currentPageId} not found`)
|
||||
|
|
@ -172,7 +172,7 @@ test.describe('Zoom and pan', () => {
|
|||
|
||||
// Restore
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageNode = store.graph.getNode(store.state.currentPageId)
|
||||
if (!pageNode) throw new Error(`Page ${store.state.currentPageId} not found`)
|
||||
|
|
@ -192,7 +192,7 @@ test.describe('Zoom and pan', () => {
|
|||
const before = await helper.screenshotCanvas()
|
||||
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const pageNode = store.graph.getNode(store.state.currentPageId)
|
||||
if (!pageNode) throw new Error(`Page ${store.state.currentPageId} not found`)
|
||||
|
|
@ -208,7 +208,7 @@ test.describe('Zoom and pan', () => {
|
|||
expect(Buffer.from(before)).not.toEqual(Buffer.from(after))
|
||||
|
||||
await helper.page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
store.clearSelection()
|
||||
})
|
||||
|
|
@ -219,7 +219,7 @@ test.describe('Zoom and pan', () => {
|
|||
const ITERATIONS = 500
|
||||
|
||||
const results = await helper.page.evaluate((iterations: number) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
|
||||
// Reset viewport
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { Page } from '@playwright/test'
|
|||
|
||||
export function getSelectedIds(page: Page) {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.selectedIds.size
|
||||
})
|
||||
|
|
@ -10,7 +10,7 @@ export function getSelectedIds(page: Page) {
|
|||
|
||||
export function getPageChildren(page: Page) {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.graph.getChildren(store.state.currentPageId).map((n) => ({
|
||||
id: n.id,
|
||||
|
|
@ -28,7 +28,7 @@ export function getPageChildren(page: Page) {
|
|||
|
||||
export function getSelectedNode(page: Page) {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const id = [...store.state.selectedIds][0]
|
||||
if (!id) return null
|
||||
|
|
@ -59,7 +59,7 @@ export function getSelectedNode(page: Page) {
|
|||
|
||||
export function getNodeById(page: Page, id: string) {
|
||||
return page.evaluate((nodeId: string) => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
const n = store.graph.getNode(nodeId)
|
||||
if (!n) return null
|
||||
|
|
@ -99,7 +99,7 @@ export function getNodeById(page: Page, id: string) {
|
|||
|
||||
export function getEditingTextId(page: Page) {
|
||||
return page.evaluate(() => {
|
||||
const store = window.__OPEN_PENCIL_STORE__
|
||||
const store = window.openPencil?.store
|
||||
if (!store) throw new Error('OpenPencil store not initialized')
|
||||
return store.state.editingTextId
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue