---
title: Browser testing with Playwright WebGPU
description: Browser tests should exercise the same public API users copy: `init()`, `surface(gpu, canvas, opts)`, explicit targets, and deterministic frame submission. Avoid hidden app globals and avoid relying on a continuous loop in assertions.
---

# Browser testing with Playwright WebGPU



```text
import { init } from "vgpu";

export async function renderOnce(canvas: HTMLCanvasElement) {
  const gpu = await init();
  const surface = surface(gpu, canvas, { dpr: 1, autoResize: false });
  const effect = effect(gpu, WGSL, { set: { time: 0, texel: surface.texelSize } });
  frame(gpu, (f) => f.pass({ target: surface, clear: [0, 0, 0, 1] }, (p) => p.draw(effect)));
  return gpu;
}
```

## Test checklist

* Use fixed DPR/size (`dpr: 1`, `autoResize: false`, or explicit `size`) for pixel snapshots.
* Submit with `frame(gpu, ...)` for one deterministic frame, not `requestAnimationFrame` loops.
* Read from explicit surfaces or offscreen targets with `target.read()`.
* Keep WGSL imports pure: modules export helpers only; bindings live in the entry shader. If a module declares a binding, fix `VGPU-RESOLVE-MODULE-BINDING`.
* For headless tests use `vgpu/mock` for deterministic unit tests and `vgpu/node` only when Dawn/WebGPU behavior is under test.


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)