Ensures a daemon is running for this project, spawning one if there isn't.
Probes this project's daemon. An actual round-trip over the socket, not a look at the sentinel
file, so a crashed daemon that left its files behind reports { running: false }.
Stops this project's daemon. Resolves true if one was running, false if there was nothing
to stop — either way, no daemon is running afterwards.
Runs the suite inside this project's daemon and resolves with the same RunResult a local run would produce — reusing the daemon's browser and warm bundle instead of paying for a fresh one.
The options a daemon run accepts: everything from UserRunOptions that survives a socket.
-
reporter: ReporterName | false
One built-in reporter by name, or
false. An instance cannot cross a socket. -
reporters: ReadonlyArray<ReporterName>
Several built-in reporters by name. Mutually exclusive with
reporter, as it is locally.
Every way a daemon-routed run can fail to produce an exit code.
| { running: true; pid: number; cwd: string; nodeVersion: string; startedAt: number; socketPath: string; }
A live daemon, as reported by status.
The qunitx JS API: run your QUnit tests in a real browser from Node.js or Deno, and get the results back as a value.
Ensures a daemon is running for this project, spawning one if there isn't.
Probes this project's daemon. An actual round-trip over the socket, not a look at the sentinel
file, so a crashed daemon that left its files behind reports { running: false }.
Stops this project's daemon. Resolves true if one was running, false if there was nothing
to stop — either way, no daemon is running afterwards.
Runs the suite inside this project's daemon and resolves with the same RunResult a local run would produce — reusing the daemon's browser and warm bundle instead of paying for a fresh one.
With watch: true, the DURABLE shape: one page behind a stable WatchSession.url, kept
open with the rerun verbs and file watching, exactly as watch gives you.
With watch: true, the DURABLE shape: one page behind a stable WatchSession.url, kept
open with the rerun verbs and file watching, exactly as watch gives you.
With watch: true, the DURABLE shape: one page behind a stable WatchSession.url, kept
open with the rerun verbs and file watching, exactly as watch gives you.
With watch: true, the DURABLE shape: one page behind a stable WatchSession.url, kept
open with the rerun verbs and file watching, exactly as watch gives you.
With watch: true, the DURABLE shape: one page behind a stable WatchSession.url, kept
open with the rerun verbs and file watching, exactly as watch gives you.
Runs ONE file as a plain script in a real browser — the API twin of qunitx run <file>, and the
sibling of test, which runs a suite.
Bootstraps a qunitx project: writes the test HTML template, updates package.json, and writes tsconfig.json when there isn't one.
Writes a new test file from the boilerplate template, deriving the QUnit module name from the path. Never overwrites an existing file.
Lists the tests a selection would run, without running them.
Adapts anything with a write(string) — a node:fs stream, a socket, an array-backed fake —
into a Console. stderr defaults to stdout, so one stream collects the whole run.
Runs the suite once in a real browser and resolves with everything it produced.
Runs the suite once in a real browser and resolves with everything it produced.
Runs the suite once in a real browser and resolves with everything it produced.
Rejects options the run cannot honour, before anything is launched.
Starts a watch session: builds once, runs once, then re-runs on every save until closed.
Starts a watch session: builds once, runs once, then re-runs on every save until closed.
Starts a watch session: builds once, runs once, then re-runs on every save until closed.
A console.* call or an uncaught error from the page under test.
-
args: unknown[]
The call's arguments, resolved to JSON values where the page could serialize them.
-
text: string
The rendered single-line text. Always present.
-
type: string
The page console type (
log/warning/error/info/debug), orpageerror.
Where a run's text goes: console, made injectable.
-
error(text: string): void
Writes to the error stream. Diagnostics that must survive a swallowed stdout go here too.
-
log(text: string): void
Writes to the primary stream — the TAP/spec/dot document itself.
The run's line coverage: one entry per source file, plus the totals across all of them.
-
coverableLines: number
Coverable lines across every file.
-
coveredLines: number
Covered lines across every file.
-
files: FileCoverageSummary[]
One entry per non-test source file the bundle mapped back to.
-
percent: number
Overall percentage covered.
The options a daemon run accepts: everything from UserRunOptions that survives a socket.
-
reporter: ReporterName | false
One built-in reporter by name, or
false. An instance cannot cross a socket. -
reporters: ReadonlyArray<ReporterName>
Several built-in reporters by name. Mutually exclusive with
reporter, as it is locally.
The options a daemon run accepts: everything from UserRunOptions that survives a socket.
-
reporter: ReporterName | false
One built-in reporter by name, or
false. An instance cannot cross a socket. -
reporters: ReadonlyArray<ReporterName>
Several built-in reporters by name. Mutually exclusive with
reporter, as it is locally.
Per-file line coverage, when coverage was requested.
-
coverableLines: number
Lines the source map attributes to executable positions in the bundle.
-
coveredLines: number
Lines executed at least once.
-
path: string
Path relative to the project root, with forward slashes.
-
percent: number
coveredLines / coverableLines, as a percentage rounded to two decimals.
One test found by the static scan, named exactly as QUnit would name it.
-
file: string
Absolute path of the file it was declared in — used to apply that file's line targets.
-
fullName: string
"Module > Sub: test name"— the string a filter matches against. -
line: number
1-based line of the declaration.
-
modules: string[]
The QUnit module path it is declared under; empty for a top-level test.
-
name: string
The test's own name.
Where to scaffold a test file. target is a project-relative path; a missing .js/.ts
extension becomes .js, and missing directories are created.
-
cwd: string
Directory to find the project root from. Defaults to
process.cwd(). -
target: string
Project-relative path of the test file to write.
What generate did: the file it wrote, or the one it refused to overwrite.
-
created: boolean
falsewhen the file already existed and nothing was written. -
path: string
Absolute path of the target file.
Where to bootstrap, and which HTML fixtures to write. Both default the way the CLI does:
the working directory, and whatever .html arguments were passed.
-
cwd: string
Directory to find the project root from. Defaults to
process.cwd(). -
htmlPaths: string[]
HTML fixtures to create, relative to the project root. Defaults to
['test/tests.html'].
What init did, so the caller can report it. Returned rather than printed: the CLI turns
these into its messages, and a programmatic caller gets the same facts as data.
-
skipped: string[]
Paths that already existed and were left alone.
-
written: string[]
Absolute paths of the files this call created.
One diagnostic from qunitx itself: which files a narrowing flag scoped the run to, a filter that matched nothing, a build error, a timeout.
-
level: "info" | "warning" | "error"
infois a decision,warninga surprise,errora diagnostic that also hits stderr. -
message: string
The text, already colored where the CLI colors it, with no
#prefix and no newline. -
raw: boolean
Write
messageverbatim rather than as a#-prefixed comment. For pre-formatted blocks — the coverage table, a stack trace — whose own layout is the point. -
stream: "output" | "error" | "both"
Which of the run's two streams the default rendering goes to;
outputby default.
The reporter contract — the public extension point for observing a run. Reporters render it
to text (the built-in tap/spec/dot/github), write an artifact (junit), or simply
collect, which is how the JS API turns a run into a value.
-
onBrowserLog(): voidcontext: ReporterContext,log: BrowserLog
Called for each
console.*call and uncaught error from the page under test. Only warnings and errors arrive unlessdebugis on — the same selection the CLI prints. -
onNotice(): voidcontext: ReporterContext,notice: Notice
Called for each of qunitx's own diagnostics — the
# …lines about what it decided to run, what it could not find, what timed out. The default rendering has already gone toconfig.state.console; implement this only to capture them as data. -
onRunEnd(): void | Promise<void>context: ReporterContext,info: RunEndInfo
Called once when the run finishes, with the final counts on
config.state.results.counter. -
onRunStart(): voidcontext: ReporterContext,info: RunStartInfo
Called once before any test output. In watch mode, once per rerun.
-
onTestEnd(): voidcontext: ReporterContext,details: TestDetails
Called once per test, after
counterhas already been updated for this test.
What a reporter is given on every hook: where to write, what the run has counted so far, and the few resolved paths a message needs.
-
console: Console
Where this reporter's text goes.
silentConsolewhen the run was asked to print nothing. -
counts: Counter
The run's live outcome totals — the same object the runner updates, not a copy.
-
daemon: boolean
Whether this run is executing inside the persistent daemon.
-
junit: boolean | string
--junit's value:truefor the default path, a string for an explicit one. -
output: string
Absolute path of the build output directory.
-
projectRoot: string
Absolute path of the directory holding
package.json, for rendering paths relative to it. -
sourceMapDecoder: SourceMapDecoder | null
Maps a bundle stack frame back to source, once the run has built one.
What the run actually resolved to, after package.json, the defaults and the options were
merged — the answers a caller cannot otherwise recover from what it passed in.
-
browser: "chromium" | "firefox" | "webkit"
The engine the tests ran in.
-
coverageFormats: string[]
Coverage artifact formats beyond the terminal summary.
-
extensions: string[]
File extensions treated as test files.
-
filter: string
The active test-name filter, when one was set.
-
output: string
Absolute path of the build output directory — where the bundle and artifacts landed.
-
port: number
The port actually bound, which may differ from the one requested.
-
projectRoot: string
Absolute path of the directory holding
package.json.
Final run info; the counts themselves live on config.state.results.counter.
-
durationMs: number
Wall-clock duration of the run in milliseconds.
One concurrent group of a run: the files bundled into a single page, and where that page's artifacts were written.
-
files: string[]
Absolute paths of the test files this group bundled and ran together.
-
index: number
Position in the run's group list, and the
group-<index>suffix onoutput. -
output: string
Absolute path of this group's build output directory.
Everything a finished run produced.
-
browserLogs: BrowserLog[]
console.*calls and uncaught errors from the page — warnings and errors unlessdebug. -
browserLogsDropped: number
How many page-log entries were dropped to stay under the cap.
0in every ordinary run. -
counts: RunCounts
Outcome totals.
-
coverage: CoverageSummary | null
Line coverage, or
nullwhencoveragewas not requested. -
durationMs: number
Wall-clock duration of the test phase, in milliseconds.
-
exitCode: number
What the CLI would have exited with:
0whenok,1otherwise. -
failedFiles: string[]
Absolute paths of the test files with at least one failure, attributed via source maps.
-
failures: TestResult[]
The subset of
teststhat failed — the list you almost always want first. -
files: string[]
Absolute paths of the test files this run executed — the ones scoped to, in a filtered watch rerun, rather than everything being watched.
-
finishedAt: number
Epoch ms when it ended.
-
groups: RunGroup[]
How the files were split across concurrent groups — one entry per group, never empty.
groups.lengthis the concurrency the run actually used;1for watch and single-file runs. -
junitXml: string | null
The JUnit XML document, when
junitwas requested. Written to disk as well. -
notices: Notice[]
qunitx's own diagnostics for this run, in emission order.
-
ok: boolean
truewhen every test passed and nothing else went wrong. -
resolved: ResolvedRun
What the run resolved to — see ResolvedRun.
-
startedAt: number
Epoch ms when the test phase began.
-
status: "completed" | "aborted" | "failFast"
How the run finished: whether it got through everything it selected, and if not, what stopped it. Distinct from RunResult.ok, which is the verdict — a
completedrun can be entirely red, and anabortedone can have no failures at all. -
tests: TestResult[]
Every finished test, in the order the browser reported them.
Run-scope counts. fileCount === null means "counts unknown at this point" (watch mode,
where the header is emitted per browser connection rather than per file batch).
-
fileCount: number | null
Test files in this run, or
nullwhen not known at announce time. -
groupCount: number | null
Concurrent groups the files were split across, or
nullalongside a nullfileCount.
Everything run accepts beyond the file itself — the subset of a script run a caller can set.
-
browser: "chromium" | "firefox" | "webkit"
Browser engine. Defaults to
chromium. -
console: Console
Where the script's own output goes, exactly as test and watch take one. Defaults to this process's stdout and stderr.
-
cwd: string
Directory the file, its relative imports and
node_moduleslookups resolve against. -
open: boolean
Run in a visible browser window instead of headless.
-
port: number
Port the local server binds. Defaults to 1234, stepping over a taken one.
-
timeout: number
Ms the script may run before it is declared hung. Unbounded by default, like
deno run.
What one script run produced.
-
browserLogs: BrowserLog[]
Everything the script printed — its
consolecalls and any uncaught error — in emit order, whateverconsoleoption was passed. The same shape a test run reports, capped the same way. -
browserLogsDropped: number
How many lines were dropped to stay under the cap.
0when nothing was. -
durationMs: number
Wall-clock ms from the first bundle to the script's top level settling.
-
exitCode: number
globalThis.exitCodeif the script set one, 1 if it threw, else 0. -
file: string
Absolute path of the file that ran.
-
ok: boolean
True when the script finished with exit code 0.
-
tests: RunResult | null
The suite the file declared, or
nullwhen it was a plain script. -
value: unknown
The script's
export default, orundefinedwhen it has none. -
valueProblem: string | null
Why ScriptResult.value is
undefinedeven though the script exported something, ornullwhen there is nothing to explain — including when it exported nothing at all.
What the static scan found, before anything is printed.
-
files: number
How many files were scanned.
-
filter: string
The expression matched against, or
undefinedwhen everything was listed. -
matches: FoundTest[]
The tests the current selection matches, in declaration order.
-
total: number
Every listable test found, matched or not.
-
unlistable: UnlistableCounts
What the scan could not name, split by cause.
-
warnings: string[]
Line-target resolution warnings, in input order.
One QUnit assertion inside a testEnd payload.
-
actual: unknown
The value the assertion actually saw.
-
expected: unknown
The value the assertion required.
-
message: string
The assertion's message, when one was given.
-
passed: boolean
truewhen the assertion held. -
stack: string
Raw stack captured at the assertion, with frames pointing at the bundle.
-
todo: boolean
truefor assertions inside atodotest, which are expected to fail.
The QUnit testEnd payload as it arrives over the WebSocket. Passing tests carry the
trimmed { status, fullName, runtime }; failing tests additionally carry assertions.
-
assertions: TestAssertion[]
Present on failing tests only (QUnit trims the payload otherwise).
-
fullName: string[]
Module path followed by the test name, e.g.
['Math', 'adds']. -
runtime: number
Test duration in milliseconds.
-
status: string
QUnit's outcome:
passed|failed|skipped|todo.
One finished test.
-
assertions: TestAssertion[]
The test's assertions. QUnit trims these for passing tests, so this is populated for failures and empty otherwise — a passing test's assertion count is not reported.
-
durationMs: number
How long the test took, in milliseconds.
-
file: string | null
Source file this test was declared in, relative to the project root, or
null. -
fullName: string
"Module > Sub: test name"— the stringfiltermatches against. -
modules: string[]
The QUnit module path it was declared under; empty for a top-level test.
-
name: string
The test's own name, without its modules.
-
status: "passed" | "failed" | "skipped" | "todo"
QUnit's outcome for this test.
One run, watched as it happens.
-
abort(): Promise<void>
Cuts the run short. The browser drops the rest of its queue and the run ends where it is, with
aborted: trueon the result — which TestSession.result still resolves with, so an aborted run is answered rather than left hanging. -
close(): Promise<void>
Closes the session, ending iteration. Idempotent; implied by
await using. -
droppedEvents: number
How many events the feed dropped because a consumer fell behind.
0in every ordinary run. -
events(): Stream<RunEvent>
The same events as iterating the session, as a Stream — so the combinators are there without a
Stream.fromwrapper. -
result(): Promise<RunResult>
The finished run. Starts it if nothing has yet, and resolves with the same RunResult the final
runEndevent carries — neverundefined, which is the whole reason this is a session rather than a bare event stream.
Why some declarations could not be listed, split by cause.
-
computedNames: number
Declarations whose name is computed at run time —
test(`case ${index}`). -
silent: number
Files that parsed but declared no test the scan could see, e.g. via a local alias.
-
total: number
The three below, added up.
-
unparseable: number
Files that could not be read or parsed at all.
Everything a run can be told to do. Every field is optional: run() with no arguments runs
the project exactly as a bare qunitx would, minus the printing.
-
after: string | false
Path to a module run after the tests; it receives the run's counters.
-
before: string | false
Path to a module run before the tests; it receives the resolved config.
-
browser: "chromium" | "firefox" | "webkit"
Browser engine. Defaults to
chromium, the only one that can collect coverage. -
changedSince: string
Run only files whose transitive imports changed since this git ref (
'HEAD'for uncommitted). -
console: Console
Where the run's text goes. Defaults to the process streams when a reporter is NAMED, and to silentConsole otherwise — so a programmatic run prints nothing unless it was asked to.
-
coverage: boolean | { formats?: Array<"lcov" | "html">; }
Collect V8 line coverage (chromium only).
formatsadditionally writes lcov/html artifacts. -
cwd: string
Directory the project root and relative inputs resolve against. Defaults to
process.cwd(). -
debug: boolean
Forward every page console call and print the server URL.
-
extensions: string[]
File extensions treated as test files. Defaults to
['js', 'ts', 'jsx', 'tsx']. -
failFast: boolean
Stop the run at the first failing test.
-
filter: string
Run only tests whose
"Module: test name"matches. QUnit's own semantics: case-insensitive substring,/regex/,/regex/i, or a leading!to invert. -
html: string[]
HTML fixture files to wrap the bundle in, relative to the project root.
-
inputs: string[]
Files, directories, globs, or
file.ts#34line targets — the same grammar as the command line's positional arguments. Defaults topackage.json#qunitx.inputs. -
junit: boolean | string
Write a JUnit XML report.
truewrites<output>/junit.xml; a string is a path. -
onlyFailed: boolean
Run only the files that failed last time, from the persistent failure cache.
-
open: boolean | string
Open the output in a browser:
truefor the default, a string to name a binary. -
output: string
Directory for the compiled bundle and HTML output. Defaults to
'tmp'. -
plugins: EsbuildPlugin[]
esbuild plugins for the test bundle — live objects, not specifiers.
-
port: number
Port for the local test server. Defaults to 1234, incrementing on conflict.
-
reporter: ReporterOption
Print the run with ONE reporter: a built-in name (
'tap','spec','dot','github'), your own Reporter, orfalse. The same spelling as the CLI's--reporter. -
reporters: ReadonlyArray<ReporterOption>
Print the run with SEVERAL. Mutually exclusive with UserRunOptions.reporter: pass
reporterfor one,reportersfor many, and validate rejects both at once. -
signal: AbortSignal
Cancels the run when it fires.
-
timeout: number
Milliseconds a single test may take before the run is declared stalled. Defaults to 20000.
A running watch session.
-
abort(): Promise<void>
Cuts the current run short: the browser drops the rest of its queue and the run ends where it is, with
aborted: trueon its result. -
browser: Browser
Playwright's
Browserfor this session — unstable, playwright-core's type. -
close(): Promise<void>
Stops watching, closes the browser and server, and ends the iteration. Idempotent.
-
droppedEvents: number
How many events the feed dropped because a consumer fell behind.
0unless something stalls. -
esbuild: BuildContext | null
esbuild's incremental
BuildContext— unstable, esbuild's type. -
events(): Stream<RunEvent>
The fine-grained feed: every event of every run, flat and in order, until the session closes.
-
fileWatchers: Record<string, FSWatcher>
The live
fs.watchhandles keyed by watched path — unstable, and a PARTIAL view: the parent-directory watchers, rescan intervals and symlink pollers the session also owns are not in here. It answers "what is being watched", not "every handle the watcher holds". -
initial: RunResult
The initial run's result, available before anything has changed on disk.
-
latest: RunResult
The most recent run's result —
initialuntil something re-runs. -
page: Page
The page the suite runs in — unstable, playwright-core's type.
-
restart(patch?: SessionPatch): Promise<RunResult>
Tears the session's machinery down and boots it again — browser, page, server, esbuild context and watchers — then runs the suite once, resolving with that run's result.
-
results(): Stream<RunResult>
The coarse feed as a Stream: one complete RunResult per rerun, with the combinators attached.
for await (const r of session)is the same sequence. -
run(files?: string[]): Promise<RunResult>
Re-runs now, optionally scoped to
files, and resolves with that run's result. -
runAll(): Promise<RunResult>
Runs the whole suite, dropping any line-target selectors this session was scoped to.
-
runFailed(): Promise<RunResult>
Re-runs the files that last failed, or repeats the last run when nothing has failed yet — saying so as an
infonotice on the result rather than silently doing something else. -
running: boolean
Whether a run is in flight right now.
-
url: string
Where the QUnit view is being served, e.g.
http://localhost:1234. -
webServer: HTTPServer
The HTTP + WebSocket server serving the bundle — unstable, this project's own
HTTPServerrather than a documented interface.
Daemon control: start, stop, status, and a test that reuses the daemon's warm browser
and returns the same RunResult a local run does.
A declared failure: something the runner decided it could not do, carrying a code to branch
on and a message to show.
Every way a daemon-routed run can fail to produce an exit code.
| { running: true; pid: number; cwd: string; nodeVersion: string; startedAt: number; socketPath: string; }
A live daemon, as reported by status.
Every way a daemon-routed run can fail to produce an exit code.
| { running: true; pid: number; cwd: string; nodeVersion: string; startedAt: number; socketPath: string; }
A live daemon, as reported by status.
The one failure validate raises.
A valid --reporter value.
--reporter by name, a reporter of your own, or false for none.
The success value or a declared failure — a bare union, discriminated by the Failure
brand.
Outcome totals for a run. total is the sum of the four buckets; assertionsFailed counts
individual assertions rather than tests, so one test can contribute several.
| { kind: "test"; test: TestResult; }
| { kind: "notice"; notice: Notice; }
| { kind: "browserLog"; log: BrowserLog; }
| { kind: "runEnd"; result: RunResult; }
One thing that happened during a run, as it happened.
Every way a run can fail to happen: an option the runner will not accept, an unreadable input,
a directory with no package.json above it, an esbuild plugin that will not load.
| ScriptEntryFailure
Every way run can reject. A script that merely exits non-zero is NOT one of them.
What openSession accepts: every run option, plus the one that chooses the shape.
The options a WatchSession.restart may change.
The failure taxonomy, as this API's public surface.
-
format: () => stringerror: unknown,options?: { stacks?: boolean; }
Renders a failure as the one-line message the CLI would print.
-
hasCode: <Codes extends readonly string[]>() => value is AnyFailure & { code: Codes[number]; }value: unknown,...codes: Codes
Narrows to a specific set of codes, for handling some failures and rethrowing the rest.
-
is: (value: unknown) => value is AnyFailure
Narrows an unknown value to a declared failure. The guard to reach for after
.result().
An option was given a value the runner will not accept.
run was handed something that is not one script file.
The CLI's: the real process streams. .write is looked up per call, so the daemon's stdout
interception still reaches it.
Every stdout reporter --reporter accepts, in help/error-message order. Exactly one is
active per run — artifact outputs (--junit, --coverage) are separate additive flags.
This module is a leaf (type-only imports), so Args.parse can validate against it
without pulling the reporter implementations into the CLI's startup path.
Discards everything. The JS API's default, so a programmatic run prints nothing unless it was asked to.
The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only
entry points — there is no public constructor and no call form.
The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only
entry points — there is no public constructor and no call form.
Call-or-construct, like Boolean/Date: Task(recipe) and new Task(recipe) build the
same lazy Task. ES classes reject the call form, so the export is a Proxy whose apply
forwards to construction — statics, instanceof, and the prototype all pass through.
Call-or-construct, like Boolean/Date: Task(recipe) and new Task(recipe) build the
same lazy Task. ES classes reject the call form, so the export is a Proxy whose apply
forwards to construction — statics, instanceof, and the prototype all pass through.
Public options in, runner input out — this is the API's Args.parse, and the only reason
UserRunOptions and ConfigOptions are separate types.
Rejects options the run cannot honour, before anything is launched.
Everything a run can be told to do. Every field is optional: run() with no arguments runs
the project exactly as a bare qunitx would, minus the printing.
-
after: string | false
Path to a module run after the tests; it receives the run's counters.
-
before: string | false
Path to a module run before the tests; it receives the resolved config.
-
browser: "chromium" | "firefox" | "webkit"
Browser engine. Defaults to
chromium, the only one that can collect coverage. -
changedSince: string
Run only files whose transitive imports changed since this git ref (
'HEAD'for uncommitted). -
console: Console
Where the run's text goes. Defaults to the process streams when a reporter is NAMED, and to silentConsole otherwise — so a programmatic run prints nothing unless it was asked to.
-
coverage: boolean | { formats?: Array<"lcov" | "html">; }
Collect V8 line coverage (chromium only).
formatsadditionally writes lcov/html artifacts. -
cwd: string
Directory the project root and relative inputs resolve against. Defaults to
process.cwd(). -
debug: boolean
Forward every page console call and print the server URL.
-
extensions: string[]
File extensions treated as test files. Defaults to
['js', 'ts', 'jsx', 'tsx']. -
failFast: boolean
Stop the run at the first failing test.
-
filter: string
Run only tests whose
"Module: test name"matches. QUnit's own semantics: case-insensitive substring,/regex/,/regex/i, or a leading!to invert. -
html: string[]
HTML fixture files to wrap the bundle in, relative to the project root.
-
inputs: string[]
Files, directories, globs, or
file.ts#34line targets — the same grammar as the command line's positional arguments. Defaults topackage.json#qunitx.inputs. -
junit: boolean | string
Write a JUnit XML report.
truewrites<output>/junit.xml; a string is a path. -
onlyFailed: boolean
Run only the files that failed last time, from the persistent failure cache.
-
open: boolean | string
Open the output in a browser:
truefor the default, a string to name a binary. -
output: string
Directory for the compiled bundle and HTML output. Defaults to
'tmp'. -
plugins: EsbuildPlugin[]
esbuild plugins for the test bundle — live objects, not specifiers.
-
port: number
Port for the local test server. Defaults to 1234, incrementing on conflict.
-
reporter: ReporterOption
Print the run with ONE reporter: a built-in name (
'tap','spec','dot','github'), your own Reporter, orfalse. The same spelling as the CLI's--reporter. -
reporters: ReadonlyArray<ReporterOption>
Print the run with SEVERAL. Mutually exclusive with UserRunOptions.reporter: pass
reporterfor one,reportersfor many, and validate rejects both at once. -
signal: AbortSignal
Cancels the run when it fires.
-
timeout: number
Milliseconds a single test may take before the run is declared stalled. Defaults to 20000.
The one failure validate raises.
--reporter by name, a reporter of your own, or false for none.
An option was given a value the runner will not accept.
The reporter that turns a run into a value: it records what happened instead of printing it.
-
browserLogs: BrowserLog[]
The most recent page console calls and uncaught errors, capped at MAX_BROWSER_LOGS.
-
browserLogsDropped: number
How many page-log entries the cap dropped.
-
notices: Notice[]
Every diagnostic, in emission order.
-
onBrowserLog(): void_context: ReporterContext,log: BrowserLog
Records one page console call or uncaught error.
-
onNotice(): void_context: ReporterContext,notice: Notice
Records one diagnostic.
-
onTestEnd(): void_context: ReporterContext,details: TestDetails
Records one finished test.
-
reset(): void
Drops everything from a previous run. Watch sessions reuse one collector across reruns, so this is what keeps rerun N's result from containing rerun N-1's tests.
-
tests: TestResult[]
Every finished test, in arrival order.
The APIReporter watching this run — the reporter every result is built from.
Projects one QUnit testEnd payload into a TestResult. QUnit's fullName is
[...modules, testName]; the joined display form matches what filter matches against —
modules separated by >, the test name after a : .
A channel carrying one run's events, together with the Reporter that fills it.
| { kind: "test"; test: TestResult; }
| { kind: "notice"; notice: Notice; }
| { kind: "browserLog"; log: BrowserLog; }
| { kind: "runEnd"; result: RunResult; }
One thing that happened during a run, as it happened.
The buffer a feed keeps for a consumer that has stopped reading.
How many page-log entries a result retains. Tests and notices are bounded by the suite; page output is bounded by nothing a test runner controls, so this is the one channel that needs a ceiling. Generous enough that a real run never reaches it.
Runs ONE file as a plain script in a real browser — the API twin of qunitx run <file>, and the
sibling of test, which runs a suite.
Everything run accepts beyond the file itself — the subset of a script run a caller can set.
-
browser: "chromium" | "firefox" | "webkit"
Browser engine. Defaults to
chromium. -
console: Console
Where the script's own output goes, exactly as test and watch take one. Defaults to this process's stdout and stderr.
-
cwd: string
Directory the file, its relative imports and
node_moduleslookups resolve against. -
open: boolean
Run in a visible browser window instead of headless.
-
port: number
Port the local server binds. Defaults to 1234, stepping over a taken one.
-
timeout: number
Ms the script may run before it is declared hung. Unbounded by default, like
deno run.
What one script run produced.
-
browserLogs: BrowserLog[]
Everything the script printed — its
consolecalls and any uncaught error — in emit order, whateverconsoleoption was passed. The same shape a test run reports, capped the same way. -
browserLogsDropped: number
How many lines were dropped to stay under the cap.
0when nothing was. -
durationMs: number
Wall-clock ms from the first bundle to the script's top level settling.
-
exitCode: number
globalThis.exitCodeif the script set one, 1 if it threw, else 0. -
file: string
Absolute path of the file that ran.
-
ok: boolean
True when the script finished with exit code 0.
-
tests: RunResult | null
The suite the file declared, or
nullwhen it was a plain script. -
value: unknown
The script's
export default, orundefinedwhen it has none. -
valueProblem: string | null
Why ScriptResult.value is
undefinedeven though the script exported something, ornullwhen there is nothing to explain — including when it exported nothing at all.
| ScriptEntryFailure
Every way run can reject. A script that merely exits non-zero is NOT one of them.
run was handed something that is not one script file.
Lists the tests a selection would run, without running them.
One test found by the static scan, named exactly as QUnit would name it.
-
file: string
Absolute path of the file it was declared in — used to apply that file's line targets.
-
fullName: string
"Module > Sub: test name"— the string a filter matches against. -
line: number
1-based line of the declaration.
-
modules: string[]
The QUnit module path it is declared under; empty for a top-level test.
-
name: string
The test's own name.
What the static scan found, before anything is printed.
-
files: number
How many files were scanned.
-
filter: string
The expression matched against, or
undefinedwhen everything was listed. -
matches: FoundTest[]
The tests the current selection matches, in declaration order.
-
total: number
Every listable test found, matched or not.
-
unlistable: UnlistableCounts
What the scan could not name, split by cause.
-
warnings: string[]
Line-target resolution warnings, in input order.
Why some declarations could not be listed, split by cause.
-
computedNames: number
Declarations whose name is computed at run time —
test(`case ${index}`). -
silent: number
Files that parsed but declared no test the scan could see, e.g. via a local alias.
-
total: number
The three below, added up.
-
unparseable: number
Files that could not be read or parsed at all.
With watch: true, the DURABLE shape: one page behind a stable WatchSession.url, kept
open with the rerun verbs and file watching, exactly as watch gives you.
One run, watched as it happens.
-
abort(): Promise<void>
Cuts the run short. The browser drops the rest of its queue and the run ends where it is, with
aborted: trueon the result — which TestSession.result still resolves with, so an aborted run is answered rather than left hanging. -
close(): Promise<void>
Closes the session, ending iteration. Idempotent; implied by
await using. -
droppedEvents: number
How many events the feed dropped because a consumer fell behind.
0in every ordinary run. -
events(): Stream<RunEvent>
The same events as iterating the session, as a Stream — so the combinators are there without a
Stream.fromwrapper. -
result(): Promise<RunResult>
The finished run. Starts it if nothing has yet, and resolves with the same RunResult the final
runEndevent carries — neverundefined, which is the whole reason this is a session rather than a bare event stream.
What openSession accepts: every run option, plus the one that chooses the shape.
The result of a run that was cancelled before it began: no browser, no tests, aborted: true.
Assembles the run's result from the config's accumulated state, the run's outcome, and the APIReporter that watched it.
Runs the suite once in a real browser and resolves with everything it produced.
The run's line coverage: one entry per source file, plus the totals across all of them.
-
coverableLines: number
Coverable lines across every file.
-
coveredLines: number
Covered lines across every file.
-
files: FileCoverageSummary[]
One entry per non-test source file the bundle mapped back to.
-
percent: number
Overall percentage covered.
Per-file line coverage, when coverage was requested.
-
coverableLines: number
Lines the source map attributes to executable positions in the bundle.
-
coveredLines: number
Lines executed at least once.
-
path: string
Path relative to the project root, with forward slashes.
-
percent: number
coveredLines / coverableLines, as a percentage rounded to two decimals.
What the run actually resolved to, after package.json, the defaults and the options were
merged — the answers a caller cannot otherwise recover from what it passed in.
-
browser: "chromium" | "firefox" | "webkit"
The engine the tests ran in.
-
coverageFormats: string[]
Coverage artifact formats beyond the terminal summary.
-
extensions: string[]
File extensions treated as test files.
-
filter: string
The active test-name filter, when one was set.
-
output: string
Absolute path of the build output directory — where the bundle and artifacts landed.
-
port: number
The port actually bound, which may differ from the one requested.
-
projectRoot: string
Absolute path of the directory holding
package.json.
One concurrent group of a run: the files bundled into a single page, and where that page's artifacts were written.
-
files: string[]
Absolute paths of the test files this group bundled and ran together.
-
index: number
Position in the run's group list, and the
group-<index>suffix onoutput. -
output: string
Absolute path of this group's build output directory.
Everything a finished run produced.
-
browserLogs: BrowserLog[]
console.*calls and uncaught errors from the page — warnings and errors unlessdebug. -
browserLogsDropped: number
How many page-log entries were dropped to stay under the cap.
0in every ordinary run. -
counts: RunCounts
Outcome totals.
-
coverage: CoverageSummary | null
Line coverage, or
nullwhencoveragewas not requested. -
durationMs: number
Wall-clock duration of the test phase, in milliseconds.
-
exitCode: number
What the CLI would have exited with:
0whenok,1otherwise. -
failedFiles: string[]
Absolute paths of the test files with at least one failure, attributed via source maps.
-
failures: TestResult[]
The subset of
teststhat failed — the list you almost always want first. -
files: string[]
Absolute paths of the test files this run executed — the ones scoped to, in a filtered watch rerun, rather than everything being watched.
-
finishedAt: number
Epoch ms when it ended.
-
groups: RunGroup[]
How the files were split across concurrent groups — one entry per group, never empty.
groups.lengthis the concurrency the run actually used;1for watch and single-file runs. -
junitXml: string | null
The JUnit XML document, when
junitwas requested. Written to disk as well. -
notices: Notice[]
qunitx's own diagnostics for this run, in emission order.
-
ok: boolean
truewhen every test passed and nothing else went wrong. -
resolved: ResolvedRun
What the run resolved to — see ResolvedRun.
-
startedAt: number
Epoch ms when the test phase began.
-
status: "completed" | "aborted" | "failFast"
How the run finished: whether it got through everything it selected, and if not, what stopped it. Distinct from RunResult.ok, which is the verdict — a
completedrun can be entirely red, and anabortedone can have no failures at all. -
tests: TestResult[]
Every finished test, in the order the browser reported them.
One finished test.
-
assertions: TestAssertion[]
The test's assertions. QUnit trims these for passing tests, so this is populated for failures and empty otherwise — a passing test's assertion count is not reported.
-
durationMs: number
How long the test took, in milliseconds.
-
file: string | null
Source file this test was declared in, relative to the project root, or
null. -
fullName: string
"Module > Sub: test name"— the stringfiltermatches against. -
modules: string[]
The QUnit module path it was declared under; empty for a top-level test.
-
name: string
The test's own name, without its modules.
-
status: "passed" | "failed" | "skipped" | "todo"
QUnit's outcome for this test.
Outcome totals for a run. total is the sum of the four buckets; assertionsFailed counts
individual assertions rather than tests, so one test can contribute several.
Every way a run can fail to happen: an option the runner will not accept, an unreadable input,
a directory with no package.json above it, an esbuild plugin that will not load.
Starts a watch session: builds once, runs once, then re-runs on every save until closed.
A running watch session.
-
abort(): Promise<void>
Cuts the current run short: the browser drops the rest of its queue and the run ends where it is, with
aborted: trueon its result. -
browser: Browser
Playwright's
Browserfor this session — unstable, playwright-core's type. -
close(): Promise<void>
Stops watching, closes the browser and server, and ends the iteration. Idempotent.
-
droppedEvents: number
How many events the feed dropped because a consumer fell behind.
0unless something stalls. -
esbuild: BuildContext | null
esbuild's incremental
BuildContext— unstable, esbuild's type. -
events(): Stream<RunEvent>
The fine-grained feed: every event of every run, flat and in order, until the session closes.
-
fileWatchers: Record<string, FSWatcher>
The live
fs.watchhandles keyed by watched path — unstable, and a PARTIAL view: the parent-directory watchers, rescan intervals and symlink pollers the session also owns are not in here. It answers "what is being watched", not "every handle the watcher holds". -
initial: RunResult
The initial run's result, available before anything has changed on disk.
-
latest: RunResult
The most recent run's result —
initialuntil something re-runs. -
page: Page
The page the suite runs in — unstable, playwright-core's type.
-
restart(patch?: SessionPatch): Promise<RunResult>
Tears the session's machinery down and boots it again — browser, page, server, esbuild context and watchers — then runs the suite once, resolving with that run's result.
-
results(): Stream<RunResult>
The coarse feed as a Stream: one complete RunResult per rerun, with the combinators attached.
for await (const r of session)is the same sequence. -
run(files?: string[]): Promise<RunResult>
Re-runs now, optionally scoped to
files, and resolves with that run's result. -
runAll(): Promise<RunResult>
Runs the whole suite, dropping any line-target selectors this session was scoped to.
-
runFailed(): Promise<RunResult>
Re-runs the files that last failed, or repeats the last run when nothing has failed yet — saying so as an
infonotice on the result rather than silently doing something else. -
running: boolean
Whether a run is in flight right now.
-
url: string
Where the QUnit view is being served, e.g.
http://localhost:1234. -
webServer: HTTPServer
The HTTP + WebSocket server serving the bundle — unstable, this project's own
HTTPServerrather than a documented interface.
The options a WatchSession.restart may change.
Classifies raw positional targets into flags, exactly as the CLI does with argv positionals:
.html fixtures become htmlPaths, a trailing #34/:34 becomes a lineTargets entry, and
everything else is an absolute path in inputs (deduplicated) plus a wholeInputPaths mention.
Parses an argv into a qunitx flag object (inputs, debug, watch, failFast, timeout, output, port, before, after).
Classifies argv into query / flag / input tokens.
Any other flag (--watch, --timeout=5000, -o, …), passed through verbatim.
-
kind: "flag"
Discriminant.
-
raw: string
The exact argv entry, including leading dashes and any
=value.
A positional target: a file, folder, or glob (possibly with a #34 line suffix).
-
kind: "input"
Discriminant.
-
raw: string
The exact argv entry.
The flag object a successful parse() carries — CLI flags only, before package.json merge.
-
after: string | false
--after: module run after the tests, orfalseto disable a configured one. -
before: string | false
--before: module run before the tests, orfalseto disable a configured one. -
browser: "chromium" | "firefox" | "webkit"
--browser: the engine to run in. -
changedSince: string
--since/--changed: run only files whose transitive imports changed since this git ref. -
coverage: boolean
--coverage: collect V8 line coverage. -
coverageFormats: string[]
Artifact formats beyond the terminal summary (
lcov,html). -
debug: boolean
--debug/--console: print the server URL and forward the page's console. -
extensions: string[]
--extensions: file extensions treated as test files. -
failFast: boolean
--failFast: stop at the first failing test. -
filter: string
-t/--filter/-m/--module/-n: the one test-name matcher, in QUnit's own semantics. -
htmlPaths: string[]
Positional
.htmlfixtures the test bundle is injected into. -
inputs: string[]
Absolute paths of the test targets, deduplicated.
.htmlfixtures and#linesuffixes are split out intohtmlPathsandlineTargetsrather than kept here. -
junit: boolean | string
--junit: write a JUnit report.trueuses the default path; a string overrides it. -
lineTargets: Record<string, number[]>
Absolute path → the
#34line targets given for it. -
onlyFailed: boolean
--only-failed/-f: run only the files that failed on the previous run. -
open: boolean | string
--open/-o: open the output in a browser; a string names a specific binary. -
output: string
--output: directory for the compiled bundle and HTML. -
port: number
--port/-p: the port the local test server listens on. -
portExplicit: boolean
truewhen--portwas given explicitly, so a busy port fails instead of incrementing. -
reporter: ReporterName
--reporter/-r: the single stdout format. -
search: string | true
--search/--printmode: the expression to preview, ortrueto list everything. -
timeout: number
--timeout: milliseconds a single test may take before the run is declared stalled. -
watch: boolean
--watch/-w: re-run on every save instead of exiting after one run. -
wholeInputPaths: string[]
Absolute paths mentioned WITHOUT a line target — whole-file requests that supersede a line target.
A query flag (-t/-m/-s/-p) with its resolved value.
-
action: "run" | "list"
What to do with the matches:
runnarrows which tests execute;listpreviews them instead. -
greedy: boolean
True when the value was consumed from following argv entries (
-t a b) rather than=glued. -
kind: "query"
Discriminant.
-
value: string | null
The value, or null when the flag was given with nothing after it.
One classified argv entry: a query flag, any other flag, or a positional input.
Every way parse() can reject its input.
A flag was given a value this parser will not accept.
Classifies raw positional targets into flags, exactly as the CLI does with argv positionals:
.html fixtures become htmlPaths, a trailing #34/:34 becomes a lineTargets entry, and
everything else is an absolute path in inputs (deduplicated) plus a wholeInputPaths mention.
Parses an argv into a qunitx flag object (inputs, debug, watch, failFast, timeout, output, port, before, after).
The flag object a successful parse() carries — CLI flags only, before package.json merge.
-
after: string | false
--after: module run after the tests, orfalseto disable a configured one. -
before: string | false
--before: module run before the tests, orfalseto disable a configured one. -
browser: "chromium" | "firefox" | "webkit"
--browser: the engine to run in. -
changedSince: string
--since/--changed: run only files whose transitive imports changed since this git ref. -
coverage: boolean
--coverage: collect V8 line coverage. -
coverageFormats: string[]
Artifact formats beyond the terminal summary (
lcov,html). -
debug: boolean
--debug/--console: print the server URL and forward the page's console. -
extensions: string[]
--extensions: file extensions treated as test files. -
failFast: boolean
--failFast: stop at the first failing test. -
filter: string
-t/--filter/-m/--module/-n: the one test-name matcher, in QUnit's own semantics. -
htmlPaths: string[]
Positional
.htmlfixtures the test bundle is injected into. -
inputs: string[]
Absolute paths of the test targets, deduplicated.
.htmlfixtures and#linesuffixes are split out intohtmlPathsandlineTargetsrather than kept here. -
junit: boolean | string
--junit: write a JUnit report.trueuses the default path; a string overrides it. -
lineTargets: Record<string, number[]>
Absolute path → the
#34line targets given for it. -
onlyFailed: boolean
--only-failed/-f: run only the files that failed on the previous run. -
open: boolean | string
--open/-o: open the output in a browser; a string names a specific binary. -
output: string
--output: directory for the compiled bundle and HTML. -
port: number
--port/-p: the port the local test server listens on. -
portExplicit: boolean
truewhen--portwas given explicitly, so a busy port fails instead of incrementing. -
reporter: ReporterName
--reporter/-r: the single stdout format. -
search: string | true
--search/--printmode: the expression to preview, ortrueto list everything. -
timeout: number
--timeout: milliseconds a single test may take before the run is declared stalled. -
watch: boolean
--watch/-w: re-run on every save instead of exiting after one run. -
wholeInputPaths: string[]
Absolute paths mentioned WITHOUT a line target — whole-file requests that supersede a line target.
Every way parse() can reject its input.
A flag was given a value this parser will not accept.
Classifies argv into query / flag / input tokens.
Any other flag (--watch, --timeout=5000, -o, …), passed through verbatim.
-
kind: "flag"
Discriminant.
-
raw: string
The exact argv entry, including leading dashes and any
=value.
A positional target: a file, folder, or glob (possibly with a #34 line suffix).
-
kind: "input"
Discriminant.
-
raw: string
The exact argv entry.
A query flag (-t/-m/-s/-p) with its resolved value.
-
action: "run" | "list"
What to do with the matches:
runnarrows which tests execute;listpreviews them instead. -
greedy: boolean
True when the value was consumed from following argv entries (
-t a b) rather than=glued. -
kind: "query"
Discriminant.
-
value: string | null
The value, or null when the flag was given with nothing after it.
One classified argv entry: a query flag, any other flag, or a positional input.
Launch args passed to Chromium for both the CDP pre-launch spawn and the playwright fallback launch.
Kills all surviving processes that reference dirPath (checked via cwd, cmdline,
and open file descriptors), then retries fs.rm() until it succeeds or a 5-second
deadline expires. Re-scans /proc on each failed rm() attempt to catch processes
that appear after the initial scan (e.g. late-forked Chrome helpers).
Resolves the Chrome/Chromium executable path. Returns a Promise for API compatibility with callers, but the resolution is synchronous.
Kills all surviving processes that reference dirPath (checked via cwd, cmdline,
and open file descriptors), then retries fs.rm() until it succeeds or a 5-second
deadline expires. Re-scans /proc on each failed rm() attempt to catch processes
that appear after the initial scan (e.g. late-forked Chrome helpers).
Resolves the Chrome/Chromium executable path. Returns a Promise for API compatibility with callers, but the resolution is synchronous.
Spawns a headless Chrome process with --remote-debugging-port=0 and resolves once the
CDP WebSocket endpoint appears on stderr. Returns null if Chrome is unavailable or fails
to start, so callers can fall back to playwright's normal chromium.launch().
Launch args passed to Chromium for both the CDP pre-launch spawn and the playwright fallback launch.
The in-flight pre-launch, or a resolved null when startPrelaunch was never called
or decided not to spawn (non-run command, --search, a daemon-routed run, non-chromium, or
macOS — where the CI runner installs playwright's own headless shell and its path is not
known this early).
Kills the pre-launched Chrome process and awaits its async temp-dir cleanup. Must be called before process.exit() so the event loop is still alive and the async rm() inside spawn's close handler can run to completion. Safe to call multiple times or when Chrome was never pre-launched (no-op).
Starts Chrome now, if this invocation is one that will need it.
Spawns a headless Chrome process with --remote-debugging-port=0 and resolves once the
CDP WebSocket endpoint appears on stderr. Returns null if Chrome is unavailable or fails
to start, so callers can fall back to playwright's normal chromium.launch().
Sends a ping and resolves the daemon's pong response (or null on failure).
Runs the suite inside the daemon and answers with the same RunResult a local run produces. The one to reach for; runArgv is the CLI's narrower variant.
The CLI's path: sends raw argv and answers with the exit code the daemon reported.
True iff the user opted in to auto-spawn (QUNITX_DAEMON=1), the invocation
is daemon-eligible, and no daemon is running yet — meaning cli should spawn
one before dispatching the run.
True iff a live daemon socket exists and the invocation can use it. The cli's primary dispatch check.
Sends shutdown and waits until the daemon has actually fully exited — not just
until the socket closes. The daemon's dispatch handler acks 'done' before its
async cleanup (server.close / browser.close / process.exit) runs, so a naive
"stop returned" signal leaves the daemon's socket / named-pipe handle still
held. A fast follow-up daemon start would then race the dying daemon and hit
EADDRINUSE — observed reliably on Windows where named-pipe handle release lags
process exit by tens of milliseconds.
Opens a connection to the daemon for the given cwd. Resolves the connected socket
on success; resolves null on any failure (no socket file, ECONNREFUSED, timeout).
Every way a daemon-routed run can fail to produce an exit code.
The daemon accepted the run and then dropped the connection without a terminal message.
The daemon accepted the connection and then said nothing for RUN_SILENCE_TIMEOUT_MS.
& ((
No daemon was listening — the ordinary case on a cold machine, not an error worth showing.
How long the client waits on total silence before declaring the daemon wedged.
Prints the daemon-mode tip to stderr and creates a sentinel file so the tip is shown at most once per machine — users who already know about the daemon shouldn't be nagged. All filesystem I/O is best-effort: a sentinel-write failure just means the hint shows again on the next eligible run.
Pure check: returns true iff the run context permits the hint. Covers env-var opt-outs, watch / daemon modes (own browser lifecycle), CI (auto-bypassed), the fast-run threshold, and TTY presence. No filesystem access.
Run context consumed by the daemon-hint eligibility check.
-
daemonMode: boolean
True if this is the daemon process itself running the work — never hint.
-
durationMs: number
Total wall-clock the run took, in ms. Used against the fast-run threshold.
-
env: NodeJS.ProcessEnv
Environment to inspect for opt-outs. Defaults to
process.env. -
isTTY: boolean
Override TTY detection (defaults to
process.stderr.isTTY). Used in tests. -
watch: boolean
True if the run is
--watchmode (manages its own browser lifecycle — bypass).
Side-effect injection points for maybePrint — testing seams.
-
sentinelPath: string
Sentinel-file path (defaults to
~/.cache/qunitx/hint-shown). -
write: (text: string) => void
Writer function (defaults to
process.stderr.write).
Ensures a daemon is reachable for the current cwd. Returns true if one was already running or was successfully spawned; false on spawn timeout. Silent — intended for the cli.ts auto-spawn path where the spawn is incidental to the run.
Dispatches qunitx daemon <subcommand>. _serve runs the in-process daemon loop
(spawned by start); all other subcommands are client operations. No subcommand
(or --help / -h / help) prints usage and exits 0; an unknown subcommand
prints usage to stderr and exits 1.
Parses the QUNITX_DAEMON_IDLE_TIMEOUT env value. Accepts:
Result of parseIdleTimeout: the resolved idle window plus an optional human-readable warning the caller should surface to the user.
-
ms: number
Milliseconds.
Infinitywhen the user opts out of auto-shutdown via"false". -
warning: string | null
Human-readable explanation, set when the env value was malformed. The caller is expected to print this on the spawning CLI's stderr so the user sees it — the daemon process detaches with
stdio: 'ignore', so a warning emitted from inside the daemon would be invisible.
Default daemon idle window: 30 minutes after the last run finishes. Long enough for typical edit/run/edit bursts, short enough that a forgotten daemon reclaims resources without manual intervention.
Returns the per-cwd subdirectory that holds the daemon's info file, lockfile, and any future per-daemon state.
Returns the per-cwd sidecar JSON path that mirrors the daemon's socket. Lets
daemon status introspect daemon identity (pid, node version, uptime) without
an IPC roundtrip, and serves as the cross-platform "is a daemon present?" sentinel
since Windows named pipes are not visible on the regular filesystem.
Returns the per-cwd path the daemon listens on. Platform-specific:
Sidecar JSON file written next to the socket; lets daemon status show details without an IPC roundtrip.
-
cwd: string
Working directory the daemon was started in (matches its socket-path hash).
-
nodeVersion: string
Daemon's
process.versionat startup. -
pid: number
OS process id of the running daemon.
-
socketPath: string
Absolute path to the daemon's listening Unix socket.
-
startedAt: number
Epoch ms when the daemon began listening.
The options a daemon run accepts: everything from UserRunOptions that survives a socket.
-
reporter: ReporterName | false
One built-in reporter by name, or
false. An instance cannot cross a socket. -
reporters: ReadonlyArray<ReporterName>
Several built-in reporters by name. Mutually exclusive with
reporter, as it is locally.
Client → daemon: request to execute a test run with the given argv/env in the daemon's persistent Chrome.
-
argv: string[]
CLI arguments after
qunitx(i.e.process.argv.slice(2)). -
cwd: string
Client's working directory. The daemon rejects mismatched cwds (different project).
-
env: Record<string, string | undefined>
Client's full process environment, applied to the run and restored on completion.
-
nodeVersion: string
Client's
process.version. The daemon shuts down on mismatch to avoid module-graph drift. -
options: DaemonRunOptions
Resolved options, when the request came from the JS API rather than a command line. Present means "build the config from these and answer with a
resultchunk"; absent means the daemon parsesargvexactly as the CLI would. -
type: "run"
Discriminator for the protocol union; always
'run'for this variant.
Client → daemon: graceful shutdown request.
-
type: "shutdown"
Discriminator; always
'shutdown'.
Discriminated union of every request the daemon accepts.
| { type: "result"; result: RunResult; }
| { type: "stderr"; data: string; }
| { type: "pong"; pid: number; nodeVersion: string; cwd: string; startedAt: number; }
| { type: "done"; exitCode: number; }
| { type: "fatal"; message: string; }
Daemon → client: one streamed response chunk in the per-request stream.
& { newBrowserCDPSession?: PlaywrightBrowser["newBrowserCDPSession"]; },
Actively confirms the browser's CDP channel is alive, unlike the passive
isConnected() flag which lags a killed browser under load. Does a real
newBrowserCDPSession round-trip bounded by timeoutMs — a dead or wedged
channel resolves false within the budget rather than hanging. Chromium-only:
firefox/webkit use a pipe transport whose 'disconnected' fires promptly on
process exit, so isConnected() is already reliable there.
The crash-budget policy, as one pure decision: what a run's outcome does to the counter, and what should happen next.
Unlinks the daemon's on-disk liveness markers: the socket, the info file, and the lock.
socket/info are gated on listenSucceeded — a daemon that reaches shutdown without ever binding
(e.g. an early throw) doesn't own them, and unlinking would corrupt whatever started in its
place. The lock IS ours unconditionally: reaching shutdown means tryAcquireDaemonLock returned
true, so always release it or the next spawn has to stale-pid-recover.
Daemon process entry point. Owns one persistent Chrome and one Unix socket; serves
run requests serially. Shuts down on SIGTERM/SIGINT, idle timeout, package.json
mutation, node version mismatch, or an explicit shutdown request.
Tears the daemon down: notifies pending clients, removes the on-disk liveness markers, closes
the browser/esbuild within a bounded grace, then exits. Idempotent via state.shuttingDown.
exit is injectable only so the shutdown ordering can be tested without killing the test
process; production always uses the default. See test/commands/daemon-shutdown-test.ts.
Budget for the pre-run liveness probe. A healthy CDP round-trip answers in single-digit ms even on a loaded runner, so this is generous headroom: if it elapses, the browser is dead (or wedged) and recovery relaunches a fresh one. Kept well under GROUP_TIMEOUT_MS so a doomed browser surfaces in seconds, not the 3-minute last-resort deadline.
How long a crash relaunch may take before the daemon declares itself unrecoverable.
Attempts a connection to the given path (POSIX socket or Windows named pipe).
Resolves the connected socket on success, null on any failure (peer absent,
ECONNREFUSED, ENOENT, timeout). Lets net.createConnection produce the error
directly — a pre-emptive existsSync check would not work for Windows named
pipes (they live in \\.\pipe\..., not on the regular filesystem).
Reads NDJSON from socket, dispatching each parsed object via onLine.
Tolerates packet splits across line boundaries; silently drops malformed lines.
Used by both the daemon server (parsing client requests) and the client
(parsing server responses).
Writes a new test file from the boilerplate template, deriving the QUnit module name from the path. Never overwrites an existing file.
Where to scaffold a test file. target is a project-relative path; a missing .js/.ts
extension becomes .js, and missing directories are created.
-
cwd: string
Directory to find the project root from. Defaults to
process.cwd(). -
target: string
Project-relative path of the test file to write.
What generate did: the file it wrote, or the one it refused to overwrite.
-
created: boolean
falsewhen the file already existed and nothing was written. -
path: string
Absolute path of the target file.
Prints qunitx-cli usage information to stdout.
Bootstraps a qunitx project: writes the test HTML template, updates package.json, and writes tsconfig.json when there isn't one.
Where to bootstrap, and which HTML fixtures to write. Both default the way the CLI does:
the working directory, and whatever .html arguments were passed.
-
cwd: string
Directory to find the project root from. Defaults to
process.cwd(). -
htmlPaths: string[]
HTML fixtures to create, relative to the project root. Defaults to
['test/tests.html'].
What init did, so the caller can report it. Returned rather than printed: the CLI turns
these into its messages, and a programmatic caller gets the same facts as data.
-
skipped: string[]
Paths that already existed and were left alone.
-
written: string[]
Absolute paths of the files this call created.
Expands each directory to its real path before anything watches it.
Runs a script file in a real browser: bundles it with esbuild, serves it from a localhost
origin, evaluates it as a module in the page, and streams its console output to this
terminal. Resolves once the script's top level — including any top-level await — settles.
Reads qunitx run's argv into a target and its settings.
The qunitx <file> line the suite warning suggests, with forward slashes.
The directories watch mode should watch, from esbuild's metafile input keys.
Runs run once, then again on every change to a first-party file in the bundle. Never resolves
— watch mode ends when the process is signalled — except to REJECT if the very first run
throws, which is a script that never started rather than a bad edit to recover from.
Everything one qunitx run invocation needs. Its own type rather than the test runner's
Config: a script has no test files, no filter, no reporter and no output directory, and
threading a script mode through those would make every one of them mean two things.
-
browser: "chromium" | "firefox" | "webkit"
Engine the script runs in.
-
console: Console
Where the script's own output goes.
processConsolefor the CLI. -
cwd: string
Directory relative imports and
node_moduleslookups resolve from. -
debug: Args.ParsedFlags["debug"]
--debug: prints the server URL and the page's console, as the bare verb's does. -
entry: string
Absolute path of the script to run.
-
filter: Args.ParsedFlags["filter"]
--filter: narrows a declared suite to matching tests. -
junit: Args.ParsedFlags["junit"]
--junit: writes a JUnit XML report for a declared suite. -
open: boolean
--open: run in a visible browser window. -
port: number
Port the local server binds. Updated in place to the port actually bound.
-
portExplicit: boolean
True when
--portwas given, which makes a taken port an error instead of a search. -
projectRoot: string
Directory holding the nearest
package.json; mapped stack frames print relative to it. -
reporter: Args.ParsedFlags["reporter"]
Reporting settings that only matter if the entry turns out to declare tests.
-
timeout: number | null
--timeout: ms the script may run before it is declared hung, or null for unbounded. -
watch: boolean
--watch: re-run on every save instead of exiting after one run.
What qunitx run's argv amounts to: the one target, and the settings the flags asked for.
-
entry: string
The single target, exactly as it was written on the command line.
-
settings: ScriptSettings
Everything the flags set, including the
projectRootthe parse already resolved.
What one execution of the script produced.
-
browserLogs: BrowserLog[]
The script's own console calls and uncaught errors, in emit order and capped at MAX_BROWSER_LOGS — the same shape and the same cap a test run reports, because it is the same thing: a page's console, read over CDP.
-
browserLogsDropped: number
How many were dropped to stay under the cap.
0when nothing was. -
entry: string
Absolute path of the file that ran, resolved against
cwd. -
exitCode: number
globalThis.exitCodeif the script set one, 1 if it threw, else 0. -
tests: RunResult | null
The suite the entry declared, or
nullwhen it was a plain script. -
value: unknown
The script's
export default, orundefinedwhen it has none — or when it had one that could not be handed back, in which case ScriptOutcome.valueProblem says so. -
valueProblem: string | null
Why ScriptOutcome.value is
undefineddespite the script exporting something, ornullwhen there is nothing to explain.
Everything a caller may set on a script run: the CLI's flags and the API's options, minus argv.
-
browser: "chromium" | "firefox" | "webkit"
Engine the script runs in. Defaults to chromium.
-
console: Console
Where the script's own output goes, as
test()andwatch()take one. Defaults to this process's stdout and stderr; passsilentConsoleto capture it from the result instead. -
cwd: string
Directory the entry, relative imports and
node_moduleslookups resolve against. -
debug: Args.ParsedFlags["debug"]
Prints the server URL and the page's console, as the bare verb's
--debugdoes. -
filter: Args.ParsedFlags["filter"]
Narrows a declared suite to matching tests. Ignored by a plain script.
-
junit: Args.ParsedFlags["junit"]
Writes a JUnit XML report for a declared suite. Ignored by a plain script.
-
open: boolean
Run in a visible browser window.
-
port: number
Port the local server binds. Defaults to 1234.
-
portExplicit: boolean
True when a port was named explicitly, which makes a taken one an error rather than a search.
-
projectRoot: string
Skips the
package.jsonwalk when the caller has already done it. -
reporter: Args.ParsedFlags["reporter"]
Stdout format when the entry turns out to be a suite. Ignored by a plain script, which has no report to format — its own output IS the output.
-
timeout: number | null
Ms the script may run before it is declared hung; null (the default) is unbounded.
-
watch: boolean
Re-run on every save instead of exiting after one run.
| Failure.Of<ScriptNotFound>
| ProjectRootNotFoundFailure
| Args.ParseFailure
Every way setup can reject its input.
The two ways naming an entry can fail, before any flag or option is even looked at.
The script could not be bundled — a syntax error, or an import that does not resolve.
qunitx run was pointed at a file that is not there.
qunitx run was given no script file, or more than one.
--search / -s / --print / --preview: list the tests the current selection matches,
without running them.
Scans the selected files and resolves which of their tests the current selection matches — no browser, no bundle, no execution.
One test found by the static scan, named exactly as QUnit would name it.
-
file: string
Absolute path of the file it was declared in — used to apply that file's line targets.
-
fullName: string
"Module > Sub: test name"— the string a filter matches against. -
line: number
1-based line of the declaration.
-
modules: string[]
The QUnit module path it is declared under; empty for a top-level test.
-
name: string
The test's own name.
What the static scan found, before anything is printed.
-
files: number
How many files were scanned.
-
filter: string
The expression matched against, or
undefinedwhen everything was listed. -
matches: FoundTest[]
The tests the current selection matches, in declaration order.
-
total: number
Every listable test found, matched or not.
-
unlistable: UnlistableCounts
What the scan could not name, split by cause.
-
warnings: string[]
Line-target resolution warnings, in input order.
Why some declarations could not be listed, split by cause.
-
computedNames: number
Declarations whose name is computed at run time —
test(`case ${index}`). -
silent: number
Files that parsed but declared no test the scan could see, e.g. via a local alias.
-
total: number
The three below, added up.
-
unparseable: number
Files that could not be read or parsed at all.
Runs the whole suite once in headless Chrome and resolves with its RunOutcome.
The qunitx run <file> line a zero-test run suggests, with forward slashes.
Starts a watch session: one browser, one page, every test file in a single bundle, behind an HTTP server that stays up. Resolves once the initial run has finished and the watchers are armed — the returned WatchSession is how the caller stops it again.
How a one-shot run ended. Everything a caller needs to decide what happens next, and nothing about how it should be announced — run neither writes a summary nor exits.
-
durationMs: number
Wall-clock duration of the test phase in milliseconds.
-
exitCode: number
0when every test passed,1for any failure, group rejection, or empty filtered run. -
finishedAt: number
Epoch ms when it ended.
finishedAt - startedAtisdurationMsmodulo clock resolution. -
startedAt: number
Epoch ms when the test phase began — after the bundle, at the first navigation.
A live watch session: the run's browser, server and file watchers, kept open.
-
abort(): void
Tells the browser to drop the rest of the current run's queue.
-
close(): Promise<Abandoned>
Stops the watchers and closes the browser and server. Idempotent.
-
config: Config
The resolved config this session runs with; its
statecarries the live counters. -
connections: Connections
The session's browser, page and HTTP server.
-
fileWatchers: Record<string, FSWatcher>
The live per-path
fs.watchhandles, keyed by watched path — the same object the watcher mutates, not a copy. A PARTIAL view: the parent-directory watchers, rescan intervals and symlink pollerskillFileWatchersalso owns are not in here, so it answers "what is being watched", not "every handle the watcher holds". -
run(files?: string[]): Promise<void>
Re-runs now, optionally scoped to
files; resolves when that run finishes. -
runAll(): Promise<void>
Runs the whole suite, dropping any line-target selectors this session was scoped to.
-
runFailed(): Promise<void>
Re-runs the files that last failed, or repeats the last run when nothing has failed yet.
-
running: boolean
Whether a run is executing or queued — true from the moment one is asked for.
-
settled(): Promise<void>
Resolves once nothing is in flight — a no-op at the back of the rerun queue.
-
teardown(disposeEsbuild?: boolean): Promise<Abandoned>
close minus the two teardowns a restart must not do, because it is building a replacement in the same process rather than ending.
-
url: string
Where the QUnit view is being served, e.g.
http://localhost:1234.
Watch-mode line targets: narrow fsTree to the targeted files and apply their selectors for the whole session.
Resolves each file#34 input into the selectors for that file, dropping targets whose file is
no longer in the run (a glob, --changed or --only-failed may have filtered it out) and
those that resolved to nothing — both fall back to running the file whole, which is what a
null selectors means. Every warning is surfaced; a line target that quietly did not narrow
is worse than one that says so.
Packs files into groupCount groups of roughly equal estimated duration, returning the groups
and the per-file weights the estimate used (the caller reuses them to apportion wall time).
Arms V8 line coverage on the page before navigation, returning whether it started.
resetOnNavigation: false keeps the data across the goto below, so the bundle's execution
is captured. Chromium-only — run.ts already disables coverage for firefox/webkit, and
page.coverage exists only on chromium pages.
Builds all concurrent group bundles with a single esbuild invocation.
Pre-builds the esbuild bundle for all test files and caches the result in the group's build state.
Cache key for the daemon/watch incremental esbuild context. Single source of truth
for what makes two builds interchangeable: file set + every BuildOption that varies
between runs. Items intentionally NOT keyed: plugins (daemon shuts down on
package.json mtime change; the prepended qunitxRuntimePlugin is static and
deterministic), nodePaths (cwd-bound, daemon stays in cwd), and the
hardcoded literals (bundle, keepNames, legalComments, jsx, sourcemap,
footer, logLevel). When adding a new variable BuildOption, extend this function
— that is the contract enforced by the unit suite.
Classifies a finished browser run.
Derives a human-readable error category from an esbuild BuildFailure or a generic Error. Inspects the first structured esbuild message when available; falls back to string heuristics.
Awaits all in-flight console handler promises until the Set is stably empty, recursing to catch handlers added by Firefox BiDi events that arrive during each await. The deadline (default 2 s) guards against infinite recursion.
Formats esbuild BuildFailure messages into clean human-readable text (no ANSI codes). When given a structured BuildFailure, each error is formatted with its file location and a caret line. Falls back to stripping ANSI codes from the error's string representation.
Reconciles the Node-side counter with QUnit's authoritative in-page tally after a run finishes, for a single-group run. Returns how many finished results the WebSocket stream failed to deliver (0 on a clean run).
Runs the esbuild-bundled tests inside a Playwright-controlled browser page and streams TAP output.
| { kind: "empty"; }
| { kind: "no-tests-ran"; }
| { kind: "stalled"; }
How a browser run ended, decided from QUnit's tally plus whether a WS done arrived.
Distributes each group's wall-clock ms to its files proportionally by LPT weight.
Writes the merged per-file timings back to tmp/test-timings.json for the next run to pack with.
--debug listing of this run's per-file wall times, slowest first.
Reads tmp/test-timings.json from projectRoot; returns {} on any error or invalid content.
Resolves the channel this process is running from.
Whether this channel's updater is qunitx's to run.
The command that upgrades this channel: deno install, npm install -g, deno add, git pull.
updateArgv rendered as one line, for printing.
The observable state detect reads. Every field defaults to this process, and every field is injectable so each channel is reachable in a test without that install existing.
-
denoDir: string
An explicit
DENO_DIR, which relocates the module cache off its recognisable path. -
execPath: string
process.execPath: the compiled binary itself, or the node/deno that is running it. -
fileExists: (target: string) => boolean
Existence probe for the only filesystem question asked: which manifest sits above the install.
-
isDeno: boolean
Whether the Deno global is present, which is what separates a
deno compilebuild from a SEA. -
modulePath: string
Absolute path of a file inside the installed package —
undefinedinside a SEA bundle. -
platform: NodeJS.Platform
Path semantics to apply. Defaults to the host's.
| { kind: "jsr-launcher"; binaryPath: string; version: string; }
| { kind: "npm-global"; prefix: string; }
| { kind: "npm-local"; projectRoot: string; manifest: string; }
| { kind: "deno-project"; projectRoot: string; manifest: string; }
| { kind: "deno-cache"; entry: string; }
| { kind: "source"; entry: string; }
The install channel this process is running from — the one thing upgrade must get right,
since only one of them can replace itself.
Parses qunitx upgrade's arguments. A bare 0.34.2 (or v0.34.2) pins the version, the same
as --version=0.34.2.
Runs qunitx upgrade.
The seams run reaches the world through: the channel it believes it is, the release lookup,
the installer, and where its text goes. Every one defaults to the real thing.
-
allowSelfUpgrade: boolean
Whether qunitx may run another tool's installer on the user's behalf. Defaults to true unless
QUNITX_NO_SELF_UPGRADEis set — for a locked-down image, a CI box, or anywhere the answer to "may this process install things" is no. Blocked,upgradeprints the command it would have run and exits 1, which is what it did before it could run anything. -
apply: (plan: Install.InstallPlan) => Promise<string[]>
The installer. Defaults to Install.apply.
-
arch: string
Architecture used for asset selection. Defaults to the host's.
-
channel: Channel.InstallChannel
The install channel. Defaults to Channel.detect.
-
console: Console
Where the command's output goes. Defaults to the process streams.
-
currentVersion: string
The version considered installed. Defaults to this package's.
-
find: (version?: string) => Promise<Release.Release>
The release lookup. Defaults to Release.find.
-
platform: NodeJS.Platform
Platform used for asset selection. Defaults to the host's.
-
spawn: (argv: string[]) => Promise<Process.SpawnResult>
Runs another tool's installer. Defaults to Process.spawn.
What qunitx upgrade's argv asked for.
-
check: boolean
Report only: no download, no replace.
-
force: boolean
Replace even when the requested version is the one already running.
-
help: boolean
Print usage and stop.
-
version: string
The pinned version, without its
v. Absent means "the latest release". -
writeManifest: boolean
Bump the declared range in the project's manifest instead of refusing outright.
An argument this command will not accept.
Downloads the release archive, verifies it against the release's checksums.txt, and replaces
the running binary (and its esbuild sidecar, when the install has one).
Unpacks a release archive with the host's tar / unzip, falling back to PowerShell's
Expand-Archive where a Windows shell has no unzip — the same two-step jsr/cli.ts uses,
for the same reason: no JS extractor has to ship inside the binary.
Puts staged at target, honouring the one platform rule that matters: POSIX replaces a
running executable with an atomic rename (the running process keeps its inode), while Windows
cannot unlink a running image at all — so the old file is renamed aside first, and renamed back
if anything goes wrong.
The seams apply reaches the world through. All three default to the real thing.
-
access: (directory: string) => Promise<void>
Rejects when the install directory cannot be written. Defaults to
fs.access(dir, W_OK). -
extract: () => Promise<void>archivePath: string,destination: string
Unpacks the archive into a directory. Defaults to extract.
-
fetch: fetch
Fetches the checksum file and the archive.
What to install, and over what.
-
assetName: string
The archive to download from it.
-
binaryPath: string
The running executable to replace, and whose directory receives the sidecar.
-
platform: NodeJS.Platform
Path and replace semantics to apply. Defaults to the host's.
-
release: Release
The release to install, as Release
findreturned it.
The release has no asset for this platform — a deno compile build asking for a target only
the SEA matrix publishes, or the reverse.
The downloaded bytes do not hash to what the release published — a corrupted or truncated transfer, or a tampered asset. Nothing has been replaced when this is thrown.
The release publishes no checksums.txt, so the download cannot be verified. Refused rather
than downgraded to a warning: an unverified binary replacing the one you are running is
exactly the thing worth refusing.
The download itself failed — an HTTP error or a dead connection mid-transfer.
The replace itself failed, after the new binary was downloaded and verified. Carries the recovery path when the old binary had to be moved aside first.
The directory holding the binary is not writable by this user — the usual case being a
root-owned prefix such as /usr/local/bin.
Points the manifest's qunitx-cli entry at version, keeping whatever range operator it already
used: ^ stays ^, ~ stays ~, and an exact pin stays exact.
Which registry a deno manifest pins qunitx-cli through, so a refusal names the deno add that
updates the entry already there instead of adding a second one beside it. npm when the file
says nothing, matching what deno add qunitx-cli resolves to.
What bump changed: where the entry lives, and the range it now carries.
-
field: string
The part of the manifest that changed:
imports,dependenciesordevDependencies. -
range: string
The range now written there, operator included.
A manifest that declares qunitx-cli, but not at a version this can bump — an unpinned specifier, or a dependency that is not declared there at all.
Runs another tool's installer — deno install, npm install -g — and reports how it went.
How the installer this process ran finished — shaped like the process it describes.
-
exitCode: number | null
The installer's exit code. Null when a signal killed it, or when it never started.
-
isMissingInstallerBinary: boolean
True when the installer is not on PATH at all —
denoon a machine without deno. -
signalCode: NodeJS.Signals | null
The signal that killed it, or null when it exited on its own.
The release asset that replaces a running binary of this flavor, or null when this
platform has no published build — the SEA matrix covers three targets, the deno one five.
Compares two x.y.z versions the way a release line orders them: negative when a is older,
0 when they are the same, positive when a is newer.
Fetches the newest release, or the one matching version when pinned.
Parses the release's checksums.txt (sha256sum output) into name → sha256.
A published release, reduced to what an upgrade needs.
-
assets: ReleaseAsset[]
Every asset the release publishes, including
checksums.txt. -
tag: string
The git tag,
v-prefixed as the workflow creates it. -
version: string
The tag without its
v, which is what package.json and--versionspeak.
One downloadable file on a release.
-
name: string
The asset's file name, e.g.
qunitx-deno-linux-x64.tar.gz. -
url: string
Its
browser_download_url.
The release lookup could not be answered — no network, a proxy, an HTTP error, or GitHub's unauthenticated rate limit.
A pinned version that has no published release.
Adapts anything with a write(string) — a node:fs stream, a socket, an array-backed fake —
into a Console. stderr defaults to stdout, so one stream collects the whole run.
Where a run's text goes: console, made injectable.
-
error(text: string): void
Writes to the error stream. Diagnostics that must survive a swallowed stdout go here too.
-
log(text: string): void
Writes to the primary stream — the TAP/spec/dot document itself.
The CLI's: the real process streams. .write is looked up per call, so the daemon's stdout
interception still reaches it.
Discards everything. The JS API's default, so a programmatic run prints nothing unless it was asked to.
Merges one page's stopJSCoverage() result into config.state.results.coverage. No-op unless
coverage is enabled and a source-map decoder is present. Only the test bundle is attributed;
node_modules sources are dropped here (test entry files are dropped later, in the report layer).
Merges one page's stopJSCoverage() result into config.state.results.coverage. No-op unless
coverage is enabled and a source-map decoder is present. Only the test bundle is attributed;
node_modules sources are dropped here (test entry files are dropped later, in the report layer).
Builds a self-contained HTML report: a summary table plus per-file source with line coloring.
Builds a standard LCOV lcov.info string (line coverage only: DA/LF/LH per file).
Turns the raw coverage map into sorted, test-file-filtered rows with computed percentages.
Renders the run's accumulated coverage: always prints the terminal summary, then writes the
lcov/html reports the user requested via config.coverageFormats. testFiles (the run's
test entry paths) are excluded so the report reflects the code under test, not the tests.
Coverage report rendering — writes the report and builds its rows/lcov/html forms.
Builds a self-contained HTML report: a summary table plus per-file source with line coloring.
Builds a standard LCOV lcov.info string (line coverage only: DA/LF/LH per file).
Turns the raw coverage map into sorted, test-file-filtered rows with computed percentages.
Renders the run's accumulated coverage: always prints the terminal summary, then writes the
lcov/html reports the user requested via config.coverageFormats. testFiles (the run's
test entry paths) are excluded so the report reflects the code under test, not the tests.
One character per test, failures reported in full at the end. The right shape for large suites and CI logs, where a line per test is thousands of lines of noise but you still want live progress.
-
onRunEnd(): voidcontext: ReporterContext,info: RunEndInfo
Closes the matrix line, then prints the counts and every buffered failure.
-
onRunStart(): voidcontext: ReporterContext,info: RunStartInfo
Resets the matrix column and buffered failures, then prints the run banner.
-
onTestEnd(): voidcontext: ReporterContext,details: TestDetails
Writes this test's character, wrapping the matrix, and buffers any failure detail.
Extracts the source location from a stack trace string. Supports Chrome/Node style "at func (url:line:col)" and Firefox/WebKit style "@url:line:col". Returns a clean location string without surrounding parens, or null if nothing can be extracted.
Extracts every genuinely-failing assertion (todo assertions are expected to fail and are
excluded) from a testEnd payload, resolving stacks back to original sources.
Splits an at string (path:line:col) into parts; returns null when it isn't a location.
One failing assertion, normalized for rendering. Every reporter needs the same three things — what failed, where in the original source, and the values involved — so the source-map resolution and value normalization happen once here rather than per reporter.
-
actual: unknown
The value the assertion saw, normalized so circular refs are safe to dump.
-
at: string | null
path:line:colof the first user frame (preferred) or the raw stack location. -
expected: unknown
The value the assertion required, normalized the same way as
actual. -
index: number
1-based index of the assertion within the test (matches TAP's
Assertion #N). -
message: string | null
The assertion's message, or
nullwhen it had none. -
source: string | null
The original source line's text, when the map embeds
sourcesContent. -
stack: string | null
Stack with bundle frames rewritten to original sources when a decoder is available.
GitHub Actions reporter: spec output, plus a ::error workflow command per failure so the
failure is annotated inline on the PR diff.
-
onRunEnd(): voidcontext: ReporterContext,info: RunEndInfo
Delegates the summary + failure recap to the spec renderer.
-
onRunStart(): voidcontext: ReporterContext,info: RunStartInfo
Delegates the run banner to the spec renderer.
-
onTestEnd(): voidcontext: ReporterContext,details: TestDetails
Renders the spec line, then annotates each failing assertion for the PR diff.
Builds one ::error file=…,line=…,col=…,title=…::message workflow command.
Emits one console.* call or uncaught error from the page under test. Rendered verbatim —
no # prefix — because it is the page's output, not qunitx's, and prefixing it would corrupt
whatever the page was deliberately printing.
Reporter wiring. config.reporter selects exactly one stdout reporter; artifact
reporters (JUnit) are additive and stack on top. Built once per run in Config.setup and
shared by every concurrent group — the group configs are spread off the parent config, so
they all reference this same array (the same way the run counter is shared).
A diagnostic that also belongs on stderr — a stack trace, a timeout, a page that crashed.
A decision the runner made and wants on the record — what it chose to run, what it skipped.
Emits run end to every active reporter, awaiting any that flush asynchronously.
Emits run start to every active reporter. In watch mode this fires once per rerun.
Applies one testEnd to the counters, then fans it out to every active reporter.
The counter update happens here — exactly once, before any reporter runs — so counts stay
correct regardless of how many reporters are attached.
Something surprising that did not stop the run — a filter that matched nothing, a flag that does not apply to the chosen browser.
Options a diagnostic can carry beyond its text. Both default to the CLI's long-standing behaviour, so only the handful of call sites that need something else say so.
-
raw: boolean
Write the message verbatim rather than as a
#-prefixed TAP comment. For pre-formatted blocks — the coverage table, a stack trace — whose own layout is the point. -
stream: "output" | "error" | "both"
Which of the run's two streams the default rendering goes to.
outputby default.
The --reporter value -> its class. Keyed by ReporterName, so adding a name to REPORTERS
without wiring it up here is a type error rather than a silent fall back to tap.
JUnit XML reporter — an additive artifact reporter, not a stdout format. Enabled with
--junit[=<path>], it accumulates a <testcase> per testEnd and writes the document at
run end, while whichever --reporter is active keeps owning stdout. That split matters:
CI wants a readable log and a machine-readable file, and it's what --coverage=lcov
already does for coverage artifacts.
-
onRunEnd(): Promise<void>context: ReporterContext,_info: RunEndInfo
Serializes the accumulated cases and writes the XML document to disk.
-
onRunStart(): void
Drops cases from any previous run so watch reruns start clean.
-
onTestEnd(): voidcontext: ReporterContext,details: TestDetails
Accumulates one
<testcase>; the document is written once at run end. -
xml(): string
The XML document as it stands.
onRunEndwrites exactly this to disk; the JS API reads it back so a caller can ship the report somewhere other than the filesystem.
Builds the full JUnit XML document string from a flat list of test cases.
Resolves where the JUnit document is written: --junit=<path> (relative to the project
root) when given a string, else <output>/junit.xml.
Converts one testEnd into a JUnit <testcase>. Failing assertions are flattened into a
failureDetail with stacks resolved back to original sources (same as the TAP at: field).
Human-readable reporter: tests nested under their QUnit module, with failures shown inline where they happen. The shape Node, Vitest and Mocha all default to — raw TAP is a poor local-dev experience.
-
onRunEnd(): voidcontext: ReporterContext,info: RunEndInfo
Prints the outcome counts and, when any test failed, the failure recap.
-
onRunStart(): voidcontext: ReporterContext,info: RunStartInfo
Resets per-run state and prints the run banner.
-
onTestEnd(): voidcontext: ReporterContext,details: TestDetails
Prints the module header when it changes, then this test's result line.
Renders every failing assertion of one test: message, values, and source location.
The default reporter: streams TAP version 13 to stdout. Stateless — every number it
prints comes from context.counts, which the dispatcher updates before onTestEnd.
-
onRunEnd(): voidcontext: ReporterContext,info: RunEndInfo
Emits the TAP plan line and the run summary.
-
onRunStart(): voidcontext: ReporterContext,info: RunStartInfo
Emits the TAP version header, plus the run banner as a
#comment. -
onTestEnd(): voidcontext: ReporterContext,details: TestDetails
Emits the
ok/not okline, with a YAML block for each failing assertion.
Applies one testEnd to the run's counters. Kept separate from any reporter so the
numbers are identical no matter which reporter (or how many) is active — the exit code
and the TAP plan both read counter, so it must be updated exactly once per test.
A console.* call or an uncaught error from the page under test.
-
args: unknown[]
The call's arguments, resolved to JSON values where the page could serialize them.
-
text: string
The rendered single-line text. Always present.
-
type: string
The page console type (
log/warning/error/info/debug), orpageerror.
One diagnostic from qunitx itself: which files a narrowing flag scoped the run to, a filter that matched nothing, a build error, a timeout.
-
level: "info" | "warning" | "error"
infois a decision,warninga surprise,errora diagnostic that also hits stderr. -
message: string
The text, already colored where the CLI colors it, with no
#prefix and no newline. -
raw: boolean
Write
messageverbatim rather than as a#-prefixed comment. For pre-formatted blocks — the coverage table, a stack trace — whose own layout is the point. -
stream: "output" | "error" | "both"
Which of the run's two streams the default rendering goes to;
outputby default.
The reporter contract — the public extension point for observing a run. Reporters render it
to text (the built-in tap/spec/dot/github), write an artifact (junit), or simply
collect, which is how the JS API turns a run into a value.
-
onBrowserLog(): voidcontext: ReporterContext,log: BrowserLog
Called for each
console.*call and uncaught error from the page under test. Only warnings and errors arrive unlessdebugis on — the same selection the CLI prints. -
onNotice(): voidcontext: ReporterContext,notice: Notice
Called for each of qunitx's own diagnostics — the
# …lines about what it decided to run, what it could not find, what timed out. The default rendering has already gone toconfig.state.console; implement this only to capture them as data. -
onRunEnd(): void | Promise<void>context: ReporterContext,info: RunEndInfo
Called once when the run finishes, with the final counts on
config.state.results.counter. -
onRunStart(): voidcontext: ReporterContext,info: RunStartInfo
Called once before any test output. In watch mode, once per rerun.
-
onTestEnd(): voidcontext: ReporterContext,details: TestDetails
Called once per test, after
counterhas already been updated for this test.
What a reporter is given on every hook: where to write, what the run has counted so far, and the few resolved paths a message needs.
-
console: Console
Where this reporter's text goes.
silentConsolewhen the run was asked to print nothing. -
counts: Counter
The run's live outcome totals — the same object the runner updates, not a copy.
-
daemon: boolean
Whether this run is executing inside the persistent daemon.
-
junit: boolean | string
--junit's value:truefor the default path, a string for an explicit one. -
output: string
Absolute path of the build output directory.
-
projectRoot: string
Absolute path of the directory holding
package.json, for rendering paths relative to it. -
sourceMapDecoder: SourceMapDecoder | null
Maps a bundle stack frame back to source, once the run has built one.
Final run info; the counts themselves live on config.state.results.counter.
-
durationMs: number
Wall-clock duration of the run in milliseconds.
Run-scope counts. fileCount === null means "counts unknown at this point" (watch mode,
where the header is emitted per browser connection rather than per file batch).
-
fileCount: number | null
Test files in this run, or
nullwhen not known at announce time. -
groupCount: number | null
Concurrent groups the files were split across, or
nullalongside a nullfileCount.
One QUnit assertion inside a testEnd payload.
-
actual: unknown
The value the assertion actually saw.
-
expected: unknown
The value the assertion required.
-
message: string
The assertion's message, when one was given.
-
passed: boolean
truewhen the assertion held. -
stack: string
Raw stack captured at the assertion, with frames pointing at the bundle.
-
todo: boolean
truefor assertions inside atodotest, which are expected to fail.
The QUnit testEnd payload as it arrives over the WebSocket. Passing tests carry the
trimmed { status, fullName, runtime }; failing tests additionally carry assertions.
-
assertions: TestAssertion[]
Present on failing tests only (QUnit trims the payload otherwise).
-
fullName: string[]
Module path followed by the test name, e.g.
['Math', 'adds']. -
runtime: number
Test duration in milliseconds.
-
status: string
QUnit's outcome:
passed|failed|skipped|todo.
A valid --reporter value.
Every stdout reporter --reporter accepts, in help/error-message order. Exactly one is
active per run — artifact outputs (--junit, --coverage) are separate additive flags.
This module is a leaf (type-only imports), so Args.parse can validate against it
without pulling the reporter implementations into the CLI's startup path.
A structured, discriminable error.
-
code: Code
The discriminant. Narrow on this, never on
instanceof. -
data: Data
Structured payload supplied by the throw site.
-
toJSON(): SerializedFailure
Serializes to plain JSON so
console.log(JSON.stringify(failure))is not{}.
Span/log attributes a failure declares for tracing: failure.code plus whatever its
factory's trace mapper (see define) explicitly allowlisted from data. A
failure whose factory declared no mapper yields the code alone — unmapped payload
fields never leave the process, which is what makes redaction (passwords, tokens) the
default rather than a discipline.
Flattens an error's cause chain into an array, error first and the root cause last.
define() overload for failures that carry no payload.
Renders an error and its whole cause chain as indented, human-readable lines.
Coerces any caught value into a Failure, leaving existing Failures untouched.
Revives a SerializedFailure into a real Failure, reconstructing the cause chain.
Narrows a Failure to one of several codes — the multi-code sibling of Factory.is.
Builds a .catch() handler for a failure that genuinely has no consequence — but says so
under QUNITX_DEBUG instead of vanishing. This is the raw handler; the ergonomic spelling
at call sites is Task(promise).ignore(context), which wraps exactly this function.
Whether value is a Failure — from this realm or any other.
True for a factory made by define. A factory carries the code it produces and its
own is guard; a plain error-mapper carries neither, so an API can accept both in one
position and tell them apart exactly, without guessing from arity.
Whether value is a Failure — from this realm or any other.
Reports a declared failure to the observation seam — onObserved plus the
OBSERVED_CHANNEL_NAME channel. Task's consuming methods call this at their
classification points; call it yourself only for a synchronous Result flow that never
crossed a Task, so a tracing adapter sees those failures too.
Installs a process-wide observer for every ignored failure — the interception seam for
"list everything the program decided not to handle". Costs one null check on the failure
path only (nothing on success, nothing per Task), and retains nothing itself: whether the
suppressed failures accumulate, sample, or stream somewhere is the observer's decision.
Pass null to detach.
Installs a process-wide observer for every handled declared failure — the portable
(browser-friendly) counterpart of subscribing to OBSERVED_CHANNEL_NAME. Single
slot, one null check on the failure path, nothing retained; pass null to detach.
The deepest cause in the chain — the original failure, whatever wrapped it since.
Toggles ignored-failure reporting at runtime, overriding the QUNITX_DEBUG default.
Converts a Failure (or any error) into plain JSON.
Per-kind options accepted by define().
-
trace: (data: Data) => TraceAttributes
Allowlist mapper from the typed payload to span/log attributes, consumed by attributes. Deliberately not a redaction filter: only what the mapper returns is ever exposed, so sensitive fields are private by omission, not by scrubbing.
A callable failure constructor produced by define(), carrying its own type guard.
-
code: Code
The literal code this factory produces. Useful as a
switchcase and in registries. -
is(value: unknown): value is Failure<Code, Data>
Cross-realm type guard narrowing to this exact failure — the flat rethrow line's guard after a
Result.try.
Options accepted by the Failure constructor and by every generated factory.
-
cause: unknown
The error this failure was derived from. Preserved verbatim and walked by
causes(). -
stackAnchor: (...args: never[]) => unknown
The function to truncate the stack at, so the top frame is the code that reported the failure rather than the plumbing that built it. Defaults to the constructor.
-
stackless: boolean
Skips stack capture. Only worth setting for failures produced in a hot loop and consumed immediately — the capture, not the allocation, is what a Failure costs. See the performance section of the docs before reaching for it.
The wire form of a Failure — what toJSON emits and fromJSON accepts.
-
cause: SerializedFailure
| { name: string; message: string; stack?: string; }The serialized cause chain: a nested Failure, or a plain error's identifying fields.
-
code: string
The discriminant. Survives the wire, unlike a prototype.
-
data: unknown
The structured payload, JSON round-tripped by
toJSONso it cannot fail later. -
failure: true
Wire marker.
Symbol.forkeys survive neitherJSON.stringifynorstructuredClone, so the serialized form carries an explicit field in the brand's place. -
message: string
The human-readable sentence, already interpolated from
data. -
stack: string
The producing process's stack. Frameless — the header line alone — when the failure was built
{ stackless: true }; the field itself is absent only ifstackwas never set.
Any Failure at all — the type to reach for when a signature accepts failures it does not
enumerate, e.g. Result<T, Failure.Any> at a boundary that only logs.
The callback shape onIgnored installs: every ignored failure arrives with the label its call site declared.
The callback shape onObserved installs: every declared failure a consumer classified arrives right as it is handed to application code.
The Failure type a factory produces: Failure.Of<typeof FileMissing>.
The attribute primitives tracing systems accept (OpenTelemetry's span-attribute values) —
what a trace mapper returns and attributes yields.
Name of the diagnostics_channel that ignore publishes to on Node and Deno —
subscribe with the platform API, no qunitx registry involved. Messages are
{ context: string, error: unknown }. Browsers have no channel; use onIgnored.
Name of the diagnostics_channel that observed publishes to on Node and Deno.
Messages are { error: Failure.Any }. This is what a tracing adapter subscribes to —
e.g. OpenTelemetry, in its entirety:
The failure from() produces for a throwable that is not already a Failure.
A structured, discriminable error.
-
code: Code
The discriminant. Narrow on this, never on
instanceof. -
data: Data
Structured payload supplied by the throw site.
-
toJSON(): SerializedFailure
Serializes to plain JSON so
console.log(JSON.stringify(failure))is not{}.
Collects an array of outcomes into an array of values, short-circuiting on the first
failure — the Result-shaped analogue of Promise.all.
Returns the success value, or throws new Error(message, { cause: failure }).
Span/log attributes a failure declares for tracing: failure.code plus whatever its
factory's trace mapper (see define) explicitly allowlisted from data. A
failure whose factory declared no mapper yields the code alone — unmapped payload
fields never leave the process, which is what makes redaction (passwords, tokens) the
default rather than a discipline.
Flattens an error's cause chain into an array, error first and the root cause last.
define() overload for failures that carry no payload.
define() overload for failures whose message is derived from their payload.
Renders an error and its whole cause chain as indented, human-readable lines.
Coerces any caught value into a Failure, leaving existing Failures untouched.
Revives a SerializedFailure into a real Failure, reconstructing the cause chain.
Narrows a Failure to one of several codes — the multi-code sibling of Factory.is.
Builds a .catch() handler for a failure that genuinely has no consequence — but says so
under QUNITX_DEBUG instead of vanishing. This is the raw handler; the ergonomic spelling
at call sites is Task(promise).ignore(context), which wraps exactly this function.
Whether value is a Failure — from this realm or any other.
Whether value is a Failure — from this realm or any other.
True for a factory made by define. A factory carries the code it produces and its
own is guard; a plain error-mapper carries neither, so an API can accept both in one
position and tell them apart exactly, without guessing from arity.
Whether value is a Failure — from this realm or any other.
Whether value is a Failure — from this realm or any other.
Reports a declared failure to the observation seam — onObserved plus the
OBSERVED_CHANNEL_NAME channel. Task's consuming methods call this at their
classification points; call it yourself only for a synchronous Result flow that never
crossed a Task, so a tracing adapter sees those failures too.
Installs a process-wide observer for every ignored failure — the interception seam for
"list everything the program decided not to handle". Costs one null check on the failure
path only (nothing on success, nothing per Task), and retains nothing itself: whether the
suppressed failures accumulate, sample, or stream somewhere is the observer's decision.
Pass null to detach.
Installs a process-wide observer for every handled declared failure — the portable
(browser-friendly) counterpart of subscribing to OBSERVED_CHANNEL_NAME. Single
slot, one null check on the failure path, nothing retained; pass null to detach.
The deepest cause in the chain — the original failure, whatever wrapped it since.
Toggles ignored-failure reporting at runtime, overriding the QUNITX_DEBUG default.
Converts a Failure (or any error) into plain JSON.
Whether value is an Error carrying one of the given Node code strings — ENOENT,
EADDRINUSE, EBUSY. With no codes it matches any error that has a string code at all
(which includes Node's ERR_* internal errors, e.g. ERR_MODULE_NOT_FOUND).
Splits outcomes into their successes and their failures, keeping both.
Calls fn(...args) and returns the value bare, classifying any throw into the
declared Failure classify builds — the boundary and the declaration fused into one
expression, producing the bare union directly. The sync sibling of Task#mapErr: like
that adapter edge it deliberately catches everything, because this IS the edge where a
foreign throw becomes a declared failure — chain the original under cause. When the
boundary should stay raw and the declaration should be a separate visible rethrow line,
use Result.try instead.
Calls fn(...args) and reflects the outcome into a Caught box — Result.try, shaped like
Promise.try. See the module doc for the flat-classification pattern this is half of.
Calls fn(...args) and reflects the outcome into a Caught box — Result.try, shaped like
Promise.try. See the module doc for the flat-classification pattern this is half of.
Returns the success value, or throws the failure.
Returns the success value, or fallback if the outcome is a failure.
Minimal shape of a Node system error, declared locally so this module stays runtime-free.
-
code: string
The symbolic error code, e.g.
ENOENT. What isErrno matches on. -
errno: number
The negated platform errno number.
-
path: string
The path the failing call was operating on, when the syscall takes one.
-
syscall: string
The syscall that failed, e.g.
open.
Per-kind options accepted by define().
-
trace: (data: Data) => TraceAttributes
Allowlist mapper from the typed payload to span/log attributes, consumed by attributes. Deliberately not a redaction filter: only what the mapper returns is ever exposed, so sensitive fields are private by omission, not by scrubbing.
A callable failure constructor produced by define(), carrying its own type guard.
-
code: Code
The literal code this factory produces. Useful as a
switchcase and in registries. -
is(value: unknown): value is Failure<Code, Data>
Cross-realm type guard narrowing to this exact failure — the flat rethrow line's guard after a
Result.try.
Options accepted by the Failure constructor and by every generated factory.
-
cause: unknown
The error this failure was derived from. Preserved verbatim and walked by
causes(). -
stackAnchor: (...args: never[]) => unknown
The function to truncate the stack at, so the top frame is the code that reported the failure rather than the plumbing that built it. Defaults to the constructor.
-
stackless: boolean
Skips stack capture. Only worth setting for failures produced in a hot loop and consumed immediately — the capture, not the allocation, is what a Failure costs. See the performance section of the docs before reaching for it.
The wire form of a Failure — what toJSON emits and fromJSON accepts.
-
cause: SerializedFailure
| { name: string; message: string; stack?: string; }The serialized cause chain: a nested Failure, or a plain error's identifying fields.
-
code: string
The discriminant. Survives the wire, unlike a prototype.
-
data: unknown
The structured payload, JSON round-tripped by
toJSONso it cannot fail later. -
failure: true
Wire marker.
Symbol.forkeys survive neitherJSON.stringifynorstructuredClone, so the serialized form carries an explicit field in the brand's place. -
message: string
The human-readable sentence, already interpolated from
data. -
stack: string
The producing process's stack. Frameless — the header line alone — when the failure was built
{ stackless: true }; the field itself is absent only ifstackwas never set.
Structured, discriminable errors — the E half of Result<T, E>.
What the boundary hands back: the value, or whatever was caught — unknown, honestly,
because a catch binding is exactly as untrustworthy.
The caught variant. value is present-but-undefined for shape stability.
Any Failure at all — the type to reach for when a signature accepts failures it does not
enumerate, e.g. Result<T, Failure.Any> at a boundary that only logs.
The callback shape onIgnored installs: every ignored failure arrives with the label its call site declared.
The callback shape onObserved installs: every declared failure a consumer classified arrives right as it is handed to application code.
The Failure type a factory produces: Failure.Of<typeof FileMissing>.
The attribute primitives tracing systems accept (OpenTelemetry's span-attribute values) —
what a trace mapper returns and attributes yields.
The success variant of a caught outcome. error is present-but-undefined for shape stability.
The outcome of rescue(): the bare T | F union, promise-wrapped when fn was async.
A leaking any collapses to unknown so it cannot pose as an inspected type.
The success value or a declared failure — a bare union, discriminated by the Failure
brand.
Name of the diagnostics_channel that ignore publishes to on Node and Deno —
subscribe with the platform API, no qunitx registry involved. Messages are
{ context: string, error: unknown }. Browsers have no channel; use onIgnored.
Name of the diagnostics_channel that observed publishes to on Node and Deno.
Messages are { error: Failure.Any }. This is what a tracing adapter subscribes to —
e.g. OpenTelemetry, in its entirety:
The failure from() produces for a throwable that is not already a Failure.
Collects an array of outcomes into an array of values, short-circuiting on the first
failure — the Result-shaped analogue of Promise.all.
Returns the success value, or throws new Error(message, { cause: failure }).
Splits outcomes into their successes and their failures, keeping both.
Returns the success value, or throws the failure.
Returns the success value, or fallback if the outcome is a failure.
The success value or a declared failure — a bare union, discriminated by the Failure
brand.
Whether value is an Error carrying one of the given Node code strings — ENOENT,
EADDRINUSE, EBUSY. With no codes it matches any error that has a string code at all
(which includes Node's ERR_* internal errors, e.g. ERR_MODULE_NOT_FOUND).
Calls fn(...args) and returns the value bare, classifying any throw into the
declared Failure classify builds — the boundary and the declaration fused into one
expression, producing the bare union directly. The sync sibling of Task#mapErr: like
that adapter edge it deliberately catches everything, because this IS the edge where a
foreign throw becomes a declared failure — chain the original under cause. When the
boundary should stay raw and the declaration should be a separate visible rethrow line,
use Result.try instead.
Calls fn(...args) and reflects the outcome into a Caught box — Result.try, shaped like
Promise.try. See the module doc for the flat-classification pattern this is half of.
Minimal shape of a Node system error, declared locally so this module stays runtime-free.
-
code: string
The symbolic error code, e.g.
ENOENT. What isErrno matches on. -
errno: number
The negated platform errno number.
-
path: string
The path the failing call was operating on, when the syscall takes one.
-
syscall: string
The syscall that failed, e.g.
open.
What the boundary hands back: the value, or whatever was caught — unknown, honestly,
because a catch binding is exactly as untrustworthy.
The caught variant. value is present-but-undefined for shape stability.
The success variant of a caught outcome. error is present-but-undefined for shape stability.
The outcome of rescue(): the bare T | F union, promise-wrapped when fn was async.
A leaking any collapses to unknown so it cannot pose as an inspected type.
Builds the ?filter=… query that carries the test filter (-t/--filter/-m/--module)
into the page.
Human-readable description of the active filters, for the "nothing matched" message.
True when this run selects a subset of the tests inside the files it loads.
Resolves file#34 line targets into exact QUnit selections.
Resolves line targets against an ALREADY-parsed scan. Split out so --search, which has scanned
every file for its listing, can resolve line targets without reading and esbuild-transforming
those files a second time.
Result of resolving a file's line targets into selectors, plus any diagnostics to surface.
-
selectors: QUnitSelector[] | null
Selectors to apply, or null to run the whole file unfiltered.
-
warnings: string[]
#-prefixed lines to print — always explains why a target did not narrow as asked.
One thing a file#34 target selects. test omitted means "this module and everything nested
under it" — used for module targets, and as the fallback when a test's name is computed and so
cannot be matched exactly.
-
module: string
Full module path, ' > '-joined. '' for a top-level test.
-
test: string
Exact test name; omitted to select the whole module and its nested children.
Finds every test(...) / module(...) declaration in a test file, with the source line range
each one spans — enough to answer "which test is at line 34?".
Every declaration found in a file, plus whether it uses only().
-
declarations: TestDeclaration[]
All test/module declarations, sorted by start line, with
parentlinks resolved. -
hasOnly: boolean
True when the file calls
only(), which makes QUnit ignore every other test in the run.
A test(...) or module(...) call found in a test file, in 1-based source lines.
-
endLine: number
Line of the call's closing paren — so [startLine, endLine] spans the whole body.
-
kind: "test" | "module"
Whether this is a
test(...)or amodule(...)call. -
name: string | null
The literal first argument, or null when it is computed (
test(\case ${i}`)`). -
parent: number | null
Index into
declarationsof the innermost enclosing module, or null at the top level. -
startLine: number
Line of the callee.
The string a filter is matched against: "Module: test name", with nested modules already
joined by " > ". A top-level test has an empty module name, giving ": test name" — which is
QUnit's own behaviour, not a quirk of this port.
True when filter selects fullName, using QUnit's semantics:
Binds an HTTPServer to config.port (default 1234).
Launches a browser for the given config.browser type.
For chromium: connects via CDP to the pre-launched Chrome (fast path) or falls
back to chromium.launch() if pre-launch failed.
For firefox/webkit: uses playwright's standard launch (requires npx playwright install [browser]).
Launches a Playwright browser (or reuses an existing one), starts the web server, and returns the page/server/browser connection object.
The three fields launch actually reads. Narrower than Config on purpose: qunitx run
has a config of its own with no test files in it, and asking it to fake thirty unrelated fields
to borrow the CDP pre-launch fast path would be a cast pretending to be a type.
-
browser: "chromium" | "firefox" | "webkit"
Engine to launch. Defaults to chromium when absent.
-
open: boolean | string
--open:trueasks for a visible window (honoured together withwatch). -
watch: boolean
--watch: keeps firefox/webkit headed whenopenis also set.
Builds the merged qunitx config from package.json settings and either an argv or an explicit
ConfigOptions. package.json#qunitx.plugins entries are dynamic-imported into esbuild
plugin objects.
Resolved settings handed to setup in place of an argv, by the JS API and by anyone else assembling a run programmatically. Every CLI flag has a field here — they are the same settings, arrived at by a different route — plus the two things argv cannot express: a working directory, and esbuild plugins as live objects rather than module specifiers.
-
console: Console
Where reporter text and
#diagnostics go. Defaults to the process streams; passsilentConsolefor a run that prints nothing at all. Named apart fromoutput— the build directory — because they are unrelated and both spellings are load-bearing. -
cwd: string
Directory the project root and relative inputs resolve against. Defaults to
process.cwd(). -
esbuildPlugins: EsbuildPlugin[]
Live esbuild plugin objects, appended after any resolved from
package.json#qunitx.plugins. -
reporters: ReporterInstance[]
Reporter instances for this run, replacing the one
reporter/junitwould have selected. The way a caller observes a run as data rather than as text. -
signal: AbortSignal
Cancels the run when it fires. Placed on
state.signal; setup never subscribes to it.
| ProjectRootNotFoundFailure
| FSTree.InputUnreadableFailure
| Result.Failure.Of<InvalidPlugins | PluginLoadFailed>
Every way config assembly can fail with something the user can act on.
package.json#qunitx.plugins was present but not an array.
A plugin specifier could not be resolved or imported.
Default qunitx config values: build output directory, test timeout (ms), fail-fast flag, HTTP server port, and tracked file extensions.
Routes a file-system event to fsTree mutation and optional rebuild trigger.
unlinkDir bypasses the extension filter so deleted directories always clean up fsTree.
When a build is already in progress, queues the event as a pending trigger (last-write-wins).
Mutates fsTree in place based on a file-system event.
Reads a file, re-reading until two reads spaced STABILITY_GAP_MS apart return byte-identical
content — so a file caught mid-write (Windows truncate→flush; see STABILITY_GAP_MS) is hashed
only once its bytes have settled. Bounded by MAX_STABILITY_ATTEMPTS; returns the latest content
if it never stabilizes. read is injectable for tests; production reads from disk. Read errors
propagate so the caller's catch can treat a vanished file as a removal.
Scans watchPath recursively and fires add / change / unlink events for any delta
between the directory contents and config.fsTree. Used as a 1 s safety-net poll on macOS
where FSEvents can drop events under load — additions and removals are recovered from the
directory listing, and modifications are recovered by re-stat'ing every tracked file and
firing change whenever its mtime is newer than config.state.watch.lastBuildEndMs (the moment the
last build saw the file). The seed for that baseline is set in setup.
Starts fs.watch watchers for each lookup path and calls onEventFunc on JS/TS file changes,
debounced via a per-file timestamp. Also watches each path's parent directory to detect when a
watched directory is renamed or deleted (since fs.watch tracks by inode, not path).
Uses config.fsTree to distinguish unlink (tracked file) from unlinkDir (directory) on deletion.
Maps a lookup path to a path fs.watch can actually watch. A real file or directory is returned
as-is; a glob is walked up to the deepest ancestor directory that exists — its base dir — which
fs.watch can watch recursively (test/x/!(plugin).ts collapses to test/x).
The fs calls rescanDirectoryForDelta makes — injectable so a platform-specific
readdir/stat disagreement can be reproduced deterministically. Production uses the real fs.
-
readdir: readdir
Lists the directory tree. Its dirent types are unreliable on Windows — see
isMissing. -
stat: stat
Resolves a path (follows symlinks). Used to drop entries that are genuinely gone.
Resolves an array of file paths, directories, or glob patterns into a flat { absolutePath: null } map.
The one failure build declares.
One of the configured test inputs could not be globbed, stat'd or walked.
Returns a new fsTree containing only the test files affected by changes
since ref, per the cached esbuild metafile's reverse-dependency graph.
Binds watch-mode keyboard shortcuts to the session's verbs: qq aborts, qa runs all, qf
re-runs the last failures, ql repeats the last run.
esbuild plugin that lets test files import { module, test } from 'qunitx' even when the
consumer project has NOT installed the separate qunitx runtime package — the case for
JSR/standalone-binary/npx users, who have no node_modules at all.
Invalidates a group's compiled bundles so the next run rebuilds them from disk.
Fresh run state for a single qunitx invocation. Built once per run in Config.setup().
Fresh per-group state. One per concurrent group; the group spread in runConcurrentMode
replaces state.group with this so groups never share the slots inside it.
Asks every live server to tell its pages to drop the rest of the QUnit queue, and records that this run was cut short.
Clears the run accumulators in place for a re-run.
The daemon's reusable Page slot, or null when reuse does not apply.
Deduplicates a list of file, folder, and glob inputs so that more-specific paths covered by broader ones are removed.
Generates a self-contained HTML error page for a build failure, styled to match the QUnit
HTML reporter (same element IDs, colors, and layout as qunit.css / qunitjs.com).
Includes a WebSocket reconnect script that reloads the page on 'refresh' (next successful
build). Uses location.port so no port needs to be baked in at generation time; the script
is a no-op when the page is opened as a static file (location.port is empty).
Generates a self-contained HTML warning page shown when a test run completes with 0 registered QUnit tests. Styled to match the QUnit HTML reporter, with an amber banner instead of red. Includes the same WebSocket reconnect script as buildErrorHTML so the page reloads on the next successful build.
Registers HTML and JS bundle routes for one concurrent group on a shared HTTPServer.
Routes: GET /group-${groupId}/ and GET /group-${groupId}/tests.js.
Creates and returns an HTTPServer with routes for the test HTML, filtered test page, and static assets, plus a WebSocket handler that streams TAP events.
Attaches the shared WebSocket event dispatcher to server.wss.
Routes each socket's messages to the correct group's Config using the groupId
baked into the browser-side wsOpen message by testRuntimeToInject.
The same runtime as bare JavaScript, for a page that injects it rather than serving it.
The <script> that turns a page into a reporting test page: the QUnit preconfig, the WebSocket
client, and the QUnit hooks that forward every event to this process.
Copies static HTML files and referenced assets from the project into the configured output directory.
A structured, discriminable error.
-
code: Code
The discriminant. Narrow on this, never on
instanceof. -
data: Data
Structured payload supplied by the throw site.
-
toJSON(): SerializedFailure
Serializes to plain JSON so
console.log(JSON.stringify(failure))is not{}.
Span/log attributes a failure declares for tracing: failure.code plus whatever its
factory's trace mapper (see define) explicitly allowlisted from data. A
failure whose factory declared no mapper yields the code alone — unmapped payload
fields never leave the process, which is what makes redaction (passwords, tokens) the
default rather than a discipline.
Flattens an error's cause chain into an array, error first and the root cause last.
define() overload for failures that carry no payload.
define() overload for failures whose message is derived from their payload.
Renders an error and its whole cause chain as indented, human-readable lines.
Coerces any caught value into a Failure, leaving existing Failures untouched.
Revives a SerializedFailure into a real Failure, reconstructing the cause chain.
Narrows a Failure to one of several codes — the multi-code sibling of Factory.is.
Builds a .catch() handler for a failure that genuinely has no consequence — but says so
under QUNITX_DEBUG instead of vanishing. This is the raw handler; the ergonomic spelling
at call sites is Task(promise).ignore(context), which wraps exactly this function.
Whether value is a Failure — from this realm or any other.
Whether value is a Failure — from this realm or any other.
True for a factory made by define. A factory carries the code it produces and its
own is guard; a plain error-mapper carries neither, so an API can accept both in one
position and tell them apart exactly, without guessing from arity.
Whether value is a Failure — from this realm or any other.
Whether value is a Failure — from this realm or any other.
Reports a declared failure to the observation seam — onObserved plus the
OBSERVED_CHANNEL_NAME channel. Task's consuming methods call this at their
classification points; call it yourself only for a synchronous Result flow that never
crossed a Task, so a tracing adapter sees those failures too.
Installs a process-wide observer for every ignored failure — the interception seam for
"list everything the program decided not to handle". Costs one null check on the failure
path only (nothing on success, nothing per Task), and retains nothing itself: whether the
suppressed failures accumulate, sample, or stream somewhere is the observer's decision.
Pass null to detach.
Installs a process-wide observer for every handled declared failure — the portable
(browser-friendly) counterpart of subscribing to OBSERVED_CHANNEL_NAME. Single
slot, one null check on the failure path, nothing retained; pass null to detach.
The deepest cause in the chain — the original failure, whatever wrapped it since.
Toggles ignored-failure reporting at runtime, overriding the QUNITX_DEBUG default.
Converts a Failure (or any error) into plain JSON.
The producer half of StreamClass.channel: emit into it, consume stream out of it.
-
abort(reason: unknown): void
Rejects the consuming Task with
reason— the two-tier rule's bug tier. Idempotent. -
buffered: number
Elements buffered for a consumer that has not taken them yet.
-
close(): void
Ends the stream once the buffer drains. Idempotent.
-
closed: boolean
Whether the channel has been closed, aborted, or abandoned by its consumer.
-
dropped: number
How many elements the buffer has lost to overflow.
0unless a consumer fell behind. -
emit(value: T): boolean
Offers a value. Returns
falsewhen there is no room left — Node'swrite()convention: advisory for a producer that can slow down, ignorable for one that cannot. -
fail(error: E): boolean
Offers a declared failure as an element — the railway, not a rejection.
-
ready(): Promise<void>
Resolves once there is room to emit again — Web Streams'
writer.ready, and the promise form of Node's'drain'. -
stream: Stream<T, E>
The consuming half. One consumer only; a second pass throws.
How a Channel behaves when its consumer cannot keep up.
-
capacity: number
How many elements to buffer for a consumer that has not taken them yet. Default
10_000. -
onDemand: () => void
Called once, when a consumer first attaches. A producer that can defer starting should start here: it is the difference between a buffer that stays near empty and one that races ahead of a consumer that has not arrived.
-
onDiscard: () => voiddropped: T | E,buffered: number
Called with each element the buffer actually lost, and the depth after the loss. The only place overflow is observable — make it fatal from here by calling
failorabort. -
overflow: Overflow
What to do once
capacityis reached: drop from either end, or'fail'— end the stream with a ChannelOverflowFailure element instead of losing anything quietly. Default'dropOldest'.
Per-kind options accepted by define().
-
trace: (data: Data) => TraceAttributes
Allowlist mapper from the typed payload to span/log attributes, consumed by attributes. Deliberately not a redaction filter: only what the mapper returns is ever exposed, so sensitive fields are private by omission, not by scrubbing.
A callable failure constructor produced by define(), carrying its own type guard.
-
code: Code
The literal code this factory produces. Useful as a
switchcase and in registries. -
is(value: unknown): value is Failure<Code, Data>
Cross-realm type guard narrowing to this exact failure — the flat rethrow line's guard after a
Result.try.
Options accepted by the Failure constructor and by every generated factory.
-
cause: unknown
The error this failure was derived from. Preserved verbatim and walked by
causes(). -
stackAnchor: (...args: never[]) => unknown
The function to truncate the stack at, so the top frame is the code that reported the failure rather than the plumbing that built it. Defaults to the constructor.
-
stackless: boolean
Skips stack capture. Only worth setting for failures produced in a hot loop and consumed immediately — the capture, not the allocation, is what a Failure costs. See the performance section of the docs before reaching for it.
The wire form of a Failure — what toJSON emits and fromJSON accepts.
-
cause: SerializedFailure
| { name: string; message: string; stack?: string; }The serialized cause chain: a nested Failure, or a plain error's identifying fields.
-
code: string
The discriminant. Survives the wire, unlike a prototype.
-
data: unknown
The structured payload, JSON round-tripped by
toJSONso it cannot fail later. -
failure: true
Wire marker.
Symbol.forkeys survive neitherJSON.stringifynorstructuredClone, so the serialized form carries an explicit field in the brand's place. -
message: string
The human-readable sentence, already interpolated from
data. -
stack: string
The producing process's stack. Frameless — the header line alone — when the failure was built
{ stackless: true }; the field itself is absent only ifstackwas never set.
Structured, discriminable failures — the E elements of a Stream.
The failure element a 'fail' channel ends with.
Any Failure at all — the type to reach for when a signature accepts failures it does not
enumerate, e.g. Result<T, Failure.Any> at a boundary that only logs.
The callback shape onIgnored installs: every ignored failure arrives with the label its call site declared.
The callback shape onObserved installs: every declared failure a consumer classified arrives right as it is handed to application code.
The Failure type a factory produces: Failure.Of<typeof FileMissing>.
The attribute primitives tracing systems accept (OpenTelemetry's span-attribute values) —
what a trace mapper returns and attributes yields.
What a full channel does — the two GenStage :buffer_keep choices, named for the element that
goes rather than the one that stays, plus the option of refusing to lose anything silently.
Anything a Stream can be built from or flattened into: sync or async iterables (a web ReadableStream is async-iterable on every modern runtime).
A channel with overflow: 'fail' filled up: the consumer fell far enough behind that the
buffer could not hold the difference, and dropping was not on the table.
Name of the diagnostics_channel that ignore publishes to on Node and Deno —
subscribe with the platform API, no qunitx registry involved. Messages are
{ context: string, error: unknown }. Browsers have no channel; use onIgnored.
Name of the diagnostics_channel that observed publishes to on Node and Deno.
Messages are { error: Failure.Any }. This is what a tracing adapter subscribes to —
e.g. OpenTelemetry, in its entirety:
The failure from() produces for a throwable that is not already a Failure.
The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only
entry points — there is no public constructor and no call form.
The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only
entry points — there is no public constructor and no call form.
Call-or-construct, like Boolean/Date: Task(recipe) and new Task(recipe) build the
same lazy Task. ES classes reject the call form, so the export is a Proxy whose apply
forwards to construction — statics, instanceof, and the prototype all pass through.
Call-or-construct, like Boolean/Date: Task(recipe) and new Task(recipe) build the
same lazy Task. ES classes reject the call form, so the export is a Proxy whose apply
forwards to construction — statics, instanceof, and the prototype all pass through.
The producer half of StreamClass.channel: emit into it, consume stream out of it.
-
abort(reason: unknown): void
Rejects the consuming Task with
reason— the two-tier rule's bug tier. Idempotent. -
buffered: number
Elements buffered for a consumer that has not taken them yet.
-
close(): void
Ends the stream once the buffer drains. Idempotent.
-
closed: boolean
Whether the channel has been closed, aborted, or abandoned by its consumer.
-
dropped: number
How many elements the buffer has lost to overflow.
0unless a consumer fell behind. -
emit(value: T): boolean
Offers a value. Returns
falsewhen there is no room left — Node'swrite()convention: advisory for a producer that can slow down, ignorable for one that cannot. -
fail(error: E): boolean
Offers a declared failure as an element — the railway, not a rejection.
-
ready(): Promise<void>
Resolves once there is room to emit again — Web Streams'
writer.ready, and the promise form of Node's'drain'. -
stream: Stream<T, E>
The consuming half. One consumer only; a second pass throws.
How a Channel behaves when its consumer cannot keep up.
-
capacity: number
How many elements to buffer for a consumer that has not taken them yet. Default
10_000. -
onDemand: () => void
Called once, when a consumer first attaches. A producer that can defer starting should start here: it is the difference between a buffer that stays near empty and one that races ahead of a consumer that has not arrived.
-
onDiscard: () => voiddropped: T | E,buffered: number
Called with each element the buffer actually lost, and the depth after the loss. The only place overflow is observable — make it fatal from here by calling
failorabort. -
overflow: Overflow
What to do once
capacityis reached: drop from either end, or'fail'— end the stream with a ChannelOverflowFailure element instead of losing anything quietly. Default'dropOldest'.
The failure element a 'fail' channel ends with.
What a full channel does — the two GenStage :buffer_keep choices, named for the element that
goes rather than the one that stays, plus the option of refusing to lose anything silently.
Anything a Stream can be built from or flattened into: sync or async iterables (a web ReadableStream is async-iterable on every modern runtime).
A channel with overflow: 'fail' filled up: the consumer fell far enough behind that the
buffer could not hold the difference, and dropping was not on the table.
The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only
entry points — there is no public constructor and no call form.
Prints the TAP plan line and test-run summary (total, pass, skip, fail, duration).
Formats and prints a single QUnit testEnd event as a TAP ok/not ok line with an
optional YAML failure block. A pure formatter: testNumber is the TAP sequence number
(the caller owns counting) and failures are pre-resolved by failedAssertions.
Serializes the fixed TAP assertion object to a YAML string. Uses a template literal (no Object.entries overhead) for the known top-level keys.
Prints the TAP plan line and test-run summary (total, pass, skip, fail, duration).
Formats and prints a single QUnit testEnd event as a TAP ok/not ok line with an
optional YAML failure block. A pure formatter: testNumber is the TAP sequence number
(the caller owns counting) and failures are pre-resolved by failedAssertions.
Serializes the fixed TAP assertion object to a YAML string. Uses a template literal (no Object.entries overhead) for the known top-level keys.
A structured, discriminable error.
-
code: Code
The discriminant. Narrow on this, never on
instanceof. -
data: Data
Structured payload supplied by the throw site.
-
toJSON(): SerializedFailure
Serializes to plain JSON so
console.log(JSON.stringify(failure))is not{}.
Span/log attributes a failure declares for tracing: failure.code plus whatever its
factory's trace mapper (see define) explicitly allowlisted from data. A
failure whose factory declared no mapper yields the code alone — unmapped payload
fields never leave the process, which is what makes redaction (passwords, tokens) the
default rather than a discipline.
Flattens an error's cause chain into an array, error first and the root cause last.
define() overload for failures that carry no payload.
define() overload for failures whose message is derived from their payload.
Renders an error and its whole cause chain as indented, human-readable lines.
Coerces any caught value into a Failure, leaving existing Failures untouched.
Revives a SerializedFailure into a real Failure, reconstructing the cause chain.
Narrows a Failure to one of several codes — the multi-code sibling of Factory.is.
Builds a .catch() handler for a failure that genuinely has no consequence — but says so
under QUNITX_DEBUG instead of vanishing. This is the raw handler; the ergonomic spelling
at call sites is Task(promise).ignore(context), which wraps exactly this function.
Whether value is a Failure — from this realm or any other.
Whether value is a Failure — from this realm or any other.
True for a factory made by define. A factory carries the code it produces and its
own is guard; a plain error-mapper carries neither, so an API can accept both in one
position and tell them apart exactly, without guessing from arity.
Whether value is a Failure — from this realm or any other.
Whether value is a Failure — from this realm or any other.
Reports a declared failure to the observation seam — onObserved plus the
OBSERVED_CHANNEL_NAME channel. Task's consuming methods call this at their
classification points; call it yourself only for a synchronous Result flow that never
crossed a Task, so a tracing adapter sees those failures too.
Installs a process-wide observer for every ignored failure — the interception seam for
"list everything the program decided not to handle". Costs one null check on the failure
path only (nothing on success, nothing per Task), and retains nothing itself: whether the
suppressed failures accumulate, sample, or stream somewhere is the observer's decision.
Pass null to detach.
Installs a process-wide observer for every handled declared failure — the portable
(browser-friendly) counterpart of subscribing to OBSERVED_CHANNEL_NAME. Single
slot, one null check on the failure path, nothing retained; pass null to detach.
The deepest cause in the chain — the original failure, whatever wrapped it since.
Toggles ignored-failure reporting at runtime, overriding the QUNITX_DEBUG default.
Converts a Failure (or any error) into plain JSON.
Splits outcomes into their successes and their failures, keeping both.
Returns the success value, or throws the failure.
Per-kind options accepted by define().
-
trace: (data: Data) => TraceAttributes
Allowlist mapper from the typed payload to span/log attributes, consumed by attributes. Deliberately not a redaction filter: only what the mapper returns is ever exposed, so sensitive fields are private by omission, not by scrubbing.
A callable failure constructor produced by define(), carrying its own type guard.
-
code: Code
The literal code this factory produces. Useful as a
switchcase and in registries. -
is(value: unknown): value is Failure<Code, Data>
Cross-realm type guard narrowing to this exact failure — the flat rethrow line's guard after a
Result.try.
Options accepted by the Failure constructor and by every generated factory.
-
cause: unknown
The error this failure was derived from. Preserved verbatim and walked by
causes(). -
stackAnchor: (...args: never[]) => unknown
The function to truncate the stack at, so the top frame is the code that reported the failure rather than the plumbing that built it. Defaults to the constructor.
-
stackless: boolean
Skips stack capture. Only worth setting for failures produced in a hot loop and consumed immediately — the capture, not the allocation, is what a Failure costs. See the performance section of the docs before reaching for it.
The wire form of a Failure — what toJSON emits and fromJSON accepts.
-
cause: SerializedFailure
| { name: string; message: string; stack?: string; }The serialized cause chain: a nested Failure, or a plain error's identifying fields.
-
code: string
The discriminant. Survives the wire, unlike a prototype.
-
data: unknown
The structured payload, JSON round-tripped by
toJSONso it cannot fail later. -
failure: true
Wire marker.
Symbol.forkeys survive neitherJSON.stringifynorstructuredClone, so the serialized form carries an explicit field in the brand's place. -
message: string
The human-readable sentence, already interpolated from
data. -
stack: string
The producing process's stack. Frameless — the header line alone — when the failure was built
{ stackless: true }; the field itself is absent only ifstackwas never set.
Structured, discriminable failures — the rejection reason of a Task.
Any Failure at all — the type to reach for when a signature accepts failures it does not
enumerate, e.g. Result<T, Failure.Any> at a boundary that only logs.
The callback shape onIgnored installs: every ignored failure arrives with the label its call site declared.
The callback shape onObserved installs: every declared failure a consumer classified arrives right as it is handed to application code.
The Failure type a factory produces: Failure.Of<typeof FileMissing>.
The attribute primitives tracing systems accept (OpenTelemetry's span-attribute values) —
what a trace mapper returns and attributes yields.
The success value or a declared failure — a bare union, discriminated by the Failure
brand.
& ((
A TaskClass#retry attempt nothing will await again — the reason its signal fires.
The deadline in TaskClass#await elapsed before the work settled.
Name of the diagnostics_channel that ignore publishes to on Node and Deno —
subscribe with the platform API, no qunitx registry involved. Messages are
{ context: string, error: unknown }. Browsers have no channel; use onIgnored.
Name of the diagnostics_channel that observed publishes to on Node and Deno.
Messages are { error: Failure.Any }. This is what a tracing adapter subscribes to —
e.g. OpenTelemetry, in its entirety:
The failure from() produces for a throwable that is not already a Failure.
& ((
TaskClass#shutdown settled the Task because the caller asked it to stop.
Call-or-construct, like Boolean/Date: Task(recipe) and new Task(recipe) build the
same lazy Task. ES classes reject the call form, so the export is a Proxy whose apply
forwards to construction — statics, instanceof, and the prototype all pass through.
Call-or-construct, like Boolean/Date: Task(recipe) and new Task(recipe) build the
same lazy Task. ES classes reject the call form, so the export is a Proxy whose apply
forwards to construction — statics, instanceof, and the prototype all pass through.
The full option bag for Task#retry; pass a RetryDelay directly when the delay is all you need.
-
delayMs: RetryDelay
Wait between attempts. Omitted or
0retries immediately, as it always has. -
timeoutMs: number
Deadline for each individual attempt. The attempt is abandoned when it fires — its signal goes off so cancellation-aware work stops — and counts as a failure like any other.
-
when: () => booleanerror: unknown,attempt: number
Which failures are worth another attempt. Returning
falserethrows immediately, spending no further attempts and no delay.
The new Promise shape, made lazy: settle imperatively through resolve/reject, with the
Task's AbortSignal third.
The zero-parameter shape: return the value (or a promise of it) and that settles the Task.
Declared with no parameters both because that is what it receives and because it is what
lets TypeScript tell a recipe from an Executor — a lambda naming even one parameter
can then only be the executor, so resolve gets contextually typed instead of any.
A recipe that needs the AbortSignal takes the executor shape.
Milliseconds to wait before the next attempt, or a function of the attempt just finished —
the shape lib/job converged on for Oban-style backoff, with a constant as its degenerate
case. (n) => Math.min(100 * 2 ** n, 30_000) is exponential; () => 100 is fixed.
& ((
A TaskClass#retry attempt nothing will await again — the reason its signal fires.
The deadline in TaskClass#await elapsed before the work settled.
& ((
TaskClass#shutdown settled the Task because the caller asked it to stop.
Call-or-construct, like Boolean/Date: Task(recipe) and new Task(recipe) build the
same lazy Task. ES classes reject the call form, so the export is a Proxy whose apply
forwards to construction — statics, instanceof, and the prototype all pass through.
An esbuild failure, captured for display on the run's error page.
-
formatted: string
Pre-formatted esbuild message block.
-
type: string
Short error class used as the page heading (e.g.
'Build Error').
One group's esbuild output and in-flight build bookkeeping, kept warm between watch-mode
rebuilds. Lives at state.group.build, so it shares the group's lifetime rather than being
threaded alongside the config as a second, independently-passable bag.
-
activeRebuild: Promise<void> | null
Set when a parallel rebuild is in-flight during a watch-mode rerun. The
/tests.jsroute awaits this before serving, so Chrome can navigate concurrently while esbuild finishes. Cleared byrunafter the build settles. -
allTestCode: Buffer | string | null
Full test bundle source, or
nullbefore the first build completes. -
fallbackPage: FallbackPage | null
Replaces the normal test page for this run, or
nullwhen the run renders tests as usual. The web server's/route serves this page and the Playwright page is navigated there. Cleared at the start of every new build attempt. -
filteredTestCode: Buffer | string
Bundle filtered to files that failed on the previous run (used by re-run mode).
-
htmlPathsToRunTests: string[]
Absolute paths of every HTML file that will be opened in the browser to run tests.
-
lastBuildErrored: boolean
trueif the most recent build ended in an esbuild error. Keepsstate.watch.lastBuildEndMspinned to the last good build so a fix arriving after the error is never suppressed. Written by every run, read only in watch mode. -
preBuildPromise: Promise<void> | null
In-flight build promise started by
run.tsbefore Chrome setup completes (initial run) or beforerunis called (reruns), so esbuild races navigation. Consumed and cleared by the firstrun()call.
Handles to a pre-launched Chrome, available synchronously the moment it is spawned —
before the CDP endpoint is known. Enough to reap the process and its temp dir, which is all
the process.on('exit') safety net and shutdownPrelaunch() need.
-
proc: ChildProcess
The spawned Chrome child process.
-
shutdown: () => Promise<void>
Kills Chrome and awaits async temp-dir cleanup. Safe to call before CDP is ready, and idempotent with Chrome's own dead-on-arrival cleanup. Call before
process.exit().
Full resolved qunitx configuration for a single run, merging package.json settings,
CLI flags, and runtime state. Most fields are read-only after Config.setup() resolves;
underscore-prefixed fields are mutable runtime slots populated during the run lifecycle.
-
browser: "chromium" | "firefox" | "webkit"
Browser engine used for the test run (
'chromium'|'firefox'|'webkit'). -
cwd: string
Working directory this run resolves against: relative inputs, bare-specifier resolution inside the test bundle, and
--before/--afterhook paths.process.cwd()for the CLI; the JS API'scwdoption otherwise. Distinct from projectRoot, which is wherever the nearestpackage.jsonsits — running from a subdirectory keeps that subdirectory'snode_moduleson the resolution chain, exactly as Node itself would. -
extensions: string[]
File extensions treated as test files (default:
['js', 'ts']). -
failFast: boolean
When
true, abort the run after the first test failure (default:false). -
fsTree: FSTree
Current file-system snapshot, diffed in watch mode to detect added / removed files.
-
htmlPaths: string[]
Absolute paths to HTML fixture files that wrap the compiled test bundle.
-
output: string
Directory where the compiled test bundle and output HTML are written (default:
'tmp'). -
plugins: EsbuildPlugin[]
Custom esbuild plugins applied during the test bundle build. Loaded from
qunitx.config.{ts,js,mjs}in the project root. Common use cases: SFC formats like.vue(esbuild-plugin-vue-next), Svelte (esbuild-svelte), or any project-specific resolvers/loaders. -
port: number
TCP port the local test server listens on (default:
1234, auto-increments on conflict). -
projectRoot: string
Absolute path to the project root (directory containing
package.json). -
state: RunState
Mutable state for this run; see RunState for the sharing rules.
-
testFileLookupPaths: string[]
Paths searched when globbing for test files.
-
timeout: number
Maximum milliseconds to wait for the full test suite before timing out (default:
20000). -
webServer: HTTPServer
The run's HTTP server, exposed purely as
--before/--afterhook surface — qunitx itself never reads it back. Hooks use it to register extra routes (mock APIs) before tests start.
Live handles for the three resources allocated at the start of a test run. Passed through the run pipeline and closed together on shutdown.
-
browser: Browser
The Playwright browser instance.
-
page: Page
The Playwright page (tab) navigated to the test URL.
-
server: HTTPServer
The HTTP + WebSocket server that serves the test bundle and streams TAP events.
Running totals of test outcomes for a single test run. Mutated in place as TAP events arrive from the browser.
-
assertionsFailed: number
Number of test cases that threw an unexpected error outside of assertions.
-
failed: number
Number of test cases that had at least one failing assertion.
-
passed: number
Number of test cases where every assertion passed.
-
skipped: number
Number of test cases explicitly marked as skipped (not run).
-
todo: number
Number of test cases marked as todo (expected to fail, work in progress).
-
total: number
Total number of test cases registered.
The daemon's persistent, cross-run handles, lent to a single run via RunState.daemon.
-
browser: Browser
The daemon's Browser.
run()reuses it instead of launching, and does not close it. -
esbuildCache: EsbuildCache
Persistent incremental-context slot, keeping the module graph warm across daemon runs.
-
pageSlot: { page: Page | null; }
Persistent Page slot, reused across runs to save a
newPage()(~70-130ms). Read throughRunState.reusablePageSlot(), never directly — reuse is only valid for single-group runs.
A ChromeHandle plus the CDP endpoint, resolved once Chrome is listening.
-
cdpEndpoint: string
The
ws://URL exposed by Chrome's CDP remote debugging endpoint.
A slot holding esbuild's incremental build context plus the key it was built for.
Two lifetimes share this shape: the per-process one on BuildState (watch mode)
and the daemon's persistent one, which survives across runs. buildIncrementally takes
either — it disposes and recreates the context whenever the key changes.
-
context: BuildContext | null
Live esbuild incremental context, or
null/absent before the first build. -
contextKey: string
Cache key for
context:allTestFilePaths.join('\0'). Invalidated when files change.
Per-source-file line coverage, accumulated across every executed bundle. Keyed by absolute source path. Lines are 1-based, matching editor/lcov conventions.
-
coverable: Set<number>
1-based line numbers that the source map attributes to executable bundle positions.
-
covered: Map<number, number>
1-based line number → highest V8 hit count observed for that line.
-
sourceContent: string | null
Verbatim original source text (from the map's
sourcesContent), for the HTML report.
RunState scoped to a single concurrent group — one fresh object per group of a run.
-
build: BuildState
This group's bundle output and build bookkeeping.
-
groupMode: boolean
truewhile running as one of several concurrent groups. -
index: number
Index within the run's group array;
0for watch and single-group runs. -
lastQUnitResult: QUnitResult | null
QUNIT_RESULT delivered via the WS 'done' message; avoids a page.evaluate() CDP round-trip.
-
lastRanFiles: string[] | null
Test files this group ran on the last run. Failure attribution falls back to this when a failing assertion's stack can't be resolved to one file — scoped per group so an unattributable failure blames only the files that group ran, not the whole invocation.
-
pendingConsoleHandlers: Set<Promise<void>> | null
In-flight console handler promises; awaited before browser/page close so Firefox BiDi round-trips complete.
-
phase: "bundling" | "connecting" | "loading" | "running" | "done"
Current lifecycle phase of this group's run.
-
selectors: QUnitSelector[] | undefined
Exact test selections for this group, derived from
lineTargets. Applied in the browser viaQUnit.config.testFilter, which QUnit ANDs afterfilter/module. Per-group: each line-targeted file runs as its own group so untargeted files stay unfiltered. -
signals: RunSignals
Callbacks the run pipeline waits on, resolved as the browser reaches each milestone.
-
sourceMapDecoder: SourceMapDecoder | null
Decoded inline source map for this group's bundle; resolves stack frames to original sources.
-
testEndCounts: Map<string, number>
Tracks
testEndarrivals per test fullName in this group's run. Reset in lockstep with the run counter — explicitly NOT on every WS 'connection' event, which was the bug that broke no-html-test in CI run 26042614416. -
wsConnectionCount: number
Diagnostic-only: how many distinct WS connections this group's wss handler has accepted. Reset per
WebServer.setupcall. > 1 means the browser opened multiple WebSocket connections within one run — the prime suspect for the 2× test-execution flake (WS retry path in the injected runtime).
The run's resolved HTML fixtures and the assets they reference. Populated once by
buildCachedContent and not written again, so every concurrent group can share one copy.
-
assets: Set<string>
Asset paths (scripts, stylesheets) discovered inside the user's HTML fixture.
-
dynamicContentHTMLs: Record<string, string>
HTML pages whose bundle content is injected at request time, keyed by server-relative path.
-
mainHTML: { filePath: string | null; html: string | null; }
The primary HTML page: its path on disk and its resolved content.
-
staticHTMLs: Record<string, string>
Static HTML pages served verbatim, keyed by their server-relative path.
One collected JUnit <testcase> — accumulated per testEnd and serialized into
junit.xml at run end when --reporter=junit is active.
-
classname: string
Suite name: the QUnit module path (fullName minus the test name).
-
failureDetail: string
Concatenated failing-assertion messages + resolved stacks (failed cases only).
-
failureMessage: string
First failing assertion's message (failed cases only).
-
name: string
The test-case name (the last element of QUnit's fullName).
-
status: "passed" | "failed" | "skipped" | "todo"
Outcome of the test case.
-
time: number
Test runtime in seconds (QUnit reports ms; converted on record).
The run summary the browser-side runtime publishes on window.QUNIT_RESULT.
-
currentTest: string | null
Name of the test in flight, or
nullwhen none is running — the stall diagnostic. -
failedTests: number
Tests with at least one failing assertion.
-
finishedTests: number
Tests that reached
testEnd; short oftotalTestsmeans the run stalled. -
totalTests: number
Tests QUnit registered for this run.
One concurrent group of a run: the files bundled into a single page, and where that page's artifacts were written.
-
files: string[]
Absolute paths of the test files this group bundled and ran together.
-
index: number
Position in the run's group list, and the
group-<index>suffix onoutput. -
output: string
Absolute path of this group's build output directory.
Outcome totals and failure bookkeeping accumulated across every group of a single run. Every field here is mutated in place — see RunState for why replacement is unsafe.
-
aborted: boolean
Whether the browser confirmed it dropped this run's remaining queue —
qq,session.abort(), or an abortedsignal. Lives here rather than on the group because groups share this object by reference, so one aborted group marks the whole run without any cross-group plumbing. -
counter: Counter
Running test-outcome counts, mutated in place as TAP events arrive.
-
coverage: CoverageFileMap | null
Accumulator for per-source line coverage when
coverageis enabled;nullwhen it is off. Reassigned only byRunState.reset(a fresh Map per run), never by a group. -
failedFiles: Set<string>
Absolute paths of test files with ≥1 failure in the current run, attributed per-test via source maps. Every group adds into this one set; persisted to the failure cache at run end.
-
failedTests: FailedTestRecord[]
Per-test metadata for the current run's failures; accumulated alongside
failedFiles.
One-shot callbacks wiring the browser's progress back into the run pipeline. Each is installed by the code that awaits it and fired by the web server as the corresponding event arrives.
-
onTestsJsServed: (() => void) | null
Resolves when the test bundle JS has been served to the browser at least once.
-
onWsOpen: (() => void) | null
Resolves when the WebSocket connection from the browser page is established.
-
resetTestTimeout: (() => void) | null
Resets the inactivity timeout; called on each TAP progress event.
-
testRunDone: (() => void) | null
Resolves when the browser signals that the test run is complete.
Mutable state for one test run, kept separate from the resolved settings on Config.
-
aborters: Set<() => void>
One callback per live server that tells its connected pages to drop the rest of the QUnit queue — what
qq,session.abort()and an abortedsignalall go through. -
console: Console
Where this run's text goes: the TAP document, every reporter line, every
#diagnostic and every forwarded page log.processConsolefor the CLI,silentConsolefor a programmatic run that only wants the result value. Shared by reference across concurrent groups. -
daemon: DaemonState | null
Non-null exactly when this run is executing inside the persistent daemon process — it is the daemon-mode flag as well as the handles. Daemon runs reuse the shared browser, suppress the per-connection TAP header, and leave that browser open at the end of the run.
-
group: GroupState
RunState for this group only. The group spread replaces this object (everything else in
RunStateis shared by reference), so it is the one place per-group slots may live. -
groupCount: number
Number of concurrent groups in this run; 1 for watch and single-group runs.
-
groups: RunGroup[]
How this run's files were split across those groups — the descriptive record
RunResultreports. Assigned once per run alongsidegroupCountand shared by reference, so a group can read the whole split rather than only its own slice. -
htmlAssets: HtmlAssets
HTML fixtures and their referenced assets, resolved once by
buildCachedContentbefore any group config is spread off. Frozen from that point on, so all groups share one copy. -
reporters: Reporter[]
Active reporter instances for this run, built by
Reporters.createinConfig.setup. One set for the whole run, so a stateful reporter sees every group rather than one slice. -
results: RunResults
Whole-run accumulators, shared by reference across every concurrent group.
-
signal: AbortSignal
Cancels this run when it fires, or absent when nothing can. Carried here rather than threaded alongside the config because it is per-run input like everything else in
state— and it is what lets a verb reach it from the resolved config instead of re-reading the raw arguments. -
watch: WatchState
File-watcher build bookkeeping. Only meaningful in watch mode, where there is one group.
Build bookkeeping owned by the file watcher, used to decide whether a filesystem event should dispatch a rebuild. Watch mode runs exactly one group, so nothing here is contended.
-
building: boolean
truewhile esbuild is actively compiling. -
builtContentHash: Record<string, string>
Per-file content hash of what was last dispatched to a build. Both the fs.watch change handler and the macOS/Deno rescan compare against this instead of mtime — mtime has 1-second resolution on some filesystems (macOS/HFS+), so rapid same-second writes with different content are indistinguishable by mtime; the hash catches them and drops echoes.
-
justAddedAt: Map<string, number>
filePath → msof when each file was last processed as an 'add', so a 'change' echo arriving inside ADD_SUPPRESS_WINDOW_MS can be suppressed. -
justAddedFiles: Set<string>
File paths added since the last build, used to decide whether a rebuild is needed.
-
lastBuildEndMs: number
Timestamp (ms) of the most recent successful build, used for debounce logic.
0before the first build. -
pendingBuildTrigger: (() => void) | null
Queued build-trigger callback; fires once the in-progress build completes.
Absolute source path → its accumulated FileCoverage.
| { kind: "no-tests"; files: string[]; }
Why a run is showing something other than its tests: the last esbuild run failed, or every
test file compiled but registered 0 QUnit tests (files holds their display paths).
Snapshot of the project's file-system structure: a map of relative paths to null.
Diffed against a fresh snapshot in watch mode to detect added or removed test files.
Replaces process.argv for the scope and restores the previous value on exit.
Applies overrides over process.env for the scope, then restores it exactly: keys added
during the scope are dropped and changed values are put back.
Closes, and does not come back while anything it started is still running.
Awaits every cleanup promise in closes, but never longer than graceMs. Resolves
whichever happens first: every close settles (Promise.allSettled absorbs rejections
so a single failing close cannot wedge the others), or the grace timer fires. Pending
closes keep running in the background after a timeout — the caller is expected to
process.exit() shortly after, which terminates them anyway.
What closeWithGrace gave up on, and a promise for those closes finally finishing.
-
names: string[]
The keys still pending when the grace expired. Empty when everything settled in time.
-
settled: Promise<void>
Settles when the abandoned closes do. Already settled when nothing was abandoned.
Default grace period for the cleanup race — generous enough for a healthy shutdown of
Playwright + HTTP server + Chrome pre-launch, well under the 60 s outer kill the test
runner imposes, and tuned around Firefox + Windows where browser.close() is known to
deadlock for the full 60 s.
ANSI blue text.
Creates a set of ANSI color helpers with coloring enabled or disabled.
ANSI green text.
ANSI magenta text. Call without arguments to chain: magenta().bold(text).
ANSI red text.
ANSI yellow text.
Converts a kebab-case, snake_case, camelCase, or PascalCase string to PascalCase.
Splits on - and _ word boundaries; internal capitals in camelCase/PascalCase
are preserved as-is.
Turns a termination signal into an ordinary exit, so process.on('exit') handlers still run.
Assembles the cache payload from the shared per-run failure slots on config.
Resolves the concrete previously-failing test files to re-run for --only-failed. Returns
null when no cache exists (the caller picks the fallback — run all, or a full watch start).
Otherwise returns the cached files that still exist, intersected with fsTree when input
targets were given (so failures stay scoped to what the user asked for) or the full cached set
when no targets were provided. Shared by the non-watch fsTree filter and the watch initial run.
Reads the failure cache; returns null on a missing file or any parse/shape error.
Records a failed testEnd into the shared per-run slots (state.results.failedFiles / failedTests)
used to build the persistent cache. The failing file is attributed via source-map resolution
of the first failing assertion's stack; when that can't be resolved to one of the run's test
files (timeouts, no stack, a frame in a shared helper), the whole run/group set is added so a
failure is never dropped from --only-failed.
Writes the failure cache. Best-effort; callers fire-and-forget like Timings.persist.
One failed test, kept for display and future -t (test-name filter) wiring.
-
file: string | null
Source file the failure was attributed to (relative to projectRoot), or
nullwhen unattributable. -
module: string
QUnit module path,
>-joined;''for a top-level test. -
testName: string
The test's own name.
On-disk shape of tmp/.qunitx-last-failures.json.
-
browser: string
Browser engine the failures were observed in.
-
files: string[]
Absolute paths of test files that contained at least one failure — drives
--only-failed. -
tests: FailedTestRecord[]
Per-test metadata for the failures above.
Parses an HTML string and returns all internal (non-absolute-URL) <script src> and <link href> paths.
Walks up from the working directory to the nearest package.json and resolves to its directory.
The one failure findProjectRoot declares.
No package.json at or above the working directory, so there is no project to run in.
Returns the path to an executable esbuild sidecar sitting next to execDir, or
null if none is present. On Windows the .exe variant is preferred. Pure and
injectable so the lookup order is unit-testable without a real compiled binary.
Resolves the working-tree paths that differ from ref, plus all uncommitted
modifications/additions, as absolute paths — or scope: 'everything' when a blast-radius
file (package.json, tsconfig*.json, …) changed.
Runs one git command with a hard upper bound on how long it can take.
| { scope: "paths"; paths: Set<string>; }
What a change scan found.
The failure a git-change scan declares — the E of its Task, the Err of .result().
Exact basenames whose modification invalidates the entire test suite. A change
to any of these short-circuits getChangedFilePathsInGitSince to null, signalling
the caller to skip filtering and run everything. The qunitx config lives
inside package.json per project convention, so package.json alone covers it.
Basename regexes with the same blast-radius semantics. Currently catches
tsconfig.json and editor variants like tsconfig.test.json /
tsconfig.build.json.
Upper bound on a single git invocation. --changed already degrades to "run all tests" when
git fails, so a stuck git should reject rather than wedge the run — without a bound the CLI
hangs forever, since neither git nor the caller ever gives up. 30s is orders of magnitude
above a healthy git status on a large repo, so it only fires on a genuine wedge.
git could not answer: not a repo, unknown ref, git missing, or it exceeded timeoutMs.
Returns the subset of testFiles (absolute paths) whose transitive imports,
per the cached esbuild metafile, include any file in changedAbsPaths.
Subset of esbuild's Metafile shape that we actually read. Defined locally so
this module doesn't import the heavy esbuild package — it only parses a
JSON file that esbuild produced earlier.
-
inputs: Record<string, { imports?: Array<{ path: string; }>; }>
Every input file esbuild visited, keyed by path relative to esbuild's cwd.
Returns the explicit {{qunitxScript}} placeholder when it exists in the template.
Injects the qunitx runner script block into a dynamic HTML template.
Reports whether an HTML template looks dynamic enough to act as a custom runner template.
Prepends count repetitions of indent (default: one space) to each non-empty line of string.
Whether pid is safe to hand to a negated process.kill.
Sends SIGKILL to a process and its entire process group. Requires the target to have
been spawned with detached: true so that PGID === pid.
Registers a stdin listener that fires closure when the user types inputString (case-insensitive by default).
Returns the on-disk cache path for projectRoot. The path embeds a SHA-1
tag of the absolute project root so projects that share a hoisted/symlinked
node_modules (pnpm workspaces, monorepos, integration test fixtures) write
to distinct files. 12 hex chars is far below collision risk for the scale of
"projects on one machine."
Reads the cached metafile. Returns null on miss or corruption.
Best-effort write; failures are swallowed because a cache miss on the next read just degrades to "run all tests."
Persistent on-disk cache of the most recent successful esbuild metafile,
used by --changed / --since to compute the reverse-dependency graph
without re-running esbuild. Lives under node_modules/.cache/ (npm convention,
gitignored, survives rm -rf tmp/).
-
esbuildCwd: string
process.cwd()at the moment the metafile was produced; metafile paths are relative to it. -
metafile: AffectedMetafile
The raw esbuild metafile this cache represents.
Opens the test output in the browser qunitx uses, detached from the qunitx process. In watch mode, opens the live HTTP server URL so WebSocket-driven reloads work on file changes. In normal mode, opens the static file:// URL (the bundle is self-contained, no server needed). If config.open is a string, it is used as the browser binary/command directly (e.g. 'brave', 'google-chrome-lts').
Returns true if the given filesystem path is accessible, false otherwise.
Writes a timestamped perf trace line to stderr when --trace-perf is active.
Reads a JSON cache file and hands back its contents, or null.
Reads a template file by relative path. Two runtimes to satisfy:
True when running inside a deno compiled binary (vs deno run script.ts or
plain Node). Detection is on process.execPath: under deno run it ends with
deno (or deno.exe on Windows); inside a compiled binary it's the user's
binary name. Deno.mainModule looked tempting but is also a file: URL in
compiled binaries (a virtual path under /tmp/deno-compile-<name>/), so it
can't differentiate the two.
Dynamically imports modulePath and calls its default export with params.
The one failure runUserModule declares.
A user-supplied --before/--after script threw, or could not be imported.
Recursively searches directory and its ancestors for a file or folder named targetEntry; returns the absolute path or undefined.
Parses the compact mappings string from a source-map V3 object into a per-line
array of segments, sorted by generatedCol (esbuild always emits them in order).
Extracts and decodes the inline source map that esbuild appends to a bundle as
//# sourceMappingURL=data:application/json;base64,….
Returns null when no inline map is present or parsing fails.
Returns true when url points to a test bundle (/tests.js or /filtered-tests.js) served by the local HTTP server.
| null
Returns the original source position for a generated (line, col) pair.
Both coordinates are 1-based (the format Chrome uses in Error.stack).
Returns null when the position cannot be mapped.
Parses a source-map V3 JSON string into a SourceMapDecoder ready for position lookup.
Parses the trailing URL:LINE:COL suffix of a stack frame. The greedy (.+) group
captures URLs that contain colons (e.g. http://host:PORT/path); the regex anchors
mean the last two :digits sequences are always the line/col.
Reads one VLQ-encoded integer from text starting at position.
Returns [decodedValue, positionAfterLastConsumedChar].
| null
Attempts to resolve a single stack-frame line to its original source location.
Handles Chrome named (at FUNC (URL:L:C)), Chrome anonymous (at [async] URL:L:C),
and Firefox/WebKit (FUNC@URL:L:C) formats.
Resolves every frame in stack that references a test bundle to its original source.
Resolves the absolute path of the source at sourceIndex in the map's sources array,
applying the same sourceRoot + outDir rules as position lookups. Returns null when
the index is out of range or the entry is empty. Used by the coverage collector to key
accumulated line coverage by absolute source path.
One decoded mapping entry. All coordinates are 0-based.
-
generatedCol: number
0-based column in the generated (bundle) file.
-
sourceCol: number
0-based column in the original source file.
-
sourceIndex: number
Index into the source map's
sourcesarray. -
sourceLine: number
0-based line in the original source file.
Parsed representation of a source-map V3 JSON, ready for position lookup.
-
outDir: string
Absolute directory of the bundle file, used to resolve relative source paths.
-
segmentsByLine: Segment[][]
Decoded segments indexed by 0-based generated line number.
-
sourceRoot: string
Source-root prefix from the map JSON (usually
""for esbuild output). -
sources: string[]
Raw source paths from the map (may be relative to
outDir). -
sourcesContent: (string | null)[]
Original source texts verbatim from the map JSON; one entry per
sourceselement.
Returns a timer object with a startTime Date and a stop() method that returns elapsed milliseconds.
Minimal HTTP + WebSocket server used to serve test bundles and push reload events.
-
_server: http.Server
Underlying Node.js HTTP server instance.
-
close(): Promise<void>
Closes the underlying HTTP server and all active connections, returning a Promise that resolves once the server is fully closed.
-
delete(): voidpath: string,handler: RouteHandler
Registers a DELETE route handler.
-
get(): voidpath: string,handler: RouteHandler
Registers a GET route handler.
-
listen(): Promise<void>port?: number,callback?: () => void
Starts listening on the given port (0 = OS-assigned).
-
middleware: Middleware[]
Registered middleware functions, applied in order before each route handler.
-
post(): voidpath: string,handler: RouteHandler
Registers a POST route handler.
-
publish(data: string): void
Broadcasts a message to all connected WebSocket clients.
-
put(): voidpath: string,handler: RouteHandler
Registers a PUT route handler.
-
routes: Record<string, Record<string, Route>>
Registered routes keyed by HTTP method then path.
-
serve(): Promise<http.Server>config?: { port: number; onListen?: (s: object) => void; onError?: (e: Error) => void; },handler: () => voidreq: http.IncomingMessage,res: http.ServerResponse
Creates and starts a plain
http.createServerinstance on the given port. -
use(middleware: Middleware): void
Adds a middleware function to the chain.
-
wss: WebSocketServer
WebSocket server attached to the HTTP server for live-reload broadcasts.
The request a route handler receives: node's, plus the four conveniences this server attaches before dispatching.
-
params: Record<string, string>
Values captured by the matched route's
:namesegments;{}for a literal route. -
path: string
The URL's pathname, without the query string.
-
query: Record<string, string>
The parsed query string.
-
send: (data: string) => void
Responds with
dataastext/plainand ends the response.
The response a route handler receives: node's, plus a JSON shorthand.
-
json: (data: unknown) => void
Responds with
dataasapplication/jsonand ends the response.
One registered route: the parsed shape get()/post()/… store and #findRouteHandler
matches against.
-
compiledRegex: RegExp | null
Prebuilt matcher for parameterised paths;
nullfor static ones. -
handler: RouteHandler
The handler
#handleRequestdispatches to when this route matches. -
isWildcard: boolean
Whether this is the catch-all
/*route. -
paramNames: string[]
Names of the
:paramsegments, in order of appearance. -
paramValues: string[]
The captured segment values from the most recent match; feeds
req.params. -
path: string
The registered path pattern, e.g.
/tests/:idor the/*wildcard.
Middleware function signature — call next() to continue the chain.
Route handler function signature for registered GET/POST/etc. routes.
Map of file extensions to their corresponding MIME type strings.