@quake2ts/test-utils 0.0.848 → 0.0.850

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quake2ts/test-utils",
3
- "version": "0.0.848",
3
+ "version": "0.0.850",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -55,10 +55,10 @@
55
55
  "serve-handler": "^6.1.6",
56
56
  "vitest": "^1.6.0",
57
57
  "webgpu": "^0.3.8",
58
- "@quake2ts/engine": "^0.0.848",
59
- "@quake2ts/server": "0.0.848",
60
- "@quake2ts/shared": "0.0.848",
61
- "@quake2ts/game": "0.0.848"
58
+ "@quake2ts/engine": "^0.0.850",
59
+ "@quake2ts/game": "0.0.850",
60
+ "@quake2ts/shared": "0.0.850",
61
+ "@quake2ts/server": "0.0.850"
62
62
  },
63
63
  "peerDependenciesMeta": {
64
64
  "@quake2ts/engine": {
@@ -114,10 +114,10 @@
114
114
  "typescript": "^5.9.3",
115
115
  "vitest": "^4.0.16",
116
116
  "webgpu": "^0.3.8",
117
- "@quake2ts/engine": "^0.0.848",
118
- "@quake2ts/game": "0.0.848",
119
- "@quake2ts/server": "0.0.848",
120
- "@quake2ts/shared": "0.0.848"
117
+ "@quake2ts/engine": "^0.0.850",
118
+ "@quake2ts/game": "0.0.850",
119
+ "@quake2ts/server": "0.0.850",
120
+ "@quake2ts/shared": "0.0.850"
121
121
  },
122
122
  "dependencies": {
123
123
  "upng-js": "^2.1.0"
@@ -1,10 +1,10 @@
1
1
  import { test as base } from 'vitest';
2
+ import { expectSnapshot } from '../../visual/snapshots.js';
2
3
  import {
3
- expectSnapshot,
4
4
  createRenderTestSetup,
5
5
  RenderTestSetup,
6
6
  captureTexture
7
- } from '@quake2ts/test-utils';
7
+ } from '../helpers/webgpu-rendering.js';
8
8
  import path from 'path';
9
9
 
10
10
  interface VisualTestContext {
package/src/index.ts CHANGED
@@ -30,6 +30,7 @@ export * from './server/helpers/bandwidth.js';
30
30
  export * from './setup/browser.js';
31
31
  export * from './setup/canvas.js';
32
32
  export * from './setup/webgpu.js';
33
+ export * from './setup/webgpu-lifecycle.js';
33
34
  // Safe to export now as gl is lazy loaded
34
35
  export * from './setup/headless-webgl.js';
35
36
  export * from './engine/mocks/webgpu.js';
@@ -72,6 +73,7 @@ export * from './client/helpers/prediction.js';
72
73
  // Visual Testing
73
74
  export * from './visual/snapshots.js';
74
75
  export * from './visual/animation-snapshots.js';
76
+ export { test } from './engine/builders/visual-testing.js';
75
77
 
76
78
  // E2E
77
79
  export * from './e2e/playwright.js';
@@ -0,0 +1,102 @@
1
+ /**
2
+ * WebGPU Device Lifecycle Management for Integration Tests
3
+ *
4
+ * Provides utilities to track and cleanup GPUDevice instances created during tests,
5
+ * preventing resource leaks.
6
+ *
7
+ * Usage:
8
+ * ```ts
9
+ * describe('My WebGPU Tests', () => {
10
+ * const lifecycle = createWebGPULifecycle();
11
+ *
12
+ * beforeAll(async () => {
13
+ * await initHeadlessWebGPU();
14
+ * });
15
+ *
16
+ * afterAll(lifecycle.cleanup);
17
+ *
18
+ * it('test', async () => {
19
+ * const context = await createWebGPUContext();
20
+ * lifecycle.track(context.device);
21
+ * // ... test code
22
+ * });
23
+ * });
24
+ * ```
25
+ */
26
+
27
+ export interface WebGPULifecycle {
28
+ /**
29
+ * Track a GPUDevice for cleanup
30
+ */
31
+ track(device: GPUDevice): void;
32
+
33
+ /**
34
+ * Track a renderer with a device property for cleanup
35
+ */
36
+ trackRenderer(renderer: { device: GPUDevice; dispose: () => void }): void;
37
+
38
+ /**
39
+ * Cleanup all tracked devices
40
+ * Call this in afterAll hook
41
+ */
42
+ cleanup(): Promise<void>;
43
+
44
+ /**
45
+ * Get count of tracked devices
46
+ */
47
+ count(): number;
48
+ }
49
+
50
+ /**
51
+ * Create a WebGPU lifecycle manager for tracking and cleaning up devices
52
+ */
53
+ export function createWebGPULifecycle(): WebGPULifecycle {
54
+ const devices: GPUDevice[] = [];
55
+ const renderers: Array<{ device: GPUDevice; dispose: () => void }> = [];
56
+
57
+ return {
58
+ track(device: GPUDevice): void {
59
+ devices.push(device);
60
+ },
61
+
62
+ trackRenderer(renderer: { device: GPUDevice; dispose: () => void }): void {
63
+ renderers.push(renderer);
64
+ },
65
+
66
+ async cleanup(): Promise<void> {
67
+ // Dispose renderers first (they may destroy their devices)
68
+ for (const renderer of renderers) {
69
+ try {
70
+ renderer.dispose();
71
+ } catch (e) {
72
+ console.warn('Error disposing renderer:', e);
73
+ }
74
+ }
75
+ renderers.length = 0;
76
+
77
+ // Collect all devices and their lost promises
78
+ const allDevices = [...devices];
79
+ devices.length = 0;
80
+
81
+ if (allDevices.length === 0) return;
82
+
83
+ // Wait for all devices to be destroyed
84
+ const lostPromises = allDevices.map(d => d.lost);
85
+ for (const device of allDevices) {
86
+ try {
87
+ device.destroy();
88
+ } catch (e) {
89
+ // Device might already be destroyed
90
+ console.warn('Error destroying device:', e);
91
+ }
92
+ }
93
+
94
+ // Wait for all devices to report as lost
95
+ await Promise.all(lostPromises);
96
+ },
97
+
98
+ count(): number {
99
+ return devices.length + renderers.length;
100
+ }
101
+ };
102
+ }