qunitx-cli
Browser-based test runner for QUnitX — bundles your JS/TS tests with esbuild, runs them in a headless browser via Playwright, and streams TAP output to the terminal.

Features
- Runs
.jsand.tstest files in headless Chrome, Firefox, or WebKit (Playwright + esbuild) - TypeScript works with zero configuration — esbuild handles transpilation
- Inline source maps for accurate stack traces pointing to original source files
- Streams TAP-formatted output to the terminal in real time
- Concurrent mode (default) splits test files across all CPU cores for fast parallel runs
--watchmode re-runs affected tests on file change--failFaststops the run after the first failing test--debugprints the local server URL and pipes browser console to stdout--before/--afterhook scripts for server setup and teardown--timeoutcontrols the maximum ms to wait for the full suite to finish--browserflag to run tests in Chromium, Firefox, or WebKit- Docker image for zero-install CI usage
Installation
Requires Node.js >= 24.
npm install --save-dev qunitx-cli
Or run without installing:
npx qunitx test/**/*.js
With Docker — no install needed:
docker run --rm -v "$(pwd):/code" -w /code ghcr.io/izelnakri/qunitx-cli:latest npx qunitx test/**/*.js
With Nix:
nix profile install github:izelnakri/qunitx-cli
Usage
# Single file qunitx test/my-test.js # Multiple files / globs qunitx test/**/*.js test/**/*.ts # TypeScript — no tsconfig required qunitx test/my-test.ts # Watch mode: re-run on file changes qunitx test/**/*.js --watch # Stop on the first failure qunitx test/**/*.js --failFast # Print the server URL and pipe browser console to stdout qunitx test/**/*.js --debug # Custom timeout (ms) qunitx test/**/*.js --timeout=30000 # Run a setup script before tests (can be async — awaited automatically) qunitx test/**/*.js --before=scripts/start-server.js # Run a teardown script after tests (can be async) qunitx test/**/*.js --after=scripts/stop-server.js # Run in Firefox or WebKit instead of Chromium qunitx test/**/*.js --browser=firefox qunitx test/**/*.js --browser=webkit
Prerequisite for Firefox / WebKit: install the Playwright browser binaries once:
npx playwright install firefox npx playwright install webkit
Writing Tests
qunitx-cli runs QUnitX tests — a superset of QUnit with async hooks, concurrency control, and test metadata.
Migrating from QUnit? Change a single import:
// before import { module, test } from 'qunit'; // after import { module, test } from 'qunitx';
Example test file — ES modules, npm imports, and nested modules all work out of the box:
// some-test.js (TypeScript is also supported) import { module, test } from 'qunitx'; import $ from 'jquery'; module('Basic sanity check', (hooks) => { test('it works', (assert) => { assert.equal(true, true); }); module('More advanced cases', (hooks) => { test('deepEqual works', (assert) => { assert.deepEqual({ username: 'izelnakri' }, { username: 'izelnakri' }); }); test('can import ES & npm modules', (assert) => { assert.ok(Object.keys($)); }); }); });
Run it:
# Headless Chromium (default, recommended for CI) qunitx some-test.js # With browser console output qunitx some-test.js --debug # TypeScript — no config needed qunitx some-test.ts
Configuration
All CLI flags can also be set in package.json under the qunitx key, so you don't have to repeat them on every invocation:
{ "qunitx": { "inputs": ["test/**/*-test.js", "test/**/*-test.ts"], "extensions": ["js", "ts"], "output": "tmp", "timeout": 20000, "failFast": false, "port": 1234, "browser": "chromium" } }
| Key | Default | Description |
|---|---|---|
inputs |
[] |
Glob patterns, file paths, or directories to use as test entry points. Merged with any paths given on the CLI. |
extensions |
["js", "ts"] |
File extensions tracked for test discovery (directory scans) and watch-mode rebuild triggers. Add "mjs", "cjs", or any other extension your project uses. |
output |
"tmp" |
Directory where compiled test bundles are written. |
timeout |
20000 |
Maximum milliseconds to wait for the full test suite before timing out. |
failFast |
false |
Stop the run after the first failing test. |
port |
1234 |
Preferred HTTP server port. qunitx auto-selects a free port if this one is taken. |
browser |
"chromium" |
Browser engine to use: "chromium", "firefox", or "webkit". Overridden by --browser on the CLI. |
CLI flags always override package.json values when both are present.
CLI Reference
Usage: qunitx [files/folders...] [options] Options: --watch Re-run tests on file changes --failFast Stop after the first failure --debug Print the server URL; pipe browser console to stdout --timeout=<ms> Max ms to wait for the suite to finish [default: 20000] --output=<dir> Directory for compiled test assets [default: ./tmp] --extensions=<...> Comma-separated file extensions to track [default: js,ts] --before=<file> Script to run (and optionally await) before tests start --after=<file> Script to run (and optionally await) after tests finish --port=<n> HTTP server port (auto-selects a free port if taken) --browser=<name> Browser engine: chromium (default), firefox, or webkit
Development
npm install make check # lint + test (run before every commit) make test # run full test suite (Chromium) make test-firefox # run browser tests with Firefox make test-webkit # run browser tests with WebKit make test-all-browsers # run full suite on all three browsers make demo # regenerate docs/demo.gif make release LEVEL=patch # bump version, update changelog, tag, push
Use --trace-perf to print internal timing to stderr — useful when investigating startup or e2e regressions:
qunitx test/my-test.js --trace-perf
License
MIT
Usage
import * as mod from "README.md";