Fix silent rendering crash, no-chrome test mode, error detection
- Fix this.this.selColor() typo in renderer (6 occurrences) — broke selection/handles rendering since the constants extraction refactor - Add preserveDrawingBuffer to WebGL surface for reliable screenshots - Add ?no-chrome URL param to hide panels/toolbar in tests - CanvasHelper collects pageerror + console.error, assertNoErrors() fails tests on any browser-side exception
|
|
@ -18,6 +18,7 @@ useEventListener(document, 'wheel', (e: WheelEvent) => {
|
|||
}, { passive: false })
|
||||
|
||||
const params = useUrlSearchParams('history')
|
||||
const showChrome = !('no-chrome' in params)
|
||||
if (!('test' in params)) {
|
||||
createDemoShapes(store)
|
||||
}
|
||||
|
|
@ -26,12 +27,12 @@ if (!('test' in params)) {
|
|||
<template>
|
||||
<div class="flex h-screen w-screen flex-col">
|
||||
<div class="flex flex-1 overflow-hidden">
|
||||
<LayersPanel />
|
||||
<LayersPanel v-if="showChrome" />
|
||||
<div class="relative flex min-w-0 flex-1">
|
||||
<EditorCanvas />
|
||||
<Toolbar />
|
||||
<Toolbar v-if="showChrome" />
|
||||
</div>
|
||||
<PropertiesPanel />
|
||||
<PropertiesPanel v-if="showChrome" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export function useCanvas(canvasRef: Ref<HTMLCanvasElement | null>, store: Edito
|
|||
canvas.width = w * dpr
|
||||
canvas.height = h * dpr
|
||||
|
||||
const surface = ck.MakeWebGLCanvasSurface(canvas)
|
||||
const surface = ck.MakeWebGLCanvasSurface(canvas, undefined, { preserveDrawingBuffer: 1 })
|
||||
if (!surface) {
|
||||
console.error('Failed to create WebGL surface')
|
||||
return
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ export class SkiaRenderer {
|
|||
const rotLinePaint = new this.ck.Paint()
|
||||
rotLinePaint.setStyle(this.ck.PaintStyle.Stroke)
|
||||
rotLinePaint.setStrokeWidth(1)
|
||||
rotLinePaint.setColor(this.this.selColor())
|
||||
rotLinePaint.setColor(this.selColor())
|
||||
rotLinePaint.setAntiAlias(true)
|
||||
canvas.drawLine(mx, y1, mx, rotHandleY, rotLinePaint)
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ export class SkiaRenderer {
|
|||
if (node.type === 'FRAME' && node.parentId === graph.rootId) {
|
||||
const labelPaint = new this.ck.Paint()
|
||||
labelPaint.setStyle(this.ck.PaintStyle.Fill)
|
||||
labelPaint.setColor(this.this.selColor())
|
||||
labelPaint.setColor(this.selColor())
|
||||
labelPaint.setAntiAlias(true)
|
||||
canvas.drawText(node.name, sx1, sy1 - 8, labelPaint, this.labelFont)
|
||||
labelPaint.delete()
|
||||
|
|
@ -307,7 +307,7 @@ export class SkiaRenderer {
|
|||
|
||||
const pillPaint = new this.ck.Paint()
|
||||
pillPaint.setStyle(this.ck.PaintStyle.Fill)
|
||||
pillPaint.setColor(this.this.selColor())
|
||||
pillPaint.setColor(this.selColor())
|
||||
pillPaint.setAntiAlias(true)
|
||||
|
||||
const rrect = this.ck.RRectXY(this.ck.LTRBRect(pillX, pillY, pillX + pillW, pillY + pillH), 4, 4)
|
||||
|
|
@ -512,7 +512,7 @@ export class SkiaRenderer {
|
|||
const paint = new this.ck.Paint()
|
||||
paint.setStyle(this.ck.PaintStyle.Stroke)
|
||||
paint.setStrokeWidth(2)
|
||||
paint.setColor(this.this.selColor())
|
||||
paint.setColor(this.selColor())
|
||||
paint.setAntiAlias(true)
|
||||
|
||||
if (indicator.direction === 'HORIZONTAL') {
|
||||
|
|
@ -752,7 +752,7 @@ export class SkiaRenderer {
|
|||
const pathPaint = new this.ck.Paint()
|
||||
pathPaint.setStyle(this.ck.PaintStyle.Stroke)
|
||||
pathPaint.setStrokeWidth(2)
|
||||
pathPaint.setColor(this.this.selColor())
|
||||
pathPaint.setColor(this.selColor())
|
||||
pathPaint.setAntiAlias(true)
|
||||
|
||||
const handlePaint = new this.ck.Paint()
|
||||
|
|
@ -769,7 +769,7 @@ export class SkiaRenderer {
|
|||
const vertexStroke = new this.ck.Paint()
|
||||
vertexStroke.setStyle(this.ck.PaintStyle.Stroke)
|
||||
vertexStroke.setStrokeWidth(2)
|
||||
vertexStroke.setColor(this.this.selColor())
|
||||
vertexStroke.setColor(this.selColor())
|
||||
vertexStroke.setAntiAlias(true)
|
||||
|
||||
const toScreen = (x: number, y: number) => ({
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ test.describe.configure({ mode: 'serial' })
|
|||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage()
|
||||
await page.goto('/?test')
|
||||
await page.goto('/?test&no-chrome')
|
||||
canvas = new CanvasHelper(page)
|
||||
await canvas.waitForInit()
|
||||
})
|
||||
|
|
@ -23,6 +23,7 @@ test.beforeEach(async () => {
|
|||
})
|
||||
|
||||
async function expectCanvas(name: string) {
|
||||
canvas.assertNoErrors()
|
||||
const buffer = await canvas.canvas.screenshot()
|
||||
expect(buffer).toMatchSnapshot(`${name}.png`)
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -3,10 +3,23 @@ import type { Page, Locator } from '@playwright/test'
|
|||
export class CanvasHelper {
|
||||
readonly page: Page
|
||||
readonly canvas: Locator
|
||||
readonly errors: string[] = []
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
this.canvas = page.locator('canvas')
|
||||
page.on('pageerror', (err) => this.errors.push(err.message))
|
||||
page.on('console', (msg) => {
|
||||
if (msg.type() === 'error') this.errors.push(msg.text())
|
||||
})
|
||||
}
|
||||
|
||||
assertNoErrors() {
|
||||
if (this.errors.length > 0) {
|
||||
const messages = this.errors.join('\n')
|
||||
this.errors.length = 0
|
||||
throw new Error(`Browser errors:\n${messages}`)
|
||||
}
|
||||
}
|
||||
|
||||
async waitForRender() {
|
||||
|
|
|
|||