openpencil/tests/e2e/properties/stroke-geometry.spec.ts
Danila Poyarkov e69ba75c12
refactor(ui): compose shared editor controls (#670)
* refactor(ui): extract shared action and navigation primitives

* refactor(ui): compose settings and libraries with shared tabs

* feat(ui): preserve native activation and toolbar keyboard navigation

* refactor(home): share document entries and accessible input controls

* fix(layers): share virtualized row geometry and selection styling

* refactor(layout): compose spacing and readable dimension controls

* refactor(properties): compose advanced strokes and inline effects

* refactor(ui): reuse actions in page and property controls

* refactor(settings): adopt shared actions without changing workflows

* refactor(ui): share collaboration and provider actions

* refactor(ui): finish shell and paint action composition

* test(ui): restore extracted control and settings coverage

* test(ui): complete workflow extraction coverage

* fix(ui): address review and trim redundant snapshots

* fix(layout): preserve single-step Undo for guides and wrap
2026-09-10 12:09:06 +03:00

110 lines
3.7 KiB
TypeScript

import { expect, test, type Page } from '@playwright/test'
import { CanvasHelper } from '#tests/helpers/canvas'
import { propertySection } from '#tests/helpers/properties'
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()
})
async function drawStrokedRectangle(x: number, y: number) {
await canvas.pressKey('r')
await canvas.drag(x, y, x + 120, y + 80)
await canvas.waitForRender()
await propertySection(page, 'Stroke').getByRole('button', { name: 'Add stroke' }).click()
await canvas.waitForRender()
}
async function selectedStrokeGeometry() {
return page.evaluate(() => {
const store = window.openPencil?.getStore?.()
if (!store) throw new Error('OpenPencil store not initialized')
return [...store.state.selectedIds].map((id) => {
const node = store.graph.getNode(id)
return node
? {
cap: node.strokeCap,
join: node.strokeJoin,
miterLimit: node.strokeMiterLimit,
paintCaps: node.strokes.map((stroke) => stroke.cap),
paintJoins: node.strokes.map((stroke) => stroke.join)
}
: null
})
})
}
test('shows geometry controls only after a stroke is added', async () => {
await canvas.pressKey('r')
await canvas.drag(100, 100, 220, 180)
await canvas.waitForRender()
await expect(page.locator('[data-property="stroke-cap"]')).not.toBeVisible()
await propertySection(page, 'Stroke').getByRole('button', { name: 'Add stroke' }).click()
await canvas.waitForRender()
await propertySection(page, 'Stroke').getByRole('button', { name: 'Stroke settings' }).click()
await expect(page.locator('[data-property="stroke-cap"]')).toBeVisible()
await expect(page.locator('[data-property="stroke-join"]')).toBeVisible()
await expect(page.locator('[data-property="stroke-miter-limit"]')).toBeVisible()
})
test('updates cap, join, and miter state from compact controls', async () => {
const section = page.getByRole('dialog', { name: 'Stroke settings' })
await section.getByRole('button', { name: 'Round cap' }).click()
await section.getByRole('button', { name: 'Bevel join' }).click()
await section.getByRole('spinbutton', { name: 'Miter limit' }).focus()
const miter = section.getByRole('spinbutton', { name: 'Miter limit' })
await miter.fill('12')
await miter.press('Enter')
await canvas.waitForRender()
expect(await selectedStrokeGeometry()).toEqual([
{
cap: 'ROUND',
join: 'BEVEL',
miterLimit: 12,
paintCaps: ['ROUND'],
paintJoins: ['BEVEL']
}
])
await page.keyboard.press('Escape')
await canvas.pressKey('Meta+z')
await canvas.waitForRender()
expect((await selectedStrokeGeometry())[0]?.miterLimit).toBe(4)
})
test('applies mixed multi-selection joins in one undo step', async () => {
await canvas.clearCanvas()
await drawStrokedRectangle(80, 80)
await drawStrokedRectangle(260, 80)
await canvas.pressKey('Meta+a')
await canvas.waitForRender()
const roundJoin = page
.getByRole('dialog', { name: 'Stroke settings' })
.getByRole('button', { name: 'Round join' })
await propertySection(page, 'Stroke').getByRole('button', { name: 'Stroke settings' }).click()
await expect(roundJoin).toBeVisible()
await roundJoin.click()
await canvas.waitForRender()
expect((await selectedStrokeGeometry()).map((value) => value?.join)).toEqual(['ROUND', 'ROUND'])
await page.keyboard.press('Escape')
await canvas.pressKey('Meta+z')
await canvas.waitForRender()
expect((await selectedStrokeGeometry()).map((value) => value?.join)).toEqual(['MITER', 'MITER'])
})