Skip to content

Contributing

Testing

Which tests run on any machine, which need a GPU and model files, and what CI checks.

Unit tests and browser tests (headless Chromium on SwiftShader, a software GPU) run on any machine and cover most room, Code mode and Serve API changes. GPU tests need WebGPU in Deno and the model files.

npm test # unit tests (Deno), 84 test files in tests/unit
npm run check # type-check the engine, syntax-check everything else
tests/run.sh selftest # proves the GPU runner fails on a printed FAIL

The browser tests need npm install first, for Playwright and the peer signaling server:

npm run e2e:code # Code mode end to end: two tabs, a real room, a scripted model builds and fixes Tetris
node tests/e2e/preview_browser.mjs # the Code mode preview sandbox
node tests/e2e/room_synth.mjs # the real engine and room on a tiny synthetic model
node tests/e2e/signal_fallback.mjs # signaling fallback: cloud down, one server down, all down, a drop mid-room

harness_tetris.mjs (behind e2e:code) and room_synth.mjs take --port and --signal-port when the default ports are busy.

The Serve API bridge has its own Node tests:

npm ci --prefix cli
node --test cli/test/*_test.mjs # drives the bridge with the official openai and anthropic SDKs

You need a GPU with WebGPU and Deno 2. Put the model files under models/ (it is git-ignored):

models/
qwen/ model.gguf (Qwen3 0.6B Q8_0), model-q4.gguf, tokenizer.json, config.json
qwen17/ model.gguf, tokenizer.json, config.json # Qwen3 1.7B, Code mode's small model
q38/ model.gguf (Qwen 3.8 27B Q4_0)
q36moe/ Qwen_Qwen3.6-35B-A3B-Q4_0.gguf # for tests/test_moe.js
model/ SmolLM2-135M: model.safetensors, tokenizer.json, config.json

Run the suites through tests/run.sh:

Command What it runs Needs
npm run test:gpu (run.sh quick) Golden tests on Qwen3 0.6B and SmolLM, streams, batching, splits The small models. About a minute.
npm run test:q38 (run.sh q38) The 27B suites, including speculative decoding equal to plain, one process per file About 16 GB of GPU memory. The reference run before you land.
npm run test:q38once The same 27B checks in one process with one weight upload About a minute once the cache is warm.
tests/run.sh extra MoE, sharding, splits, the full 27B: GPU tests no other suite covers The MoE and 27B files.
npm run test:all quick plus q38

A test fails if it exits nonzero or prints FAIL/FAILED. STRICT=1 also fails on SKIP; ONLY=test_mtp,test_ctx runs a subset of q38once.

To run one test on its own:

cd tests && deno run --unstable-webgpu --allow-read --allow-env test_qwen.js

The 27B and MoE tests keep converted tensors in ~/.cache/swarmllm-weights (about 16 GB and 20 GB), so a warm load takes seconds instead of converting the GGUF again.

Variable Effect
WEIGHT_CACHE=0 Turn the cache off.
WEIGHT_CACHE=<dir> Keep the cache somewhere else.
WEIGHT_CACHE_VERIFY=1 Also check each entry’s checksum (about 1.5 times the warm load time).
WEIGHT_CACHE_PRUNE=1 Delete directories left over from older loader versions.

Any edit to engine/gguf.js starts a new cache directory. npm run test:cache checks the cache is byte-identical.

Real rooms between headless Chromium tabs on your machine. GPU needed; run by hand.

Command What it checks
npm run e2e -- --phone Host, worker and a phone-shaped tab. --wire off|slice|stripeN picks the transport.
node tests/e2e/room_chaos.mjs --devices 3 --plan net Latency, loss and freezes (no root). Other plans: death, signal, join, turn.
node tests/e2e/room_drop.mjs --devices 3 A silent device is noticed in 3 to 5 s; a bad network is not mistaken for one.
node tests/e2e/room_resume.mjs Lock, reload or kill a device mid-answer; the text must match an uninterrupted run.
node tests/e2e/room_latency.mjs --model qwen3.6-35b-moe --devices 2 --lat 0,5,20 Speed against emulated latency.
node tests/e2e/serve.mjs pooled serve against a real 1.7B room with the official SDKs; --codex, --claude run an agent turn.

Rigs for two machines (tests/e2e/xroom_pair.sh, xroom_report.mjs) and a USB-attached iPhone (xroom_phone.mjs, xroom_cluster.sh, resume_phone.mjs) are described in docs/testing-fast.md. The phone must open an https page, and all devices must run the same commit.

Every pull request and every push to main runs two jobs on GitHub’s Ubuntu runners:

  1. node --check on every engine, room, harness, site, test, benchmark and script file.
  2. The unit tests, deno test --parallel --allow-read tests/unit, with a JUnit report.
  3. The pooled serve bridge tests (node --test cli/test/*_test.mjs).
  4. A sanity check of the kernel generator (tests/unit/generator_smoke.js).
  5. scripts/check-test-report.mjs, which fails the run on zero tests, or on a skipped test that isn’t on its allowed list.
  6. tests/run.sh selftest.

CI has no GPU, so say in your PR which GPU tests you ran, and on which GPU.