- Replace browser store non-null assertions with explicit initialization guards - Use expectDefined for optional test resources and tool results - Clean low-count non-null assertions in font, icon, snap, OKHCL, and visual tests
141 lines
4.2 KiB
TypeScript
141 lines
4.2 KiB
TypeScript
import { expect, test, type Page } from '@playwright/test'
|
|
|
|
import { CanvasHelper } from '#tests/helpers/canvas'
|
|
|
|
let page: Page
|
|
let canvas: CanvasHelper
|
|
|
|
test.describe.configure({ mode: 'serial' })
|
|
|
|
test.beforeAll(async ({ browser }) => {
|
|
page = await browser.newPage()
|
|
await page.goto('/')
|
|
canvas = new CanvasHelper(page)
|
|
await canvas.waitForInit()
|
|
})
|
|
|
|
test.afterAll(async () => {
|
|
await page.close()
|
|
})
|
|
|
|
async function getSelectedFill() {
|
|
return page.evaluate(() => {
|
|
const store = window.__OPEN_PENCIL_STORE__
|
|
if (!store) throw new Error('OpenPencil store not initialized')
|
|
const id = [...store.state.selectedIds][0]
|
|
if (!id) return null
|
|
const node = store.graph.getNode(id)
|
|
return node?.fills?.[0] ?? null
|
|
})
|
|
}
|
|
|
|
async function openFillPicker() {
|
|
const solidTab = page.locator('[data-test-id="fill-picker-tab-solid"]')
|
|
if (await solidTab.isVisible().catch(() => false)) return
|
|
const swatch = page.locator('[data-test-id="fill-picker-swatch"]').first()
|
|
await swatch.click()
|
|
await expect(solidTab).toBeVisible()
|
|
}
|
|
|
|
async function chooseFormat(label: 'RGB' | 'HSL' | 'HSB' | 'OkHCL') {
|
|
await page.locator('[data-test-id="color-format-select"]').click()
|
|
await page.getByRole('option', { name: label, exact: true }).click()
|
|
}
|
|
|
|
async function dragSlider(testId: string, ratio: number) {
|
|
const slider = page.locator(`[data-test-id="${testId}"] input[type="range"]`)
|
|
const box = await slider.boundingBox()
|
|
if (!box) throw new Error(`Missing slider: ${testId}`)
|
|
const y = box.y + box.height / 2
|
|
await page.mouse.move(box.x + 2, y)
|
|
await page.mouse.down()
|
|
await page.mouse.move(box.x + Math.max(2, Math.min(box.width - 2, box.width * ratio)), y, {
|
|
steps: 20
|
|
})
|
|
await page.mouse.up()
|
|
await canvas.waitForRender()
|
|
}
|
|
|
|
test('rgb hue slider updates selected fill color', async () => {
|
|
await canvas.clearCanvas()
|
|
await canvas.drawRect(100, 100, 160, 120)
|
|
await canvas.waitForRender()
|
|
|
|
await openFillPicker()
|
|
const before = await getSelectedFill()
|
|
await dragSlider('color-slider-hue', 0.65)
|
|
const after = await getSelectedFill()
|
|
|
|
expect(after).not.toBeNull()
|
|
expect(
|
|
before?.color.r !== after?.color.r ||
|
|
before?.color.g !== after?.color.g ||
|
|
before?.color.b !== after?.color.b
|
|
).toBe(true)
|
|
})
|
|
|
|
test('rgb alpha slider updates fill opacity and alpha', async () => {
|
|
await openFillPicker()
|
|
await dragSlider('color-slider-alpha', 0.3)
|
|
const after = await getSelectedFill()
|
|
|
|
expect(after).not.toBeNull()
|
|
expect(after?.opacity).toBeLessThan(1)
|
|
expect(after?.color.a).toBeCloseTo(after?.opacity ?? 0, 3)
|
|
})
|
|
|
|
test('hsl saturation slider changes saturation', async () => {
|
|
await openFillPicker()
|
|
await chooseFormat('HSL')
|
|
const before = await getSelectedFill()
|
|
await dragSlider('color-slider-hsl-s', 0.2)
|
|
const after = await getSelectedFill()
|
|
|
|
expect(after).not.toBeNull()
|
|
expect(
|
|
before?.color.r !== after?.color.r ||
|
|
before?.color.g !== after?.color.g ||
|
|
before?.color.b !== after?.color.b
|
|
).toBe(true)
|
|
})
|
|
|
|
test('hsl lightness slider changes color independently', async () => {
|
|
await openFillPicker()
|
|
await chooseFormat('HSL')
|
|
const before = await getSelectedFill()
|
|
await dragSlider('color-slider-hsl-l', 0.8)
|
|
const after = await getSelectedFill()
|
|
|
|
expect(after).not.toBeNull()
|
|
expect(
|
|
before?.color.r !== after?.color.r ||
|
|
before?.color.g !== after?.color.g ||
|
|
before?.color.b !== after?.color.b
|
|
).toBe(true)
|
|
})
|
|
|
|
test('hsb saturation and brightness sliders both affect fill color', async () => {
|
|
await openFillPicker()
|
|
await chooseFormat('HSB')
|
|
|
|
const beforeS = await getSelectedFill()
|
|
await dragSlider('color-slider-hsb-s', 0.15)
|
|
const afterS = await getSelectedFill()
|
|
expect(afterS).not.toBeNull()
|
|
expect(
|
|
beforeS?.color.r !== afterS?.color.r ||
|
|
beforeS?.color.g !== afterS?.color.g ||
|
|
beforeS?.color.b !== afterS?.color.b
|
|
).toBe(true)
|
|
|
|
const beforeB = await getSelectedFill()
|
|
await dragSlider('color-slider-hsb-b', 0.9)
|
|
const afterB = await getSelectedFill()
|
|
expect(afterB).not.toBeNull()
|
|
expect(
|
|
beforeB?.color.r !== afterB?.color.r ||
|
|
beforeB?.color.g !== afterB?.color.g ||
|
|
beforeB?.color.b !== afterB?.color.b
|
|
).toBe(true)
|
|
})
|