mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
test: bridge happy-dom OffscreenCanvas canvas mocks
Provide the existing HTML canvas test double when happy-dom exposes an adapter-less OffscreenCanvas 2D context. This keeps xterm tests working across supported happy-dom versions without changing production rendering.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/** @vitest-environment happy-dom */
|
||||
import { Terminal } from '@xterm/xterm'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { installHappyDomOffscreenCanvasCompatibility } from './happy-dom-offscreen-canvas'
|
||||
|
||||
type TestOffscreenCanvas = new (
|
||||
width: number,
|
||||
height: number
|
||||
) => {
|
||||
getContext: (contextType: string, contextAttributes?: unknown) => unknown
|
||||
}
|
||||
|
||||
const openTerminals: Terminal[] = []
|
||||
|
||||
describe('happy-dom OffscreenCanvas compatibility', () => {
|
||||
afterEach(() => {
|
||||
while (openTerminals.length > 0) {
|
||||
openTerminals.pop()?.dispose()
|
||||
}
|
||||
vi.restoreAllMocks()
|
||||
document.body.replaceChildren()
|
||||
})
|
||||
|
||||
it('delegates adapter-less 2D contexts to the existing HTML canvas double', () => {
|
||||
const offscreenCanvas = (globalThis as { OffscreenCanvas?: TestOffscreenCanvas })
|
||||
.OffscreenCanvas
|
||||
if (!offscreenCanvas) {
|
||||
expect(installHappyDomOffscreenCanvasCompatibility()).toBe(false)
|
||||
return
|
||||
}
|
||||
|
||||
const context = { measureText: () => ({ width: 10 }) }
|
||||
const getContext = vi
|
||||
.spyOn(HTMLCanvasElement.prototype, 'getContext')
|
||||
.mockReturnValue(context as unknown as CanvasRenderingContext2D)
|
||||
|
||||
expect(installHappyDomOffscreenCanvasCompatibility()).toBe(true)
|
||||
expect(new offscreenCanvas(1, 1).getContext('2d')).toBe(context)
|
||||
expect(getContext).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('does not turn unsupported non-2D contexts into test doubles', () => {
|
||||
const offscreenCanvas = (globalThis as { OffscreenCanvas?: TestOffscreenCanvas })
|
||||
.OffscreenCanvas
|
||||
if (!offscreenCanvas) {
|
||||
return
|
||||
}
|
||||
|
||||
const getContext = vi.spyOn(HTMLCanvasElement.prototype, 'getContext')
|
||||
expect(new offscreenCanvas(1, 1).getContext('webgl')).toBeNull()
|
||||
expect(getContext).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('keeps xterm DOM rendering open with the existing HTML canvas double', () => {
|
||||
vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue({
|
||||
measureText: () => ({ width: 10 })
|
||||
} as unknown as CanvasRenderingContext2D)
|
||||
const host = document.createElement('div')
|
||||
document.body.append(host)
|
||||
const terminal = new Terminal()
|
||||
openTerminals.push(terminal)
|
||||
|
||||
terminal.open(host)
|
||||
|
||||
expect(terminal.element).not.toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,59 @@
|
||||
// Why: happy-dom exposes OffscreenCanvas without a default canvas adapter. xterm prefers that API
|
||||
// and then cannot open in tests that already provide the HTML canvas text-metric stand-in.
|
||||
|
||||
const OFFSCREEN_CANVAS_COMPATIBILITY_INSTALLED = Symbol.for(
|
||||
'orca.happyDomOffscreenCanvasCompatibility'
|
||||
)
|
||||
|
||||
type PatchableCanvas = {
|
||||
getContext?: (contextType: string, contextAttributes?: unknown) => unknown
|
||||
} & Record<symbol, unknown>
|
||||
|
||||
type CanvasConstructor = {
|
||||
prototype: PatchableCanvas
|
||||
new (width: number, height: number): PatchableCanvas
|
||||
}
|
||||
|
||||
type HappyDomGlobals = {
|
||||
OffscreenCanvas?: CanvasConstructor
|
||||
HTMLCanvasElement?: { prototype: PatchableCanvas }
|
||||
document?: Pick<Document, 'createElement'>
|
||||
}
|
||||
|
||||
/** Make happy-dom's adapter-less OffscreenCanvas honor the existing HTML canvas test double. */
|
||||
export function installHappyDomOffscreenCanvasCompatibility(): boolean {
|
||||
const globals = globalThis as unknown as HappyDomGlobals
|
||||
const offscreenCanvas = globals.OffscreenCanvas
|
||||
const htmlCanvas = globals.HTMLCanvasElement
|
||||
const document = globals.document
|
||||
if (!offscreenCanvas || !htmlCanvas || !document) {
|
||||
return false
|
||||
}
|
||||
|
||||
const prototype = offscreenCanvas.prototype
|
||||
if (prototype[OFFSCREEN_CANVAS_COMPATIBILITY_INSTALLED] === true) {
|
||||
return true
|
||||
}
|
||||
const originalGetContext = prototype.getContext
|
||||
if (!originalGetContext || !htmlCanvas.prototype.getContext) {
|
||||
return false
|
||||
}
|
||||
|
||||
prototype.getContext = function patchedGetContext(
|
||||
this: PatchableCanvas,
|
||||
contextType: string,
|
||||
contextAttributes?: unknown
|
||||
): unknown {
|
||||
const context = originalGetContext.call(this, contextType, contextAttributes)
|
||||
if (contextType !== '2d' || context) {
|
||||
return context
|
||||
}
|
||||
|
||||
const canvas = document.createElement('canvas') as PatchableCanvas
|
||||
return htmlCanvas.prototype.getContext!.call(canvas, contextType, contextAttributes)
|
||||
}
|
||||
prototype[OFFSCREEN_CANVAS_COMPATIBILITY_INSTALLED] = true
|
||||
return true
|
||||
}
|
||||
|
||||
installHappyDomOffscreenCanvasCompatibility()
|
||||
@@ -20,6 +20,7 @@ export default defineConfig({
|
||||
execArgv: ['--no-experimental-webstorage', '--expose-gc'],
|
||||
// Why: happy-dom drops MutationObserver callbacks on GC; keep them alive like a browser does.
|
||||
setupFiles: [
|
||||
resolve('config/scripts/happy-dom-offscreen-canvas.ts'),
|
||||
resolve('config/scripts/happy-dom-mutation-observer-retention.ts'),
|
||||
resolve('config/scripts/vitest-host-ports-setup.ts')
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user