2026-05-16 13:19:03 +00:00
|
|
|
import { expect, test, useEditorSetup } from '#tests/e2e/fixtures'
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
|
2026-05-16 13:19:03 +00:00
|
|
|
const editor = useEditorSetup()
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
|
|
|
|
|
function codeTab() {
|
2026-05-16 13:19:03 +00:00
|
|
|
return editor.page.getByTestId('properties-tab-code')
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function designTab() {
|
2026-05-16 13:19:03 +00:00
|
|
|
return editor.page.getByTestId('properties-tab-design')
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function codePanel() {
|
2026-05-16 13:19:03 +00:00
|
|
|
return editor.page.getByTestId('code-panel')
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function codePanelEmpty() {
|
2026-05-16 13:19:03 +00:00
|
|
|
return editor.page.getByTestId('code-panel-empty')
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatToggle() {
|
2026-05-16 13:19:03 +00:00
|
|
|
return editor.page.getByTestId('code-panel-format-toggle')
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function copyButton() {
|
2026-05-16 13:19:03 +00:00
|
|
|
return editor.page.getByTestId('code-panel-copy')
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test('Code tab shows empty state with no selection', async () => {
|
|
|
|
|
await codeTab().click()
|
|
|
|
|
await expect(codePanelEmpty()).toBeVisible()
|
|
|
|
|
await expect(codePanelEmpty()).toContainText('Select a layer')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('selecting a rectangle shows JSX code', async () => {
|
2026-05-16 13:19:03 +00:00
|
|
|
await editor.canvas.drawRect(100, 100, 200, 150)
|
|
|
|
|
await editor.canvas.waitForRender()
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
|
|
|
|
|
await expect(codePanel()).toBeVisible()
|
|
|
|
|
|
2026-05-15 10:02:41 +00:00
|
|
|
const code = await codePanel().textContent()
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
expect(code).toContain('Rectangle')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('format toggle switches between OpenPencil and Tailwind', async () => {
|
|
|
|
|
await expect(formatToggle()).toBeVisible()
|
|
|
|
|
|
|
|
|
|
const initialFormat = await formatToggle().textContent()
|
|
|
|
|
expect(initialFormat).toContain('OpenPencil')
|
|
|
|
|
|
|
|
|
|
await formatToggle().click()
|
|
|
|
|
await expect(formatToggle()).toContainText('Tailwind')
|
|
|
|
|
|
2026-05-15 10:02:41 +00:00
|
|
|
const code = await codePanel().textContent()
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
expect(code).toContain('div')
|
|
|
|
|
|
|
|
|
|
await formatToggle().click()
|
|
|
|
|
await expect(formatToggle()).toContainText('OpenPencil')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('copy button works and shows confirmation', async () => {
|
|
|
|
|
await copyButton().click()
|
|
|
|
|
|
|
|
|
|
await expect(copyButton()).toContainText('Copied')
|
|
|
|
|
|
2026-05-16 13:19:03 +00:00
|
|
|
await editor.page.waitForTimeout(2500)
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
await expect(copyButton()).toContainText('Copy')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('deselecting shows empty state again', async () => {
|
2026-05-16 13:19:03 +00:00
|
|
|
await editor.page.keyboard.press('Escape')
|
|
|
|
|
await editor.canvas.waitForRender()
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
|
|
|
|
|
await expect(codePanelEmpty()).toBeVisible()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('selecting a frame shows Frame in JSX', async () => {
|
|
|
|
|
// Create a frame via store to avoid click-targeting issues
|
2026-05-16 13:19:03 +00:00
|
|
|
await editor.page.evaluate(() => {
|
2026-05-06 09:19:39 +00:00
|
|
|
const store = window.openPencil?.getStore?.()
|
2026-05-05 23:59:56 +00:00
|
|
|
if (!store) throw new Error('OpenPencil store not initialized')
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
const id = store.createShape('FRAME', 300, 100, 200, 200)
|
|
|
|
|
store.select([id])
|
|
|
|
|
})
|
2026-05-16 13:19:03 +00:00
|
|
|
await editor.canvas.waitForRender()
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
|
2026-05-15 10:02:41 +00:00
|
|
|
const code = await codePanel().textContent()
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
expect(code).toContain('Frame')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('switching back to Design tab works', async () => {
|
|
|
|
|
await designTab().click()
|
|
|
|
|
|
2026-05-24 09:15:29 +00:00
|
|
|
await expect(
|
|
|
|
|
editor.page
|
|
|
|
|
.getByTestId('design-panel-single')
|
|
|
|
|
.or(editor.page.getByTestId('design-panel-empty'))
|
|
|
|
|
.first()
|
|
|
|
|
).toBeVisible()
|
Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 10:23:32 +00:00
|
|
|
})
|
2026-06-06 07:59:43 +00:00
|
|
|
|
2026-06-06 14:30:36 +00:00
|
|
|
test('shows import errors in the Code panel', async () => {
|
|
|
|
|
await codeTab().click()
|
|
|
|
|
await editor.page.getByTestId('code-panel-import-toggle').click()
|
|
|
|
|
await editor.page.evaluate(() => {
|
|
|
|
|
const store = window.openPencil?.getStore?.()
|
|
|
|
|
if (!store) throw new Error('OpenPencil store not initialized')
|
|
|
|
|
const importDOMText = store.importDOMText
|
|
|
|
|
store.importDOMText = async () => {
|
|
|
|
|
store.importDOMText = importDOMText
|
|
|
|
|
throw new Error('CSS import failed')
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
await editor.page.getByTestId('code-panel-import-html').fill('<div class="card">Broken DOM</div>')
|
|
|
|
|
await editor.page.getByTestId('code-panel-import').click()
|
|
|
|
|
|
|
|
|
|
await expect(editor.page.getByTestId('code-panel-import-error')).toBeVisible()
|
|
|
|
|
await expect(editor.page.getByTestId('code-panel-import-error')).toContainText(
|
|
|
|
|
'CSS import failed'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
await editor.page.getByTestId('code-panel-import-html').fill('<div class="card">Recovered</div>')
|
|
|
|
|
await expect(editor.page.getByTestId('code-panel-import-error')).toBeHidden()
|
|
|
|
|
await editor.page.getByTestId('code-panel-import-toggle').click()
|
|
|
|
|
})
|
|
|
|
|
|
2026-06-06 07:59:43 +00:00
|
|
|
test('imports HTML and CSS into the canvas', async () => {
|
|
|
|
|
await codeTab().click()
|
|
|
|
|
await editor.page.getByTestId('code-panel-import-toggle').click()
|
|
|
|
|
await editor.page.getByTestId('code-panel-import-html').fill('<div class="card">Hello DOM</div>')
|
|
|
|
|
await editor.page
|
|
|
|
|
.getByTestId('code-panel-import-css')
|
|
|
|
|
.fill('.card { width: 240px; height: 120px; padding: 16px; background: #ffffff; }')
|
|
|
|
|
await editor.page.getByTestId('code-panel-import').click()
|
|
|
|
|
await editor.page.waitForFunction(() => {
|
|
|
|
|
const store = window.openPencil?.getStore?.()
|
|
|
|
|
return store?.graph.getAllNodes().some((node) => node.name.includes('Hello DOM'))
|
|
|
|
|
})
|
|
|
|
|
await editor.canvas.waitForRender()
|
|
|
|
|
|
|
|
|
|
const imported = await editor.page.evaluate(() => {
|
|
|
|
|
const store = window.openPencil?.getStore?.()
|
|
|
|
|
if (!store) throw new Error('OpenPencil store not initialized')
|
|
|
|
|
return store.graph.getAllNodes().some((node) => node.name.includes('Hello DOM'))
|
|
|
|
|
})
|
|
|
|
|
expect(imported).toBe(true)
|
|
|
|
|
})
|