@quake2ts/test-utils 0.0.807 → 0.0.809

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.807",
3
+ "version": "0.0.809",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -45,10 +45,10 @@
45
45
  "serve-handler": "^6.1.6",
46
46
  "vitest": "^1.6.0",
47
47
  "webgpu": "^0.3.8",
48
- "@quake2ts/engine": "^0.0.807",
49
- "@quake2ts/game": "0.0.807",
50
- "@quake2ts/server": "0.0.807",
51
- "@quake2ts/shared": "0.0.807"
48
+ "@quake2ts/engine": "^0.0.809",
49
+ "@quake2ts/game": "0.0.809",
50
+ "@quake2ts/server": "0.0.809",
51
+ "@quake2ts/shared": "0.0.809"
52
52
  },
53
53
  "peerDependenciesMeta": {
54
54
  "@quake2ts/engine": {
@@ -104,10 +104,10 @@
104
104
  "vitest": "^4.0.16",
105
105
  "serve-handler": "^6.1.6",
106
106
  "webgpu": "^0.3.8",
107
- "@quake2ts/engine": "^0.0.807",
108
- "@quake2ts/game": "0.0.807",
109
- "@quake2ts/server": "0.0.807",
110
- "@quake2ts/shared": "0.0.807"
107
+ "@quake2ts/engine": "^0.0.809",
108
+ "@quake2ts/game": "0.0.809",
109
+ "@quake2ts/server": "0.0.809",
110
+ "@quake2ts/shared": "0.0.809"
111
111
  },
112
112
  "dependencies": {
113
113
  "upng-js": "^2.1.0"
@@ -7,8 +7,10 @@
7
7
 
8
8
  import type { Browser, Page, BrowserContext } from 'playwright';
9
9
  import { expectSnapshot, SnapshotTestOptions } from '../../visual/snapshots.js';
10
+ import { expectAnimationSnapshot, AnimationSnapshotOptions } from '../../visual/animation-snapshots.js';
10
11
  import { createServer, IncomingMessage, ServerResponse } from 'http';
11
12
  import path from 'path';
13
+ import fs from 'fs';
12
14
 
13
15
  export interface WebGLPlaywrightSetup {
14
16
  browser: Browser;
@@ -26,6 +28,18 @@ export interface WebGLPlaywrightOptions {
26
28
  headless?: boolean;
27
29
  }
28
30
 
31
+ function findWorkspaceRoot(startDir: string): string {
32
+ let currentDir = startDir;
33
+ while (currentDir !== path.parse(currentDir).root) {
34
+ if (fs.existsSync(path.join(currentDir, 'pnpm-workspace.yaml'))) {
35
+ return currentDir;
36
+ }
37
+ currentDir = path.dirname(currentDir);
38
+ }
39
+ // Fallback to process.cwd() if not found (though unexpected in this repo)
40
+ return process.cwd();
41
+ }
42
+
29
43
  /**
30
44
  * Creates a Playwright-based WebGL test setup with the actual quake2ts renderer.
31
45
  * Starts a static server, loads the built renderer bundle, and provides a clean testing environment.
@@ -56,9 +70,9 @@ export async function createWebGLPlaywrightSetup(
56
70
  }
57
71
 
58
72
  // Start static server to serve built files
59
- // Serve from repo root so we can access packages/engine/dist
60
- // Note: __dirname is handled by tsup shims to work in both ESM and CJS
61
- const repoRoot = path.resolve(__dirname, '../../../../..');
73
+ // Find workspace root robustly (works from src or dist, and regardless of CWD)
74
+ // We start looking from __dirname (which might be src/... or dist/...)
75
+ const repoRoot = findWorkspaceRoot(__dirname);
62
76
 
63
77
  const staticServer = createServer((request: IncomingMessage, response: ServerResponse) => {
64
78
  return handler(request, response, {
@@ -148,16 +162,18 @@ export async function createWebGLPlaywrightSetup(
148
162
  * @param renderFn - Function code as string that uses window.testRenderer
149
163
  * @param width - Optional width to resize the canvas to
150
164
  * @param height - Optional height to resize the canvas to
165
+ * @param frameIndex - Optional frame index passed to the render function
151
166
  * @returns Captured pixel data
152
167
  */
153
168
  export async function renderAndCaptureWebGLPlaywright(
154
169
  page: Page,
155
170
  renderFn: string,
156
171
  width?: number,
157
- height?: number
172
+ height?: number,
173
+ frameIndex: number = 0
158
174
  ): Promise<Uint8ClampedArray> {
159
175
  try {
160
- const pixelData = await page.evaluate(({ code, width, height }) => {
176
+ const pixelData = await page.evaluate(({ code, width, height, frameIndex }) => {
161
177
  const renderer = (window as any).testRenderer;
162
178
  const gl = (window as any).testGl;
163
179
  const canvas = (window as any).testCanvas;
@@ -175,8 +191,8 @@ export async function renderAndCaptureWebGLPlaywright(
175
191
 
176
192
  try {
177
193
  // Execute the render function
178
- const fn = new Function('renderer', 'gl', code);
179
- fn(renderer, gl);
194
+ const fn = new Function('renderer', 'gl', 'frameIndex', code);
195
+ fn(renderer, gl, frameIndex);
180
196
  } catch (err: any) {
181
197
  // Capture context for better debugging
182
198
  throw new Error(`Renderer Execution Error: ${err.message}\nCode:\n${code}`);
@@ -187,7 +203,7 @@ export async function renderAndCaptureWebGLPlaywright(
187
203
 
188
204
  // Capture pixels
189
205
  return (window as any).captureCanvas();
190
- }, { code: renderFn, width, height });
206
+ }, { code: renderFn, width, height, frameIndex });
191
207
 
192
208
  return new Uint8ClampedArray(pixelData);
193
209
  } catch (err: any) {
@@ -245,3 +261,55 @@ export async function testWebGLRenderer(
245
261
  await setup.cleanup();
246
262
  }
247
263
  }
264
+
265
+ /**
266
+ * Runs a WebGL animated visual test with the actual quake2ts renderer.
267
+ *
268
+ * Usage:
269
+ * ```ts
270
+ * await testWebGLAnimation(`
271
+ * // frameIndex is available here
272
+ * gl.clearColor(frameIndex * 0.1, 0, 0, 1);
273
+ * gl.clear(gl.COLOR_BUFFER_BIT);
274
+ * `, {
275
+ * name: 'animated-red',
276
+ * description: 'Fading red animation',
277
+ * width: 256,
278
+ * height: 256,
279
+ * frameCount: 10,
280
+ * fps: 10,
281
+ * snapshotDir: __dirname
282
+ * });
283
+ * ```
284
+ */
285
+ export async function testWebGLAnimation(
286
+ renderCode: string,
287
+ options: AnimationSnapshotOptions & WebGLPlaywrightOptions
288
+ ): Promise<void> {
289
+ const setup = await createWebGLPlaywrightSetup(options);
290
+
291
+ try {
292
+ await expectAnimationSnapshot(async (frameIndex) => {
293
+ return renderAndCaptureWebGLPlaywright(
294
+ setup.page,
295
+ renderCode,
296
+ options.width,
297
+ options.height,
298
+ frameIndex
299
+ );
300
+ }, {
301
+ name: options.name,
302
+ description: options.description,
303
+ width: setup.width,
304
+ height: setup.height,
305
+ frameCount: options.frameCount,
306
+ fps: options.fps,
307
+ updateBaseline: options.updateBaseline,
308
+ snapshotDir: options.snapshotDir,
309
+ threshold: options.threshold,
310
+ maxDifferencePercent: options.maxDifferencePercent
311
+ });
312
+ } finally {
313
+ await setup.cleanup();
314
+ }
315
+ }