wgsl-test 0.2.5 → 0.2.6

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.
Files changed (31) hide show
  1. package/README.md +38 -16
  2. package/dist/index.d.ts +72 -9
  3. package/dist/index.js +258 -64
  4. package/dist/index.js.map +1 -1
  5. package/dist/weslBundle.d.ts +20 -0
  6. package/dist/weslBundle.js +12 -0
  7. package/package.json +10 -5
  8. package/src/CompileShader.ts +41 -24
  9. package/src/TestComputeShader.ts +19 -19
  10. package/src/TestDiscovery.ts +50 -0
  11. package/src/TestFragmentShader.ts +13 -10
  12. package/src/TestVirtualLib.ts +18 -0
  13. package/src/TestWesl.ts +183 -0
  14. package/src/VitestImport.ts +23 -0
  15. package/src/WebGPUTestSetup.ts +28 -13
  16. package/src/index.ts +3 -0
  17. package/src/test/BackendCheck.test.ts +12 -0
  18. package/src/test/TestDiscovery.test.ts +77 -0
  19. package/src/test/TestWesl.test.ts +111 -0
  20. package/src/test/fixtures/wesl_test_pkg/package.json +4 -0
  21. package/src/test/fixtures/wesl_test_pkg/shaders/expect_eq.wesl +9 -0
  22. package/src/test/fixtures/wesl_test_pkg/shaders/failing_expect.wesl +5 -0
  23. package/src/test/fixtures/wesl_test_pkg/shaders/failing_near.wesl +5 -0
  24. package/src/test/fixtures/wesl_test_pkg/shaders/failing_ulp.wesl +8 -0
  25. package/src/test/fixtures/wesl_test_pkg/shaders/multiple_tests.wesl +7 -0
  26. package/src/test/fixtures/wesl_test_pkg/shaders/no_tests.wesl +1 -0
  27. package/src/test/fixtures/wesl_test_pkg/shaders/passing_expect.wesl +5 -0
  28. package/src/test/fixtures/wesl_test_pkg/shaders/passing_near.wesl +5 -0
  29. package/src/test/fixtures/wesl_test_pkg/shaders/passing_ulp.wesl +12 -0
  30. package/src/test/fixtures/wesl_test_pkg/wesl.toml +3 -0
  31. package/src/test_lib.wesl +89 -0
package/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # wgsl-test
2
2
 
3
- Write GPU shader tests as easily as regular unit tests. Test WGSL and WESL shaders with vitest or your favorite Node.js test framework.
3
+ Test WGSL and WESL shaders with vitest or your favorite Node.js test framework.
4
4
 
5
- - **Test WGSL shaders** - Works with standard `.wgsl` files, no new syntax required
6
- - **Test WESL shaders** - Import and compose shader dependencies via WESL
7
- - **Visual regression testing** - Snapshot comparison catches rendering changes
5
+ - **Native WESL** (`@test`) - Unit test shader functions, assertions run on GPU
6
+ - **TypeScript-driven** - Integration tests, visual regression, custom validation
8
7
 
9
8
  ## Installation
10
9
 
@@ -12,17 +11,42 @@ Write GPU shader tests as easily as regular unit tests. Test WGSL and WESL shade
12
11
  npm install wgsl-test
13
12
  ```
14
13
 
15
- Quick start in 3 steps:
14
+ ## Native WESL Testing
16
15
 
17
- 1. Write your shader function in WGSL or WESL as normal
18
- 2. Use `testCompute()`, `testFragment()`, `testFragmentImage()`, or `expectFragmentImage()` to test your shader with inline source or from files
19
- 3. Assert the results with your test framework
16
+ Write tests directly in WESL with the `@test` attribute. No boilerplate, assertions run on the GPU:
20
17
 
21
- ## Testing Compute Shaders
18
+ ```wgsl
19
+ // luminance_test.wesl
20
+ import lygia::color::luminance::luminance;
21
+ import wgsl_test::expectNear;
22
+
23
+ @test fn luminanceOrange() {
24
+ expectNear(luminance(vec3f(1.0, 0.5, 0.0)), 0.5702);
25
+ }
26
+
27
+ @test fn luminanceWhite() {
28
+ expectNear(luminance(vec3f(1.0, 1.0, 1.0)), 1.0);
29
+ }
30
+ ```
31
+
32
+ Run with a minimal TypeScript wrapper:
33
+
34
+ ```typescript
35
+ import { expectWesl, getGPUDevice } from "wgsl-test";
36
+
37
+ test("luminance", async () => {
38
+ const device = await getGPUDevice();
39
+ await expectWesl({ device, moduleName: "luminance_test" });
40
+ });
41
+ ```
22
42
 
23
- The default choice for unit testing shader functions. Flexible and explicit.
43
+ Use `runWesl()` instead if you need to inspect individual test results.
24
44
 
25
- Use `testCompute()` to test compute shader logic. A `test::results` buffer is automatically provided:
45
+ **[See API.md for assertion functions →](https://github.com/wgsl-tooling-wg/wesl-js/blob/main/tools/packages/wgsl-test/API.md#assertion-functions)**
46
+
47
+ ## Testing Compute Shaders
48
+
49
+ For more control, use `testCompute()` directly. A `test::results` buffer is automatically provided:
26
50
 
27
51
  ```typescript
28
52
  import { testCompute, getGPUDevice } from "wgsl-test";
@@ -47,7 +71,7 @@ const result = await testCompute({ device, src, size: 2 });
47
71
 
48
72
  ## Testing Fragment Shaders
49
73
 
50
- For unit testing shader functions that only run in fragment shaders. Tests a single pixel output.
74
+ Some functions only make sense in fragment shaders.
51
75
 
52
76
  Use `testFragment()` to test fragment shader rendering.
53
77
 
@@ -102,10 +126,8 @@ Snapshot comparison automatically detects rendering changes. Update snapshots wi
102
126
  - **[API.md#complete-test-example](https://github.com/wgsl-tooling-wg/wesl-js/blob/main/tools/packages/wgsl-test/API.md#complete-test-example)** - Full vitest test setup with beforeAll/afterAll
103
127
  - **[Examples](https://github.com/wgsl-tooling-wg/wesl-js/tree/main/tools/examples)** - Tiny standalone examples
104
128
 
105
- ## Future
129
+ ## Future
130
+
106
131
  What would you like to see next in wgsl-test?
107
- Test scaffolding for vertex shaders?
108
- Annotations to put simple tests in WESL directly?
109
- Something else?
110
132
 
111
133
  Please file an [issue](https://github.com/wgsl-tooling-wg/wesl-js/issues) or talk about your ideas on the tooling group [discord chat](https://discord.gg/5UhkaSu4dt).
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { DeviceCache, FragmentRenderParams, RenderUniforms, SamplerOptions, WeslOptions, checkerboardTexture, colorBarsTexture, createSampler, createUniformsVirtualLib, edgePatternTexture, fullscreenTriangleVertex, gradientTexture, noiseTexture, radialGradientTexture, renderUniformBuffer, simpleRender, solidTexture, updateRenderUniforms, withErrorScopes } from "wesl-gpu";
2
- import { LinkParams, ModuleResolver, WeslBundle } from "wesl";
2
+ import { FnElem, LinkParams, ModuleResolver, WeslAST, WeslBundle } from "wesl";
3
3
  import { WgslElementType, WgslElementType as WgslElementType$1 } from "thimbleberry";
4
4
  import { ImageData, ImageData as ImageData$1, MatchImageOptions } from "vitest-image-snapshot";
5
5
 
@@ -19,6 +19,8 @@ interface ResolveContextParams {
19
19
  projectDir?: string;
20
20
  /** Use source shaders instead of built bundles. Default: true. */
21
21
  useSourceShaders?: boolean;
22
+ /** Virtual lib names to exclude from dependency resolution. */
23
+ virtualLibNames?: string[];
22
24
  }
23
25
  interface CompileShaderParams {
24
26
  /** Project directory for resolving shader dependencies.
@@ -38,6 +40,12 @@ interface CompileShaderParams {
38
40
  /** Virtual libraries to include in the shader.
39
41
  * Allows dynamic generation of shader code at runtime. */
40
42
  virtualLibs?: LinkParams["virtualLibs"];
43
+ /** Additional WESL bundles to include.
44
+ * These are merged with auto-discovered dependencies. */
45
+ libs?: WeslBundle[];
46
+ /** Override the package name for module resolution.
47
+ * Used to ensure package:: references resolve correctly. */
48
+ packageName?: string;
41
49
  /** Use source shaders from current package instead of built bundles.
42
50
  * Default: true for faster iteration during development.
43
51
  * Set to false or use TEST_BUNDLES=true environment variable to test built bundles.
@@ -112,6 +120,14 @@ interface ComputeTestParams {
112
120
  * Can be a single number or [x, y, z] for multi-dimensional dispatch. */
113
121
  dispatchWorkgroups?: number | [number, number, number];
114
122
  }
123
+ interface RunComputeParams {
124
+ device: GPUDevice;
125
+ module: GPUShaderModule;
126
+ resultFormat?: WgslElementType$1;
127
+ size?: number;
128
+ dispatchWorkgroups?: number | [number, number, number];
129
+ entryPoint?: string;
130
+ }
115
131
  /**
116
132
  * Compiles and runs a compute shader on the GPU for testing.
117
133
  *
@@ -130,14 +146,17 @@ declare function testCompute(params: ComputeTestParams): Promise<number[]>;
130
146
  * Creates a storage buffer at @group(0) @binding(0) where the shader can
131
147
  * write output. The shader is invoked once, then the buffer is copied back
132
148
  * to the CPU for reading.
133
- *
134
- * @param module - The compiled GPUShaderModule containing the compute shader
135
- * @param resultFormat - Format for interpreting result buffer data (default: u32)
136
- * @param size - Size of result buffer in bytes (default: 16)
137
- * @param dispatchWorkgroups - Number of workgroups to dispatch (default: 1)
138
- * @returns Array containing the shader's output from the storage buffer
139
149
  */
140
- declare function runCompute(device: GPUDevice, module: GPUShaderModule, resultFormat?: WgslElementType$1, size?: number, dispatchWorkgroups?: number | [number, number, number]): Promise<number[]>;
150
+ declare function runCompute(params: RunComputeParams): Promise<number[]>;
151
+ //#endregion
152
+ //#region src/TestDiscovery.d.ts
153
+ interface TestFunctionInfo {
154
+ name: string;
155
+ description?: string;
156
+ fn: FnElem;
157
+ }
158
+ /** Find all functions marked with @test attribute in a parsed WESL module. */
159
+ declare function findTestFunctions(ast: WeslAST): TestFunctionInfo[];
141
160
  //#endregion
142
161
  //#region src/TestFragmentShader.d.ts
143
162
  interface FragmentTestParams extends WeslOptions, FragmentRenderParams {
@@ -188,9 +207,53 @@ declare function testFragment(params: FragmentTestParams): Promise<number[]>;
188
207
  */
189
208
  declare function testFragmentImage(params: FragmentTestParams): Promise<ImageData$1>;
190
209
  //#endregion
210
+ //#region src/TestVirtualLib.d.ts
211
+ /** Size of TestResult struct in bytes.
212
+ * Layout: u32 passed (4) + u32 failCount (4) + padding (8) + vec4f actual (16) + vec4f expected (16) = 48 */
213
+ declare const testResultSize = 48;
214
+ /** Virtual library for test:: namespace providing assertions and result reporting. */
215
+ declare function testVirtualLib(): string;
216
+ //#endregion
217
+ //#region src/TestWesl.d.ts
218
+ /** Parameters for running @test functions in a WESL module. */
219
+ type RunWeslParams = Omit<ComputeTestParams, "resultFormat" | "size" | "dispatchWorkgroups"> & {
220
+ /** Run only the @test function with this name */
221
+ testName?: string;
222
+ };
223
+ /** Result from running a single @test function on the GPU. */
224
+ interface TestResult {
225
+ name: string;
226
+ passed: boolean;
227
+ actual: number[];
228
+ expected: number[];
229
+ }
230
+ /** Parameters for testWesl() which registers all @test functions with vitest. */
231
+ type TestWeslParams = Omit<RunWeslParams, "testName">;
232
+ /**
233
+ * Discovers @test functions in a WESL module and registers each as a vitest test.
234
+ * Use top-level await in your test file to call this function.
235
+ */
236
+ declare function testWesl(params: TestWeslParams): Promise<void>;
237
+ /**
238
+ * Runs all @test functions and asserts they pass.
239
+ * Throws descriptive error on failure showing test name and actual/expected values.
240
+ */
241
+ declare function expectWesl(params: RunWeslParams): Promise<void>;
242
+ /**
243
+ * Runs all @test functions in a WESL module.
244
+ * Each test function is wrapped in a compute shader and dispatched.
245
+ * Returns results for all tests.
246
+ */
247
+ declare function runWesl(params: RunWeslParams): Promise<TestResult[]>;
248
+ //#endregion
191
249
  //#region src/WebGPUTestSetup.d.ts
250
+ declare const isDeno: boolean;
192
251
  /** get or create shared GPU device for testing */
193
252
  declare function getGPUDevice(): Promise<GPUDevice>;
253
+ /** get or create shared GPU object for testing */
254
+ declare function getGPU(): Promise<GPU>;
255
+ /** get or create shared GPU adapter for testing */
256
+ declare function getGPUAdapter(): Promise<GPUAdapter>;
194
257
  /** destroy globally shared GPU test device */
195
258
  declare function destroySharedDevice(): void;
196
259
  //#endregion
@@ -201,5 +264,5 @@ declare module "vitest" {
201
264
  }
202
265
  }
203
266
  //#endregion
204
- export { CompileShaderParams, ComputeTestParams, DeviceCache, FragmentImageTestParams, FragmentTestParams, type ImageData, type RenderUniforms, ResolveContextParams, type SamplerOptions, ShaderContext, type WgslElementType, checkerboardTexture, colorBarsTexture, compileShader, createProjectResolver, createSampler, createUniformsVirtualLib, destroySharedDevice, edgePatternTexture, expectFragmentImage, fullscreenTriangleVertex, getGPUDevice, gradientTexture, lemurImagePath, lemurTexture, noiseTexture, pngToTexture, radialGradientTexture, renderUniformBuffer, resolveShaderContext, runCompute, simpleRender, solidTexture, testCompute, testFragment, testFragmentImage, updateRenderUniforms, withErrorScopes };
267
+ export { CompileShaderParams, ComputeTestParams, DeviceCache, FragmentImageTestParams, FragmentTestParams, type ImageData, type RenderUniforms, ResolveContextParams, RunComputeParams, RunWeslParams, type SamplerOptions, ShaderContext, TestFunctionInfo, TestResult, TestWeslParams, type WgslElementType, checkerboardTexture, colorBarsTexture, compileShader, createProjectResolver, createSampler, createUniformsVirtualLib, destroySharedDevice, edgePatternTexture, expectFragmentImage, expectWesl, findTestFunctions, fullscreenTriangleVertex, getGPU, getGPUAdapter, getGPUDevice, gradientTexture, isDeno, lemurImagePath, lemurTexture, noiseTexture, pngToTexture, radialGradientTexture, renderUniformBuffer, resolveShaderContext, runCompute, runWesl, simpleRender, solidTexture, testCompute, testFragment, testFragmentImage, testResultSize, testVirtualLib, testWesl, updateRenderUniforms, withErrorScopes };
205
268
  //# sourceMappingURL=index.d.ts.map