qunitx-cli

CI codecov npm npm downloads License: MIT

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.

qunitx-cli demo

Features

  • Runs .js and .ts test 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
  • --watch mode re-runs affected tests on file change
  • --failFast stops the run after the first failing test
  • --debug prints the local server URL and pipes browser console to stdout
  • --before / --after hook scripts for server setup and teardown
  • --timeout controls the maximum ms to wait for the full suite to finish
  • --browser flag 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