vitest-environment-webgl-node 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,37 +1,90 @@
1
+ <p align="center">
2
+ <a href="https://npmjs.com/package/vitest-environment-webgl-node"><img src="https://img.shields.io/npm/v/vitest-environment-webgl-node.svg" alt="npm package"></a>
3
+ <a href="https://www.npmtrends.com/vitest-environment-webgl-node"><img src="https://img.shields.io/npm/dw/vitest-environment-webgl-node.svg" alt="npm downloads"></a>
4
+ <a href="https://codecov.io/gh/bhouston/vitest-gpu"><img src="https://codecov.io/gh/bhouston/vitest-gpu/branch/main/graph/badge.svg" alt="coverage"></a>
5
+ <a href="https://discord.gg/fwupDN493R"><img src="https://img.shields.io/badge/chat-discord-blue?style=flat&logo=discord" alt="discord chat"></a>
6
+ <a href="https://vitest-gpu.ben3d.ca/"><img src="https://img.shields.io/badge/docs-read-blue?style=flat" alt="documentation"></a>
7
+ </p>
8
+ <br/>
9
+
1
10
  # vitest-environment-webgl-node
2
11
 
3
- [![npm version][npm-badge]][npm-url]
4
- [![npm downloads][downloads-badge]][npm-url]
5
- [![Tests][tests-badge]][tests-url]
6
- [![Discord][discord-badge]][discord-url]
12
+ > Real WebGL 1 and 2 tests in Vitest, with no browser.
13
+
14
+ - 🖥️ Real WebGL 1 and 2
15
+ - 🚫 No Browser or Mocks
16
+ - 🧩 Runs three.js Unchanged
17
+ - 🖼️ Pairs With vitest-screenshot
18
+ - ⚡ Up to 2.4x Faster Than Browsers
19
+
20
+ Headless GPU testing for CI: `canvas.getContext('webgl2')` returns a GPU-backed context, so three.js, regl,
21
+ PixiJS and plain WebGL code run unchanged. Native GPU testing is up to 2.4x faster than running the same tests
22
+ in a browser, see the [blog post](https://ben3d.ca/blog/native-gpu-testing-for-vitest-and-jest).
23
+ Powered by [`@onirenaud/node-webgl`](https://github.com/RenaudRohlinger/node-webgl) (Chrome's ANGLE, statically linked).
24
+
25
+ Part of [vitest-gpu](https://github.com/bhouston/vitest-gpu), which also provides WebGPU and image snapshot packages.
26
+
27
+ [Read the Docs to Learn More](https://vitest-gpu.ben3d.ca/docs/webgl/) about the WebGL environment: what it installs, its options, TypeScript types for the globals and CI setup.
28
+
29
+ ```sh
30
+ pnpm add -D vitest vitest-environment-webgl-node
31
+ ```
7
32
 
8
- Real, headless WebGL 1 and WebGL 2 inside Vitest, with no browser. Native GPU testing is up to
9
- 2.4x faster than running the same tests in a browser — see the
10
- [blog post](https://ben3d.ca/blog/native-gpu-testing-for-vitest-and-jest) for details.
11
- Powered by
12
- [`@onirenaud/node-webgl`](https://github.com/RenaudRohlinger/node-webgl) (Chrome's ANGLE, statically linked).
33
+ ```ts
34
+ // vitest.config.ts
35
+ import { defineConfig } from 'vitest/config';
36
+
37
+ export default defineConfig({ test: { environment: 'webgl-node' } });
38
+ ```
39
+
40
+ ```ts
41
+ // gl.test.ts
42
+ import { expect, it } from 'vitest';
43
+
44
+ it('clears to red on a real GPU', () => {
45
+ const canvas = document.createElement('canvas');
46
+ canvas.width = canvas.height = 4;
47
+ const gl = canvas.getContext('webgl2')!;
48
+ gl.clearColor(1, 0, 0, 1);
49
+ gl.clear(gl.COLOR_BUFFER_BIT);
50
+ const pixel = new Uint8Array(4);
51
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
52
+ expect([...pixel]).toEqual([255, 0, 0, 255]);
53
+ });
54
+ ```
13
55
 
14
56
  The environment installs `window`, `document`, `HTMLCanvasElement`, `Image`, `requestAnimationFrame`,
15
57
  the `WebGL*` classes and a file-reading `fetch()` before each test file, and removes them afterwards.
16
- `document.createElement('canvas').getContext('webgl2')` returns a GPU-backed context, so three.js,
17
- regl, pixi and plain WebGL code run unchanged.
18
58
 
19
59
  Using Jest instead? See the equivalent
20
60
  [`jest-environment-webgl-node`](https://github.com/bhouston/jest-gpu/tree/main/packages/jest-environment-webgl-node)
21
- in [jest-gpu](https://github.com/bhouston/jest-gpu).
61
+ in [jest-gpu](https://github.com/bhouston/jest-gpu), documented at [jest-gpu.ben3d.ca](https://jest-gpu.ben3d.ca/).
22
62
 
23
63
  ## Stability
24
64
 
25
65
  As of 1.0.0, the public API (the environment export and its options) is considered stable.
26
66
  Breaking changes will be released as a new major version.
27
67
 
28
- ## Install
68
+ ## Compared to alternatives
29
69
 
30
- ```sh
31
- pnpm add -D vitest vitest-environment-webgl-node
32
- ```
70
+ | Approach | Real rendering | Notes |
71
+ | --------------------------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------- |
72
+ | jsdom plus a canvas mock (`jest-webgl-canvas-mock`, etc.) | No | Fast and light, but `getContext()` returns stubs: you can assert calls, not pixels or shader results. |
73
+ | Raw [`gl`](https://github.com/stackgl/headless-gl) | Yes | WebGL 1 only (per node-webgl's docs), runs on the system OpenGL driver, and you wire up the DOM globals yourself. |
74
+ | Vitest browser mode or Playwright | Yes | A real browser: heavier to install and slower to start, and the right choice when you need real browser APIs. |
75
+ | vitest-environment-webgl-node | Yes | ANGLE in the Node process, WebGL 1 and 2. Not a browser: only canvas, `Image`, `fetch` and `requestAnimationFrame` are provided. |
76
+
77
+ ## Supported versions and platforms
78
+
79
+ - Vitest 4 and 5 (CI tests both). Vitest 3 is not supported.
80
+ - Node 22 or later. CI runs Node 22 and 26 on `macos-latest`, `ubuntu-latest` and `windows-latest`.
81
+ - macOS uses Metal. Linux uses Mesa (see below). Windows uses Direct3D 11 per the
82
+ [node-webgl docs](https://github.com/RenaudRohlinger/node-webgl#platforms).
33
83
 
34
- Requires Vitest 4 or 5. Vitest 3 is not supported.
84
+ ## Useful for
85
+
86
+ three.js `WebGLRenderer`, Babylon.js, regl, PixiJS, deck.gl and plain WebGL code. The demos exercise three.js and
87
+ Babylon.js; node-webgl's docs name regl, PixiJS and deck.gl. These are compatible use cases, not endorsements.
35
88
 
36
89
  ## Usage
37
90
 
@@ -62,7 +115,6 @@ it('renders', () => {
62
115
 
63
116
  Options are those of node-webgl's `init()` (`backend`, `api`) and `installDOM()`
64
117
  (`baseDir`, `fetch`, `devicePixelRatio`, `innerWidth`, `innerHeight`, `frameInterval`).
65
- Pair with [`vitest-screenshot`](../vitest-screenshot) for pixel-diff assertions.
66
118
 
67
119
  For a Node-only TypeScript project, opt into types for the installed globals by adding
68
120
  `import 'vitest-environment-webgl-node/globals';` to a `.d.ts` file your tsconfig includes. Do not include
@@ -73,18 +125,51 @@ node-webgl canvas at the library boundary when necessary.
73
125
  On Linux CI install Mesa (`apt-get install libegl1 libgles2 libgl1-mesa-dri`) and set
74
126
  `LIBGL_ALWAYS_SOFTWARE=1`. macOS and Windows use prebuilt binaries.
75
127
 
76
- ## Author
128
+ ## Image snapshots
129
+
130
+ Pair with [`vitest-screenshot`](https://github.com/bhouston/vitest-gpu/tree/main/packages/vitest-screenshot) to diff the canvas against a committed baseline:
77
131
 
78
- Created by [Ben Houston](https://ben3d.ca) and sponsored by [Land of Assets](https://landofassets.com).
132
+ ```ts
133
+ import * as THREE from 'three';
134
+ import { expect, it } from 'vitest';
135
+ import { extendMatchers } from 'vitest-screenshot';
136
+
137
+ extendMatchers();
138
+
139
+ it('renders a cube', async () => {
140
+ const canvas = document.createElement('canvas');
141
+ const renderer = new THREE.WebGLRenderer({ canvas });
142
+ renderer.setSize(256, 256, false);
143
+ const scene = new THREE.Scene();
144
+ const camera = new THREE.PerspectiveCamera(50, 1, 0.1, 100);
145
+ camera.position.z = 3;
146
+ scene.add(new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshNormalMaterial()));
147
+
148
+ renderer.render(scene, camera);
149
+ await expect(canvas).toMatchScreenshot('cube.png');
150
+ renderer.dispose();
151
+ });
152
+ ```
153
+
154
+ ## See also
155
+
156
+ - [`vitest-environment-webgpu-node`](https://github.com/bhouston/vitest-gpu/tree/main/packages/vitest-environment-webgpu-node) for headless WebGPU.
157
+ - [`vitest-screenshot`](https://github.com/bhouston/vitest-gpu/tree/main/packages/vitest-screenshot) for `toMatchScreenshot()`.
158
+ - [`demo/`](https://github.com/bhouston/vitest-gpu/tree/main/demo/test/webgl) for WebGL contexts, uploads, readbacks, three.js and Babylon.js tests, and the
159
+ [repository README](https://github.com/bhouston/vitest-gpu#readme).
160
+
161
+ ## Resource cleanup
162
+
163
+ Environment teardown destroys contexts first created through `Canvas.getContext()` during the test file, including DOM canvases, `OffscreenCanvas` and imported canvas factories. It also cancels pending callbacks scheduled through its animation-frame shim. Contexts created directly with the WebGL context constructors, or before setup, remain the caller's responsibility: call `destroy()` on them. Dispose renderers and canvases during a long-running file to release resources sooner.
164
+
165
+ ## Contribution
166
+
167
+ See [Contributing Guide](https://github.com/bhouston/vitest-gpu/blob/main/CONTRIBUTING.md).
79
168
 
80
169
  ## License
81
170
 
82
171
  MIT
83
172
 
84
- [npm-badge]: https://img.shields.io/npm/v/vitest-environment-webgl-node.svg
85
- [npm-url]: https://www.npmjs.com/package/vitest-environment-webgl-node
86
- [downloads-badge]: https://img.shields.io/npm/dm/vitest-environment-webgl-node.svg
87
- [tests-badge]: https://github.com/bhouston/vitest-gpu/actions/workflows/ci.yml/badge.svg
88
- [tests-url]: https://github.com/bhouston/vitest-gpu/actions/workflows/ci.yml
89
- [discord-badge]: https://img.shields.io/badge/Discord-Join%20Chat-5865F2?logo=discord&logoColor=white
90
- [discord-url]: https://discord.gg/fwupDN493R
173
+ ## Author
174
+
175
+ [Ben Houston](https://ben3d.ca), Sponsored by [Land of Assets](https://landofassets.com).
package/dist/index.d.ts CHANGED
@@ -1,13 +1,33 @@
1
1
  import { type InitOptions, type InstallDOMOptions } from '@onirenaud/node-webgl';
2
2
  /** Set under `test.environmentOptions.webglNode` in your Vitest config. */
3
3
  export type WebglNodeOptions = InitOptions & InstallDOMOptions;
4
+ /**
5
+ * The Vitest environment registered as `webgl-node`. Before each test file it installs node-webgl's `window`,
6
+ * `document`, `HTMLCanvasElement`, `Image`, `requestAnimationFrame` and `WebGL*` classes plus a file-reading
7
+ * `fetch()`, and it restores the original globals afterwards.
8
+ */
4
9
  declare const _default: {
10
+ /** The name Vitest uses to select this environment: `test.environment: 'webgl-node'`. */
5
11
  name: string;
12
+ /** Runs test files through Vite's `ssr` environment, as Node code. */
6
13
  viteEnvironment: "ssr";
14
+ /**
15
+ * Installs the GL display and the DOM globals on the test file's global object.
16
+ *
17
+ * @param global - The global object of the test file's context.
18
+ * @param __namedParameters - The environment options from the Vitest config; `webglNode` holds {@link WebglNodeOptions}.
19
+ * @returns A `teardown` hook that destroys contexts and restores the globals this call changed.
20
+ */
7
21
  setup(global: typeof globalThis, { webglNode }: {
8
22
  webglNode?: WebglNodeOptions;
9
23
  }): {
10
- teardown(g: Record<string, unknown>): void;
24
+ /**
25
+ * Destroys the WebGL contexts created during the test file, cancels pending animation-frame callbacks and
26
+ * restores the globals that `setup` replaced.
27
+ *
28
+ * @param g - The global object of the test file's context.
29
+ */
30
+ teardown: (g: Record<string, unknown>) => void;
11
31
  };
12
32
  };
13
33
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAMnH,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,iBAAiB,CAAC;;;;kBAkF/C,OAAO,UAAU,iBAAsB;QAAE,SAAS,CAAC,EAAE,gBAAgB,CAAA;KAAE;oBAwCrE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAM/B,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,iBAAiB,CAAC;AA+E/D;;;;GAIG;;IAED,yFAAyF;;IAEzF,sEAAsE;;IAEtE;;;;;;OAMG;kBACW,OAAO,UAAU,iBAAsB;QAAE,SAAS,CAAC,EAAE,gBAAgB,CAAA;KAAE;QA0FjF;;;;;WAKG;sBACW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;AA5G3C,wBAyHwB"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getDisplayInfo, init, installDOM } from '@onirenaud/node-webgl';
1
+ import { Canvas, getDisplayInfo, init, installDOM, } from '@onirenaud/node-webgl';
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import { extname, resolve } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
@@ -73,9 +73,23 @@ const installFetch = (global, baseDir) => {
73
73
  };
74
74
  Object.defineProperty(global, 'fetch', { value: localFetch, writable: true, configurable: true });
75
75
  };
76
+ /**
77
+ * The Vitest environment registered as `webgl-node`. Before each test file it installs node-webgl's `window`,
78
+ * `document`, `HTMLCanvasElement`, `Image`, `requestAnimationFrame` and `WebGL*` classes plus a file-reading
79
+ * `fetch()`, and it restores the original globals afterwards.
80
+ */
76
81
  export default {
82
+ /** The name Vitest uses to select this environment: `test.environment: 'webgl-node'`. */
77
83
  name: 'webgl-node',
84
+ /** Runs test files through Vite's `ssr` environment, as Node code. */
78
85
  viteEnvironment: 'ssr',
86
+ /**
87
+ * Installs the GL display and the DOM globals on the test file's global object.
88
+ *
89
+ * @param global - The global object of the test file's context.
90
+ * @param __namedParameters - The environment options from the Vitest config; `webglNode` holds {@link WebglNodeOptions}.
91
+ * @returns A `teardown` hook that destroys contexts and restores the globals this call changed.
92
+ */
79
93
  setup(global, { webglNode = {} }) {
80
94
  const { backend, api, ...dom } = webglNode;
81
95
  if (backend || api) {
@@ -90,11 +104,65 @@ export default {
90
104
  }
91
105
  init({ backend, api });
92
106
  }
107
+ const contexts = new Set();
108
+ const frames = new Set();
109
+ let disposed = false;
110
+ const dispose = () => {
111
+ disposed = true;
112
+ for (const frame of frames)
113
+ clearTimeout(frame);
114
+ frames.clear();
115
+ for (const context of contexts)
116
+ context.destroy();
117
+ contexts.clear();
118
+ };
119
+ const hasFrame = global.requestAnimationFrame !== undefined;
93
120
  const before = snapshot(global);
94
121
  const nested = [];
95
122
  try {
96
123
  // node-webgl remembers fetch installation at module scope, which cannot represent separate Vitest environments.
97
124
  installDOM({ ...dom, fetch: false });
125
+ // Intercept the shared canvas API so imported factories and OffscreenCanvas are covered too.
126
+ const canvasBefore = snapshot(Canvas.prototype);
127
+ nested.push({ target: Canvas.prototype, before: canvasBefore });
128
+ // oxlint-disable-next-line typescript/unbound-method -- Canvas.prototype.getContext is patched/compared by identity, never called unbound
129
+ const getContext = Canvas.prototype.getContext;
130
+ Canvas.prototype.getContext = function (...args) {
131
+ if (disposed)
132
+ throw new Error('WebGL environment has been torn down');
133
+ // node-webgl exposes the cached context at runtime but strips it from its declarations.
134
+ const previous = this._ctx;
135
+ const context = getContext.apply(this, args);
136
+ if (context && context !== previous)
137
+ contexts.add(context);
138
+ return context;
139
+ };
140
+ nested.at(-1).changed = changedProperties(canvasBefore, Canvas.prototype);
141
+ // Own only the rAF shim installed by this setup; preserve host implementations.
142
+ if (!hasFrame) {
143
+ Object.defineProperty(global, 'requestAnimationFrame', {
144
+ configurable: true,
145
+ writable: true,
146
+ value: (callback) => {
147
+ if (disposed)
148
+ return 0;
149
+ const frame = setTimeout(() => {
150
+ frames.delete(frame);
151
+ callback(performance.now());
152
+ }, dom.frameInterval ?? 16).unref();
153
+ frames.add(frame);
154
+ return frame;
155
+ },
156
+ });
157
+ Object.defineProperty(global, 'cancelAnimationFrame', {
158
+ configurable: true,
159
+ writable: true,
160
+ value: (frame) => {
161
+ frames.delete(frame);
162
+ clearTimeout(frame);
163
+ },
164
+ });
165
+ }
98
166
  if (dom.fetch !== false)
99
167
  installFetch(global, dom.baseDir ?? process.cwd());
100
168
  // node-webgl's window/document have no event methods; engines like Babylon.js register resize/blur listeners.
@@ -110,6 +178,7 @@ export default {
110
178
  }
111
179
  }
112
180
  catch (error) {
181
+ dispose();
113
182
  for (const item of nested.toReversed())
114
183
  restore(item.target, item.before, item.changed ?? changedProperties(item.before, item.target));
115
184
  restore(global, before, changedProperties(before, global));
@@ -117,10 +186,25 @@ export default {
117
186
  }
118
187
  const changed = changedProperties(before, global);
119
188
  return {
120
- teardown(g) {
121
- for (const item of nested.toReversed())
122
- restore(item.target, item.before, item.changed);
123
- restore(g, before, changed);
189
+ /**
190
+ * Destroys the WebGL contexts created during the test file, cancels pending animation-frame callbacks and
191
+ * restores the globals that `setup` replaced.
192
+ *
193
+ * @param g - The global object of the test file's context.
194
+ */
195
+ teardown: (g) => {
196
+ if (disposed)
197
+ return;
198
+ try {
199
+ dispose();
200
+ }
201
+ finally {
202
+ for (const item of nested.toReversed())
203
+ restore(item.target, item.before, item.changed);
204
+ restore(g, before, changed);
205
+ nested.length = 0;
206
+ before.clear();
207
+ }
124
208
  },
125
209
  };
126
210
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,14 +1,24 @@
1
1
  {
2
2
  "name": "vitest-environment-webgl-node",
3
- "version": "3.0.0",
4
- "description": "Vitest environment that provides real headless WebGL 1/2 (ANGLE via @onirenaud/node-webgl) in Node",
3
+ "version": "3.0.2",
4
+ "description": "Vitest environment for real headless WebGL 1/2 tests in Node (ANGLE via @onirenaud/node-webgl): no browser, Playwright or canvas mocks",
5
5
  "keywords": [
6
+ "babylonjs",
7
+ "canvas",
8
+ "ci",
9
+ "gpu",
10
+ "gpu-testing",
6
11
  "headless",
12
+ "headless-gl",
13
+ "node",
14
+ "pixijs",
15
+ "regl",
7
16
  "testing",
8
17
  "three.js",
9
18
  "vitest",
10
19
  "vitest-environment",
11
20
  "webgl",
21
+ "webgl-testing",
12
22
  "webgl2"
13
23
  ],
14
24
  "homepage": "https://github.com/bhouston/vitest-gpu#readme",
@@ -56,7 +66,7 @@
56
66
  "node": ">=22"
57
67
  },
58
68
  "scripts": {
59
- "build": "tsc",
60
- "tsc": "tsc"
69
+ "build": "tsc -p tsconfig.build.json",
70
+ "tsc": "tsc --noEmit"
61
71
  }
62
72
  }
package/src/index.ts CHANGED
@@ -1,4 +1,11 @@
1
- import { getDisplayInfo, init, installDOM, type InitOptions, type InstallDOMOptions } from '@onirenaud/node-webgl';
1
+ import {
2
+ Canvas,
3
+ getDisplayInfo,
4
+ init,
5
+ installDOM,
6
+ type InitOptions,
7
+ type InstallDOMOptions,
8
+ } from '@onirenaud/node-webgl';
2
9
  import { readFile } from 'node:fs/promises';
3
10
  import { extname, resolve } from 'node:path';
4
11
  import { fileURLToPath } from 'node:url';
@@ -84,9 +91,23 @@ const installFetch = (global: typeof globalThis, baseDir: string): void => {
84
91
  Object.defineProperty(global, 'fetch', { value: localFetch, writable: true, configurable: true });
85
92
  };
86
93
 
94
+ /**
95
+ * The Vitest environment registered as `webgl-node`. Before each test file it installs node-webgl's `window`,
96
+ * `document`, `HTMLCanvasElement`, `Image`, `requestAnimationFrame` and `WebGL*` classes plus a file-reading
97
+ * `fetch()`, and it restores the original globals afterwards.
98
+ */
87
99
  export default {
100
+ /** The name Vitest uses to select this environment: `test.environment: 'webgl-node'`. */
88
101
  name: 'webgl-node',
102
+ /** Runs test files through Vite's `ssr` environment, as Node code. */
89
103
  viteEnvironment: 'ssr',
104
+ /**
105
+ * Installs the GL display and the DOM globals on the test file's global object.
106
+ *
107
+ * @param global - The global object of the test file's context.
108
+ * @param __namedParameters - The environment options from the Vitest config; `webglNode` holds {@link WebglNodeOptions}.
109
+ * @returns A `teardown` hook that destroys contexts and restores the globals this call changed.
110
+ */
90
111
  setup(global: typeof globalThis, { webglNode = {} }: { webglNode?: WebglNodeOptions }) {
91
112
  const { backend, api, ...dom } = webglNode;
92
113
  if (backend || api) {
@@ -103,11 +124,60 @@ export default {
103
124
  }
104
125
  init({ backend, api });
105
126
  }
127
+ const contexts = new Set<NonNullable<ReturnType<Canvas['getContext']>>>();
128
+ const frames = new Set<ReturnType<typeof setTimeout>>();
129
+ let disposed = false;
130
+ const dispose = () => {
131
+ disposed = true;
132
+ for (const frame of frames) clearTimeout(frame);
133
+ frames.clear();
134
+ for (const context of contexts) context.destroy();
135
+ contexts.clear();
136
+ };
137
+ const hasFrame = (global as unknown as Record<string, unknown>).requestAnimationFrame !== undefined;
106
138
  const before = snapshot(global);
107
139
  const nested: { target: object; before: PropertySnapshot; changed?: Set<PropertyKey> }[] = [];
108
140
  try {
109
141
  // node-webgl remembers fetch installation at module scope, which cannot represent separate Vitest environments.
110
142
  installDOM({ ...dom, fetch: false });
143
+ // Intercept the shared canvas API so imported factories and OffscreenCanvas are covered too.
144
+ const canvasBefore = snapshot(Canvas.prototype);
145
+ nested.push({ target: Canvas.prototype, before: canvasBefore });
146
+ // oxlint-disable-next-line typescript/unbound-method -- Canvas.prototype.getContext is patched/compared by identity, never called unbound
147
+ const getContext = Canvas.prototype.getContext;
148
+ Canvas.prototype.getContext = function (this: Canvas, ...args: Parameters<Canvas['getContext']>) {
149
+ if (disposed) throw new Error('WebGL environment has been torn down');
150
+ // node-webgl exposes the cached context at runtime but strips it from its declarations.
151
+ const previous = (this as Canvas & { _ctx?: ReturnType<Canvas['getContext']> })._ctx;
152
+ const context = getContext.apply(this, args);
153
+ if (context && context !== previous) contexts.add(context);
154
+ return context;
155
+ } as Canvas['getContext'];
156
+ nested.at(-1)!.changed = changedProperties(canvasBefore, Canvas.prototype);
157
+ // Own only the rAF shim installed by this setup; preserve host implementations.
158
+ if (!hasFrame) {
159
+ Object.defineProperty(global, 'requestAnimationFrame', {
160
+ configurable: true,
161
+ writable: true,
162
+ value: (callback: (time: number) => void) => {
163
+ if (disposed) return 0;
164
+ const frame = setTimeout(() => {
165
+ frames.delete(frame);
166
+ callback(performance.now());
167
+ }, dom.frameInterval ?? 16).unref();
168
+ frames.add(frame);
169
+ return frame;
170
+ },
171
+ });
172
+ Object.defineProperty(global, 'cancelAnimationFrame', {
173
+ configurable: true,
174
+ writable: true,
175
+ value: (frame: ReturnType<typeof setTimeout>) => {
176
+ frames.delete(frame);
177
+ clearTimeout(frame);
178
+ },
179
+ });
180
+ }
111
181
  if (dom.fetch !== false) installFetch(global, dom.baseDir ?? process.cwd());
112
182
  // node-webgl's window/document have no event methods; engines like Babylon.js register resize/blur listeners.
113
183
  const { window, document } = global as unknown as Record<string, Record<string, unknown>>;
@@ -120,6 +190,7 @@ export default {
120
190
  nested.at(-1)!.changed = changedProperties(targetBefore, target);
121
191
  }
122
192
  } catch (error) {
193
+ dispose();
123
194
  for (const item of nested.toReversed())
124
195
  restore(item.target, item.before, item.changed ?? changedProperties(item.before, item.target));
125
196
  restore(global, before, changedProperties(before, global));
@@ -127,9 +198,22 @@ export default {
127
198
  }
128
199
  const changed = changedProperties(before, global);
129
200
  return {
130
- teardown(g: Record<string, unknown>) {
131
- for (const item of nested.toReversed()) restore(item.target, item.before, item.changed!);
132
- restore(g, before, changed);
201
+ /**
202
+ * Destroys the WebGL contexts created during the test file, cancels pending animation-frame callbacks and
203
+ * restores the globals that `setup` replaced.
204
+ *
205
+ * @param g - The global object of the test file's context.
206
+ */
207
+ teardown: (g: Record<string, unknown>) => {
208
+ if (disposed) return;
209
+ try {
210
+ dispose();
211
+ } finally {
212
+ for (const item of nested.toReversed()) restore(item.target, item.before, item.changed!);
213
+ restore(g, before, changed);
214
+ nested.length = 0;
215
+ before.clear();
216
+ }
133
217
  },
134
218
  };
135
219
  },