#wgsl-test
Test WGSL and WESL shaders with the CLI or vitest.
- Native WESL (
@test) — Unit test shader functions, assertions run on the GPU - CLI (
wgsl-test run) — Run tests from the command line - TypeScript — Optionally run tests from vitest or jest.
#Installation
npm install wgsl-test
#Native WESL Testing
Write tests directly in WESL with the @test attribute.
Minimal boilerplate, assertions run on the GPU:
/// interp_test.wesl
import package::interp::smootherstep;
import wgsl_test::expectNear;
@test
fn smootherstepQuarter() {
expectNear(smootherstep(0.0, 1.0, 0.25), 0.103516);
}
See the assertion functions reference for expect, expectNear, expectNearV2f, and more.
#CLI
Run tests directly from the command line:
wgsl-test run # discover **/*.test.wesl, run all
wgsl-test run path/to/test.wesl # run specific file(s)
wgsl-test run --projectDir ./foo # specify project root
#Vitest Integration
Or run GPU shader tests from vitest with a minimal TypeScript wrapper:
import { getGPUDevice, testWesl } from "wgsl-test";
const device = await getGPUDevice();
await testWesl({ device, moduleName: "interp_test" });
#Visual Regression Testing
Test complete rendered images in vitest:
import { expectFragmentImage } from "wgsl-test";
import { imageMatcher } from "vitest-image-snapshot";
imageMatcher(); // setup once
test("blur shader matches snapshot", async () => {
await expectFragmentImage(device, "effects/blur.wgsl");
// snapshot compared against __image_snapshots__/effects-blur.png
});
Update snapshots with vitest -u.
See the visual regression testing reference for details.
#Testing Compute Shaders
If you want to validate results in TypeScript,
use testCompute() for compute shader tests.
A test::results buffer is automatically provided:
import { testCompute, getGPUDevice } from "wgsl-test";
const device = await getGPUDevice();
const src = ` // test function can be an inline WESL string or a .wesl file
import package::hash::lowbias32;
@compute @workgroup_size(1)
fn main() {
test::results[0] = lowbias32(0u);
test::results[1] = lowbias32(42u);
}
`;
// results returned to TypeScript for validation
const result = await testCompute({ device, src, size: 2 });
// result = [0, 388445122]