lib/api/daemon.ts

Functions

f
start(): Task<boolean, never>

Ensures a daemon is running for this project, spawning one if there isn't.

f
status(): Task<DaemonStatus, never>

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 }.

f
stop(): Task<boolean, never>

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.

f
test(options?: DaemonRunOptions): Task<RunResult, Client.DaemonRunFailure>

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.

Interfaces

I
DaemonRunOptions

The options a daemon run accepts: everything from UserRunOptions that survives a socket.

Type Aliases

lib/api/index.ts

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.

Functions

f
Daemon.start(): Task<boolean, never>

Ensures a daemon is running for this project, spawning one if there isn't.

f
Daemon.status(): Task<DaemonStatus, never>

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 }.

f
Daemon.stop(): Task<boolean, never>

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.

f
Daemon.test(options?: DaemonRunOptions): Task<RunResult, Client.DaemonRunFailure>

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.

f
openSession(
input?: SessionOptions | string | string[],
extra?: SessionOptions
): Task<TestSession | WatchSession, RunFailure>
4 overloads

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.

f
openSession(
input?: SessionOptions | string | string[],
extra?: SessionOptions
): Task<TestSession | WatchSession, RunFailure>
4 overloads

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.

f
openSession(
input?: SessionOptions | string | string[],
extra?: SessionOptions
): Task<TestSession | WatchSession, RunFailure>
4 overloads

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.

f
openSession(
input?: SessionOptions | string | string[],
extra?: SessionOptions
): Task<TestSession | WatchSession, RunFailure>
4 overloads

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.

f
openSession(
input?: SessionOptions | string | string[],
extra?: SessionOptions
): Task<TestSession | WatchSession, RunFailure>
4 overloads

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.

f
run(
file: string,
options?: ScriptOptions
): Task<ScriptResult, ScriptFailure>

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.

f
run(options?: InitOptions): Task<InitResult, ProjectRootNotFoundFailure>

Bootstraps a qunitx project: writes the test HTML template, updates package.json, and writes tsconfig.json when there isn't one.

f
run(options?: GenerateOptions): Task<GenerateResult, ProjectRootNotFoundFailure>

Writes a new test file from the boilerplate template, deriving the QUnit module name from the path. Never overwrites an existing file.

f
streamConsole(
stdout: { write(text: string): unknown; },
stderr?: { write(text: string): unknown; }
): Console

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.

f
test(
input?: UserRunOptions | string | string[],
extra?: UserRunOptions
): Task<RunResult, RunFailure>
2 overloads

Runs the suite once in a real browser and resolves with everything it produced.

f
test(
input?: UserRunOptions | string | string[],
extra?: UserRunOptions
): Task<RunResult, RunFailure>
2 overloads

Runs the suite once in a real browser and resolves with everything it produced.

f
test(
input?: UserRunOptions | string | string[],
extra?: UserRunOptions
): Task<RunResult, RunFailure>
2 overloads

Runs the suite once in a real browser and resolves with everything it produced.

f
validate(userRunOptions: UserRunOptions): void

Rejects options the run cannot honour, before anything is launched.

f
watch(
input?: UserRunOptions | string | string[],
extra?: UserRunOptions
): Task<WatchSession, RunFailure>
2 overloads

Starts a watch session: builds once, runs once, then re-runs on every save until closed.

f
watch(
input?: UserRunOptions | string | string[],
extra?: UserRunOptions
): Task<WatchSession, RunFailure>
2 overloads

Starts a watch session: builds once, runs once, then re-runs on every save until closed.

f
watch(
input?: UserRunOptions | string | string[],
extra?: UserRunOptions
): Task<WatchSession, RunFailure>
2 overloads

Starts a watch session: builds once, runs once, then re-runs on every save until closed.

Interfaces

I
BrowserLog

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), or pageerror.

I
Console

Where a run's text goes: console, made injectable.

I
CoverageSummary

The run's line coverage: one entry per source file, plus the totals across all of them.

I
Daemon.DaemonRunOptions

The options a daemon run accepts: everything from UserRunOptions that survives a socket.

I
DaemonRunOptions

The options a daemon run accepts: everything from UserRunOptions that survives a socket.

I
FileCoverageSummary

Per-file line coverage, when coverage was requested.

I
FoundTest

One test found by the static scan, named exactly as QUnit would name it.

I
GenerateOptions

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.

I
GenerateResult

What generate did: the file it wrote, or the one it refused to overwrite.

I
InitOptions

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'].

I
InitResult

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.

I
Notice

One diagnostic from qunitx itself: which files a narrowing flag scoped the run to, a filter that matched nothing, a build error, a timeout.

I
Reporter

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.

I
ReporterContext

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.

I
ResolvedRun

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.

I
RunEndInfo

Final run info; the counts themselves live on config.state.results.counter.

I
RunGroup

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 on output.

  • output: string

    Absolute path of this group's build output directory.

I
RunResult

Everything a finished run produced.

I
RunStartInfo

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).

I
ScriptOptions

Everything run accepts beyond the file itself — the subset of a script run a caller can set.

I
ScriptResult

What one script run produced.

  • browserLogs: BrowserLog[]

    Everything the script printed — its console calls and any uncaught error — in emit order, whatever console option 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. 0 when nothing was.

  • durationMs: number

    Wall-clock ms from the first bundle to the script's top level settling.

  • exitCode: number

    globalThis.exitCode if 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 null when it was a plain script.

  • value: unknown

    The script's export default, or undefined when it has none.

  • valueProblem: string | null

    Why ScriptResult.value is undefined even though the script exported something, or null when there is nothing to explain — including when it exported nothing at all.

I
SearchReport

What the static scan found, before anything is printed.

I
TestAssertion

One QUnit assertion inside a testEnd payload.

I
TestDetails

The QUnit testEnd payload as it arrives over the WebSocket. Passing tests carry the trimmed { status, fullName, runtime }; failing tests additionally carry assertions.

I
TestResult

One finished test.

I
TestSession

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: true on 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. 0 in every ordinary run.

  • events(): Stream<RunEvent>

    The same events as iterating the session, as a Stream — so the combinators are there without a Stream.from wrapper.

  • result(): Promise<RunResult>

    The finished run. Starts it if nothing has yet, and resolves with the same RunResult the final runEnd event carries — never undefined, which is the whole reason this is a session rather than a bare event stream.

I
UnlistableCounts

Why some declarations could not be listed, split by cause.

I
UserRunOptions

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). formats additionally 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#34 line targets — the same grammar as the command line's positional arguments. Defaults to package.json#qunitx.inputs.

  • junit: boolean | string

    Write a JUnit XML report. true writes <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: true for 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, or false. The same spelling as the CLI's --reporter.

  • reporters: ReadonlyArray<ReporterOption>

    Print the run with SEVERAL. Mutually exclusive with UserRunOptions.reporter: pass reporter for one, reporters for 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.

I
WatchSession

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: true on its result.

  • browser: Browser

    Playwright's Browser for 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. 0 unless something stalls.

  • esbuild: BuildContext | null

    esbuild's incremental BuildContextunstable, 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.watch handles 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 — initial until 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 info notice 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 HTTPServer rather than a documented interface.

Namespaces

N
Daemon

Daemon control: start, stop, status, and a test that reuses the daemon's warm browser and returns the same RunResult a local run does.

Type Aliases

T
AnyFailure = Any

A declared failure: something the runner decided it could not do, carrying a code to branch on and a message to show.

T
Daemon.DaemonRunFailure = Failure.Of<DaemonUnreachable | DaemonDisconnected | DaemonSilent>

Every way a daemon-routed run can fail to produce an exit code.

T
DaemonRunFailure = Failure.Of<DaemonUnreachable | DaemonDisconnected | DaemonSilent>

Every way a daemon-routed run can fail to produce an exit code.

T
InvalidOptionFailure = Failure.Of<InvalidOption>

The one failure validate raises.

T
ReporterName = (REPORTERS)[number]

A valid --reporter value.

T
ReporterOption = ReporterName | Reporter | false

--reporter by name, a reporter of your own, or false for none.

T
Result<T, E = Any> = T | E

The success value or a declared failure — a bare union, discriminated by the Failure brand.

T
RunCounts = Counter

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.

T
RunFailure = ConfigFailure | InvalidOptionFailure

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.

T
ScriptFailure =
Failure.Of<NotAScriptFile | RunCommand.ScriptBuildFailed>
| ScriptEntryFailure

Every way run can reject. A script that merely exits non-zero is NOT one of them.

T
SessionOptions = UserRunOptions & { watch?: boolean; }

What openSession accepts: every run option, plus the one that chooses the shape.

Variables

v
processConsole: Console

The CLI's: the real process streams. .write is looked up per call, so the daemon's stdout interception still reaches it.

v
REPORTERS: "tap" | "spec" | "dot" | "github"[]

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.

v
silentConsole: Console

Discards everything. The JS API's default, so a programmatic run prints nothing unless it was asked to.

v
T
Stream

The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only entry points — there is no public constructor and no call form.

v
T
Stream

The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only entry points — there is no public constructor and no call form.

v
T
Task: TaskConstructor

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.

v
T
Task: TaskConstructor

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.

lib/api/options.ts

Functions

f
from(
input?: UserRunOptions | string | string[],
options?: UserRunOptions
): ConfigOptions & { reporters: Reporter[]; }

Public options in, runner input out — this is the API's Args.parse, and the only reason UserRunOptions and ConfigOptions are separate types.

f
validate(userRunOptions: UserRunOptions): void

Rejects options the run cannot honour, before anything is launched.

Interfaces

I
UserRunOptions

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). formats additionally 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#34 line targets — the same grammar as the command line's positional arguments. Defaults to package.json#qunitx.inputs.

  • junit: boolean | string

    Write a JUnit XML report. true writes <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: true for 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, or false. The same spelling as the CLI's --reporter.

  • reporters: ReadonlyArray<ReporterOption>

    Print the run with SEVERAL. Mutually exclusive with UserRunOptions.reporter: pass reporter for one, reporters for 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.

Type Aliases

T
InvalidOptionFailure = Failure.Of<InvalidOption>

The one failure validate raises.

T
ReporterOption = ReporterName | Reporter | false

--reporter by name, a reporter of your own, or false for none.

Variables

lib/api/reporter.ts

Classes

c
APIReporter

The reporter that turns a run into a value: it records what happened instead of printing it.

Functions

f
findAPIReporterFrom(config: Config): APIReporter

The APIReporter watching this run — the reporter every result is built from.

f
toTestResult(details: TestDetails): TestResult

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 : .

Type Aliases

Variables

v
CHANNEL_CAPACITY: 10000

The buffer a feed keeps for a consumer that has stopped reading.

v
MAX_BROWSER_LOGS: 1000

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.

lib/api/run.ts

Functions

f
run(
file: string,
options?: ScriptOptions
): Task<ScriptResult, ScriptFailure>

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.

Interfaces

I
ScriptOptions

Everything run accepts beyond the file itself — the subset of a script run a caller can set.

I
ScriptResult

What one script run produced.

  • browserLogs: BrowserLog[]

    Everything the script printed — its console calls and any uncaught error — in emit order, whatever console option 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. 0 when nothing was.

  • durationMs: number

    Wall-clock ms from the first bundle to the script's top level settling.

  • exitCode: number

    globalThis.exitCode if 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 null when it was a plain script.

  • value: unknown

    The script's export default, or undefined when it has none.

  • valueProblem: string | null

    Why ScriptResult.value is undefined even though the script exported something, or null when there is nothing to explain — including when it exported nothing at all.

Type Aliases

T
ScriptFailure =
Failure.Of<NotAScriptFile | RunCommand.ScriptBuildFailed>
| ScriptEntryFailure

Every way run can reject. A script that merely exits non-zero is NOT one of them.

Variables

lib/api/search.ts

Functions

f
search(options?: UserRunOptions | string | string[]): Task<SearchResult, RunFailure>

Lists the tests a selection would run, without running them.

Interfaces

I
FoundTest

One test found by the static scan, named exactly as QUnit would name it.

I
SearchReport

What the static scan found, before anything is printed.

I
UnlistableCounts

Why some declarations could not be listed, split by cause.

lib/api/session.ts

Functions

f
openSession(
input?: SessionOptions | string | string[],
extra?: SessionOptions
): Task<TestSession | WatchSession, RunFailure>
4 overloads

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.

Interfaces

I
TestSession

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: true on 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. 0 in every ordinary run.

  • events(): Stream<RunEvent>

    The same events as iterating the session, as a Stream — so the combinators are there without a Stream.from wrapper.

  • result(): Promise<RunResult>

    The finished run. Starts it if nothing has yet, and resolves with the same RunResult the final runEnd event carries — never undefined, which is the whole reason this is a session rather than a bare event stream.

Type Aliases

T
SessionOptions = UserRunOptions & { watch?: boolean; }

What openSession accepts: every run option, plus the one that chooses the shape.

lib/api/test.ts

Functions

f
abort(config: ResolvedConfig): RunResult

The result of a run that was cancelled before it began: no browser, no tests, aborted: true.

f
buildResult(
config: ResolvedConfig,
outcome: RunOutcome
): RunResult

Assembles the run's result from the config's accumulated state, the run's outcome, and the APIReporter that watched it.

f
test(
input?: UserRunOptions | string | string[],
extra?: UserRunOptions
): Task<RunResult, RunFailure>
2 overloads

Runs the suite once in a real browser and resolves with everything it produced.

Interfaces

I
CoverageSummary

The run's line coverage: one entry per source file, plus the totals across all of them.

I
FileCoverageSummary

Per-file line coverage, when coverage was requested.

I
ResolvedRun

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.

I
RunGroup

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 on output.

  • output: string

    Absolute path of this group's build output directory.

I
RunResult

Everything a finished run produced.

I
TestResult

One finished test.

Type Aliases

T
RunCounts = Counter

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.

T
RunFailure = ConfigFailure | InvalidOptionFailure

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.

lib/api/watch.ts

Functions

f
watch(
input?: UserRunOptions | string | string[],
extra?: UserRunOptions
): Task<WatchSession, RunFailure>
2 overloads

Starts a watch session: builds once, runs once, then re-runs on every save until closed.

Interfaces

I
WatchSession

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: true on its result.

  • browser: Browser

    Playwright's Browser for 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. 0 unless something stalls.

  • esbuild: BuildContext | null

    esbuild's incremental BuildContextunstable, 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.watch handles 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 — initial until 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 info notice 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 HTTPServer rather than a documented interface.

Type Aliases

lib/args/index.ts

Functions

f
applyInputs(
flags: ParsedFlags,
projectRoot: string,
cwd: string,
positional: readonly string[]
): ParsedFlags

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.

f
parse(
projectRoot: string,
argv?: readonly string[],
cwd?: string
): Result<ParsedFlags, ParseFailure>

Parses an argv into a qunitx flag object (inputs, debug, watch, failFast, timeout, output, port, before, after).

f
tokenize(args: readonly string[]): ArgToken[]

Classifies argv into query / flag / input tokens.

Interfaces

I
FlagToken

Any other flag (--watch, --timeout=5000, -o, …), passed through verbatim.

I
InputToken

A positional target: a file, folder, or glob (possibly with a #34 line suffix).

I
ParsedFlags

The flag object a successful parse() carries — CLI flags only, before package.json merge.

I
QueryToken

A query flag (-t/-m/-s/-p) with its resolved value.

Type Aliases

T
ArgToken = QueryToken | FlagToken | InputToken

One classified argv entry: a query flag, any other flag, or a positional input.

T
ParseFailure = Failure.Of<InvalidFlag>

Every way parse() can reject its input.

Variables

lib/args/parse.ts

Functions

f
applyInputs(
flags: ParsedFlags,
projectRoot: string,
cwd: string,
positional: readonly string[]
): ParsedFlags

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.

f
parse(
projectRoot: string,
argv?: readonly string[],
cwd?: string
): Result<ParsedFlags, ParseFailure>

Parses an argv into a qunitx flag object (inputs, debug, watch, failFast, timeout, output, port, before, after).

Interfaces

I
ParsedFlags

The flag object a successful parse() carries — CLI flags only, before package.json merge.

Type Aliases

T
ParseFailure = Failure.Of<InvalidFlag>

Every way parse() can reject its input.

Variables

lib/args/tokenize.ts

Functions

f
tokenize(args: readonly string[]): ArgToken[]

Classifies argv into query / flag / input tokens.

Interfaces

I
FlagToken

Any other flag (--watch, --timeout=5000, -o, …), passed through verbatim.

I
InputToken

A positional target: a file, folder, or glob (possibly with a #34 line suffix).

I
QueryToken

A query flag (-t/-m/-s/-p) with its resolved value.

Type Aliases

T
ArgToken = QueryToken | FlagToken | InputToken

One classified argv entry: a query flag, any other flag, or a positional input.

lib/chrome/chromium-args.ts

Variables

v
CHROMIUM_ARGS: string[]

Launch args passed to Chromium for both the CDP pre-launch spawn and the playwright fallback launch.

lib/chrome/cleanup-dir.ts

Functions

f
cleanupDir(dirPath: string): Promise<void>

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).

lib/chrome/find.ts

Functions

f
find(): Promise<string | null>

Resolves the Chrome/Chromium executable path. Returns a Promise for API compatibility with callers, but the resolution is synchronous.

lib/chrome/index.ts

Functions

f
cleanupDir(dirPath: string): Promise<void>

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).

f
find(): Promise<string | null>

Resolves the Chrome/Chromium executable path. Returns a Promise for API compatibility with callers, but the resolution is synchronous.

f
spawn(
chromePath: string | null | undefined,
args: string[],
headless?: boolean,
onSpawn?: (handle: ChromeHandle) => void
): Promise<EarlyChrome | null>

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().

Variables

v
CHROMIUM_ARGS: string[]

Launch args passed to Chromium for both the CDP pre-launch spawn and the playwright fallback launch.

lib/chrome/prelaunch.ts

Functions

f
prelaunchPromise(): Promise<EarlyChrome | null>

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).

f
shutdownPrelaunch(): Promise<void>

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).

f
startPrelaunch(): void

Starts Chrome now, if this invocation is one that will need it.

lib/chrome/spawn.ts

Functions

f
spawn(
chromePath: string | null | undefined,
args: string[],
headless?: boolean,
onSpawn?: (handle: ChromeHandle) => void
): Promise<EarlyChrome | null>

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().

lib/commands/daemon/client.ts

Functions

f
ping(): Promise<ResponseChunk | null>

Sends a ping and resolves the daemon's pong response (or null on failure).

f
run(
options: DaemonRunOptions,
sink?: Console
): Task<RunResult, DaemonRunFailure>

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.

f
runArgv(argv: string[]): Task<number, DaemonRunFailure>

The CLI's path: sends raw argv and answers with the exit code the daemon reported.

f
shouldAutoSpawn(): boolean

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.

f
shouldUse(): boolean

True iff a live daemon socket exists and the invocation can use it. The cli's primary dispatch check.

f
shutdown(cwd?: string): Promise<boolean>

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.

f
tryConnect(cwd?: string): Promise<net.Socket | null>

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).

Type Aliases

T
DaemonRunFailure = Failure.Of<DaemonUnreachable | DaemonDisconnected | DaemonSilent>

Every way a daemon-routed run can fail to produce an exit code.

Variables

v
DaemonDisconnected: Failure.FailureFactory<
"DaemonDisconnected",
{ reason: "close" | "error" | "no-result"; }
>

The daemon accepted the run and then dropped the connection without a terminal message.

v
DaemonSilent: Failure.FailureFactory<"DaemonSilent", { ms: number; }>

The daemon accepted the connection and then said nothing for RUN_SILENCE_TIMEOUT_MS.

v
RUN_SILENCE_TIMEOUT_MS: 240000

How long the client waits on total silence before declaring the daemon wedged.

lib/commands/daemon/hint.ts

Functions

f
maybePrint(
ctx: HintContext,
opts?: PrintOpts
): Promise<void>

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.

f
shouldShow(ctx: HintContext): boolean

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.

Interfaces

I
HintContext

Run context consumed by the daemon-hint eligibility check.

I
PrintOpts

Side-effect injection points for maybePrint — testing seams.

lib/commands/daemon/index.ts

Functions

f
ensureRunning(): Promise<boolean>

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.

f
run(): Promise<number>

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.

lib/commands/daemon/parse-idle-timeout.ts

Functions

f
parseIdleTimeout(value: string | undefined): ParsedIdleTimeout

Parses the QUNITX_DAEMON_IDLE_TIMEOUT env value. Accepts:

Interfaces

I
ParsedIdleTimeout

Result of parseIdleTimeout: the resolved idle window plus an optional human-readable warning the caller should surface to the user.

  • ms: number

    Milliseconds. Infinity when 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.

Variables

v
DEFAULT_IDLE_TIMEOUT_MS: number

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.

lib/commands/daemon/paths.ts

Functions

f
dir(cwd?: string): string

Returns the per-cwd subdirectory that holds the daemon's info file, lockfile, and any future per-daemon state.

f
info(cwd?: string): string

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.

f
socket(
cwd?: string,
platform?: NodeJS.Platform
): string

Returns the per-cwd path the daemon listens on. Platform-specific:

lib/commands/daemon/protocol.ts

Interfaces

I
DaemonInfo

Sidecar JSON file written next to the socket; lets daemon status show details without an IPC roundtrip.

I
DaemonRunOptions

The options a daemon run accepts: everything from UserRunOptions that survives a socket.

I
PingRequest

Client → daemon: liveness/identity probe.

I
RunRequest

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 result chunk"; absent means the daemon parses argv exactly as the CLI would.

  • type: "run"

    Discriminator for the protocol union; always 'run' for this variant.

I
ShutdownRequest

Client → daemon: graceful shutdown request.

Type Aliases

lib/commands/daemon/server.ts

Functions

f
browserResponsive(
browser:
Pick<PlaywrightBrowser, "isConnected">
& { newBrowserCDPSession?: PlaywrightBrowser["newBrowserCDPSession"]; },
browserName: string,
timeoutMs?: number
): Promise<boolean>

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.

f
noteBrowserOutcome(
state: Pick<DaemonState, "consecutiveCrashes">,
connected: boolean
): "ok" | "relaunch" | "shutdown"

The crash-budget policy, as one pure decision: what a run's outcome does to the counter, and what should happen next.

f
removeLivenessFiles(state: DaemonState): Promise<void>

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.

f
serve(): Promise<void>

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.

f
shutdown(
state: DaemonState,
reason: string,
exit?: () => void
): Promise<void>

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.

Interfaces

Variables

v
BROWSER_PROBE_TIMEOUT_MS: 3000

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.

v
BROWSER_RELAUNCH_TIMEOUT_MS: 90000

How long a crash relaunch may take before the daemon declares itself unrecoverable.

lib/commands/daemon/socket.ts

Functions

f
connect(
socketPath: string,
timeoutMs: number
): Promise<net.Socket | null>

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).

f
readMessages<T>(
socket: net.Socket,
onLine: (line: T) => void
): void

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).

lib/commands/generate.ts

Functions

f
run(options?: GenerateOptions): Task<GenerateResult, ProjectRootNotFoundFailure>

Writes a new test file from the boilerplate template, deriving the QUnit module name from the path. Never overwrites an existing file.

Interfaces

I
GenerateOptions

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.

I
GenerateResult

What generate did: the file it wrote, or the one it refused to overwrite.

lib/commands/help.ts

Functions

f
run(): void

Prints qunitx-cli usage information to stdout.

lib/commands/init.ts

Functions

f
run(options?: InitOptions): Task<InitResult, ProjectRootNotFoundFailure>

Bootstraps a qunitx project: writes the test HTML template, updates package.json, and writes tsconfig.json when there isn't one.

Interfaces

I
InitOptions

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'].

I
InitResult

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.

lib/commands/run.ts

Functions

f
run(
entry: string,
settings?: ScriptSettings
): Promise<ScriptOutcome>

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.

f
setup(
argv?: string[],
cwd?: string
): Task<ScriptInvocation, ScriptConfigFailure>

Reads qunitx run's argv into a target and its settings.

f
suiteHint(
cwd: string,
entry: string,
relativeTo?: (
from: string,
to: string
) => string
): string

The qunitx <file> line the suite warning suggests, with forward slashes.

f
watchDirectoriesFrom(
inputs: string[],
cwd: string,
pathApi?: Pick<path, "resolve" | "dirname">
): string[]

The directories watch mode should watch, from esbuild's metafile input keys.

f
watchLoop(
directories: string[],
run: () => Promise<void>,
watch?: (
directory: string,
listener: () => void
) => void
,
debounceMs?: number
): Promise<never>

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.

Interfaces

I
ScriptConfig

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.

I
ScriptInvocation

What qunitx run's argv amounts to: the one target, and the settings the flags asked for.

I
ScriptOutcome

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. 0 when nothing was.

  • entry: string

    Absolute path of the file that ran, resolved against cwd.

  • exitCode: number

    globalThis.exitCode if the script set one, 1 if it threw, else 0.

  • tests: RunResult | null

    The suite the entry declared, or null when it was a plain script.

  • value: unknown

    The script's export default, or undefined when 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 undefined despite the script exporting something, or null when there is nothing to explain.

I
ScriptSettings

Everything a caller may set on a script run: the CLI's flags and the API's options, minus argv.

Type Aliases

Variables

v
ScriptBuildFailed: Failure.FailureFactory<"ScriptBuildFailed", { entry: string; }>

The script could not be bundled — a syntax error, or an import that does not resolve.

v
ScriptNotFound: Failure.FailureFactory<"ScriptNotFound", { entry: string; }>

qunitx run was pointed at a file that is not there.

lib/commands/search.ts

Functions

f
run(config: Config): Promise<number>

--search / -s / --print / --preview: list the tests the current selection matches, without running them.

f
scan(config: Config): Promise<SearchReport>

Scans the selected files and resolves which of their tests the current selection matches — no browser, no bundle, no execution.

Interfaces

I
FoundTest

One test found by the static scan, named exactly as QUnit would name it.

I
SearchReport

What the static scan found, before anything is printed.

I
UnlistableCounts

Why some declarations could not be listed, split by cause.

lib/commands/test.ts

Functions

f
run(config: Config): Promise<RunOutcome>

Runs the whole suite once in headless Chrome and resolves with its RunOutcome.

f
scriptHint(
cwd: string,
file: string,
relativeTo?: (
from: string,
to: string
) => string
): string

The qunitx run <file> line a zero-test run suggests, with forward slashes.

f
watch(config: Config): Promise<WatchSession>

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.

Interfaces

I
RunOutcome

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

    0 when every test passed, 1 for any failure, group rejection, or empty filtered run.

  • finishedAt: number

    Epoch ms when it ended. finishedAt - startedAt is durationMs modulo clock resolution.

  • startedAt: number

    Epoch ms when the test phase began — after the bundle, at the first navigation.

I
WatchSession

A live watch session: the run's browser, server and file watchers, kept open.

lib/commands/test/grouping.ts

Functions

f
applyWatchLineTargets(config: Config): Promise<void>

Watch-mode line targets: narrow fsTree to the targeted files and apply their selectors for the whole session.

f
resolveTargetedFiles(
config: Config,
allFiles: string[]
): Promise<TargetedFile[]>

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.

f
splitIntoGroups(
files: string[],
groupCount: number,
timings: Record<string, number>
): Promise<{ groups: string[][]; weights: Map<string, number>; }>

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).

Interfaces

lib/commands/test/tests-in-browser.ts

Functions

f
armJSCoverage(
page: Page,
config: Config,
log?: (...args: unknown[]) => void
): Promise<boolean>

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.

f
buildAllGroupBundles(groupConfigs: Config[]): Promise<void>

Builds all concurrent group bundles with a single esbuild invocation.

f
buildTestBundle(config: Config): Promise<void>

Pre-builds the esbuild bundle for all test files and caches the result in the group's build state.

f
bundleCacheKey(
opts: esbuild.BuildOptions,
files: string[]
): string

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.

f
deriveBuildErrorType(error: unknown): string

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.

f
flushConsoleHandlers(
handlers?: Set<Promise<void>> | null,
page?: Page | null,
deadline?
): Promise<void>

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.

f
formatBuildErrors(error: unknown): string

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.

f
reconcileUndeliveredResults(
counter: Counter,
result: QUnitResult
): number

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).

f
run(
config: Config,
connections: Connections,
targetTestFilesToFilter?: string[] | null
): Promise<Connections | undefined>

Runs the esbuild-bundled tests inside a Playwright-controlled browser page and streams TAP output.

Type Aliases

T
BrowserRunOutcome =
{ kind: "completed"; }
| { kind: "empty"; }
| { kind: "no-tests-ran"; }
| { kind: "stalled"; }

How a browser run ended, decided from QUnit's tally plus whether a WS done arrived.

lib/commands/test/timings.ts

Functions

f
compute(
groups: string[][],
weights: Map<string, number>,
wallTimes: Map<number, number>
): Map<string, number>

Distributes each group's wall-clock ms to its files proportionally by LPT weight.

f
persist(
fileTimes: Map<string, number>,
projectRoot: string
): Promise<void>

Writes the merged per-file timings back to tmp/test-timings.json for the next run to pack with.

f
print(
fileTimes: Map<string, number>,
projectRoot: string
): void

--debug listing of this run's per-file wall times, slowest first.

f
read(projectRoot: string): Task<Record<string, number>, never>

Reads tmp/test-timings.json from projectRoot; returns {} on any error or invalid content.

lib/commands/upgrade/channel.ts

Functions

f
detect(probe?: ChannelProbe): InstallChannel

Resolves the channel this process is running from.

f
isSelfUpdatable(channel: InstallChannel): boolean

Whether this channel's updater is qunitx's to run.

f
updateArgv(
channel: InstallChannel,
version: string,
registry?: "npm" | "jsr"
): string[]

The command that upgrades this channel: deno install, npm install -g, deno add, git pull.

Interfaces

I
ChannelProbe

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.

Type Aliases

lib/commands/upgrade/index.ts

Functions

f
parseArgs(argv: string[]): Result<UpgradeOptions, Failure.Of<InvalidArgument>>

Parses qunitx upgrade's arguments. A bare 0.34.2 (or v0.34.2) pins the version, the same as --version=0.34.2.

Interfaces

I
UpgradeDeps

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.

I
UpgradeOptions

What qunitx upgrade's argv asked for.

Variables

lib/commands/upgrade/install.ts

Functions

f
apply(
plan: InstallPlan,
deps?: InstallDeps
): Promise<string[]>

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).

f
extract(
archivePath: string,
destination: string
): Promise<void>

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.

f
swapBinary(
staged: string,
target: string,
platform?: NodeJS.Platform
): Promise<void>

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.

Interfaces

I
InstallDeps

The seams apply reaches the world through. All three default to the real thing.

I
InstallPlan

What to install, and over what.

Variables

v
AssetMissing: Failure.FailureFactory<"UpgradeAssetMissing", { asset: string; tag: string; }>

The release has no asset for this platform — a deno compile build asking for a target only the SEA matrix publishes, or the reverse.

v
ChecksumMismatch: Failure.FailureFactory<
"UpgradeChecksumMismatch",
{ asset: string; expected: string; actual: string; }
>

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.

v
ChecksumsMissing: Failure.FailureFactory<"UpgradeChecksumsMissing", { tag: string; }>

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.

v
DownloadFailed: Failure.FailureFactory<"UpgradeDownloadFailed", { url: string; reason: string; }>

The download itself failed — an HTTP error or a dead connection mid-transfer.

v
ReplaceFailed: Failure.FailureFactory<
"UpgradeReplaceFailed",
{ target: string; reason: string; recovered?: string; }
>

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.

v
TargetNotWritable: Failure.FailureFactory<"UpgradeTargetNotWritable", { dir: string; }>

The directory holding the binary is not writable by this user — the usual case being a root-owned prefix such as /usr/local/bin.

lib/commands/upgrade/manifest.ts

Functions

f
bump(
manifestPath: string,
version: string
): Promise<BumpedEntry>

Points the manifest's qunitx-cli entry at version, keeping whatever range operator it already used: ^ stays ^, ~ stays ~, and an exact pin stays exact.

f
registry(manifestPath: string): Promise<"npm" | "jsr">

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.

Interfaces

I
BumpedEntry

What bump changed: where the entry lives, and the range it now carries.

  • field: string

    The part of the manifest that changed: imports, dependencies or devDependencies.

  • range: string

    The range now written there, operator included.

Variables

v
EntryMissing: Failure.FailureFactory<"UpgradeManifestEntryMissing", { manifest: string; }>

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.

lib/commands/upgrade/process.ts

Functions

f
spawn(argv: string[]): Promise<SpawnResult>

Runs another tool's installer — deno install, npm install -g — and reports how it went.

Interfaces

I
SpawnResult

How the installer this process ran finished — shaped like the process it describes.

lib/commands/upgrade/release.ts

Functions

f
assetName(
flavor: "sea" | "deno",
platform?: NodeJS.Platform,
arch?: string
): string | null

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.

f
compare(
a: string,
b: string
): number

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.

f
find(
version?: string,
fetchImpl?: fetch
): Promise<Release>

Fetches the newest release, or the one matching version when pinned.

f
parseChecksums(text: string): Map<string, string>

Parses the release's checksums.txt (sha256sum output) into name → sha256.

Interfaces

I
Release

A published release, reduced to what an upgrade needs.

I
ReleaseAsset

One downloadable file on a release.

Variables

v
LookupFailed: Failure.FailureFactory<"UpgradeLookupFailed", { url: string; reason: string; }>

The release lookup could not be answered — no network, a proxy, an HTTP error, or GitHub's unauthenticated rate limit.

lib/console.ts

Functions

f
streamConsole(
stdout: { write(text: string): unknown; },
stderr?: { write(text: string): unknown; }
): Console

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.

Interfaces

I
Console

Where a run's text goes: console, made injectable.

Variables

v
processConsole: Console

The CLI's: the real process streams. .write is looked up per call, so the daemon's stdout interception still reaches it.

v
silentConsole: Console

Discards everything. The JS API's default, so a programmatic run prints nothing unless it was asked to.

lib/coverage/collect.ts

Functions

f
collect(
config: Config,
entries: V8ScriptCoverage[]
): Promise<void>

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).

Interfaces

lib/coverage/index.ts

Functions

f
collect(
config: Config,
entries: V8ScriptCoverage[]
): Promise<void>

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).

f
Report.buildHtml(rows: FileRow[]): string

Builds a self-contained HTML report: a summary table plus per-file source with line coloring.

f
Report.buildLcov(rows: FileRow[]): string

Builds a standard LCOV lcov.info string (line coverage only: DA/LF/LH per file).

f
Report.buildRows(
collector: CoverageFileMap,
testFiles: Set<string>,
projectRoot: string
): FileRow[]

Turns the raw coverage map into sorted, test-file-filtered rows with computed percentages.

f
Report.write(
config: Config,
testFiles: string[]
): Promise<void>

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.

Interfaces

Namespaces

N
Report

Coverage report rendering — writes the report and builds its rows/lcov/html forms.

lib/coverage/report.ts

Functions

f
buildHtml(rows: FileRow[]): string

Builds a self-contained HTML report: a summary table plus per-file source with line coloring.

f
buildLcov(rows: FileRow[]): string

Builds a standard LCOV lcov.info string (line coverage only: DA/LF/LH per file).

f
buildRows(
collector: CoverageFileMap,
testFiles: Set<string>,
projectRoot: string
): FileRow[]

Turns the raw coverage map into sorted, test-file-filtered rows with computed percentages.

f
write(
config: Config,
testFiles: string[]
): Promise<void>

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.

Interfaces

lib/reporters/dot.ts

Classes

c
DotReporter

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.

lib/reporters/failure.ts

Functions

f
extractStackAt(stack: string | null | undefined): string | null

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.

f
failedAssertions(
details: TestDetails,
decoder?: SourceMapDecoder | null,
projectRoot?: string
): FailureInfo[]

Extracts every genuinely-failing assertion (todo assertions are expected to fail and are excluded) from a testEnd payload, resolving stacks back to original sources.

f
parseAt(at: string | null): { file: string; line: number; col: number; } | null

Splits an at string (path:line:col) into parts; returns null when it isn't a location.

Interfaces

I
FailureInfo

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.

lib/reporters/github.ts

Classes

c
GithubReporter

GitHub Actions reporter: spec output, plus a ::error workflow command per failure so the failure is annotated inline on the PR diff.

Functions

f
annotation(
title: string,
failure: FailureInfo
): string

Builds one ::error file=…,line=…,col=…,title=…::message workflow command.

lib/reporters/index.ts

Functions

f
browserLog(
config: Config,
log: BrowserLog
): void

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.

f
create(config: Config): Reporter[]

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).

f
error(
config: Config,
message: string,
options?: NoticeOptions
): void

A diagnostic that also belongs on stderr — a stack trace, a timeout, a page that crashed.

f
info(
config: Config,
message: string,
options?: NoticeOptions
): void

A decision the runner made and wants on the record — what it chose to run, what it skipped.

f
runEnd(
config: Config,
info: RunEndInfo
): Promise<void>

Emits run end to every active reporter, awaiting any that flush asynchronously.

f
runStart(
config: Config,
info: RunStartInfo
): void

Emits run start to every active reporter. In watch mode this fires once per rerun.

f
testEnd(
config: Config,
details: TestDetails
): void

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.

f
warning(
config: Config,
message: string,
options?: NoticeOptions
): void

Something surprising that did not stop the run — a filter that matched nothing, a flag that does not apply to the chosen browser.

Interfaces

I
NoticeOptions

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. output by default.

Variables

v
BUILT_IN_REPORTERS: Record<ReporterName, new () => Reporter>

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.

lib/reporters/junit.ts

Classes

c
JUnitReporter

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.

Functions

f
buildXML(cases: JUnitCase[]): string

Builds the full JUnit XML document string from a flat list of test cases.

f
outputPath(context: ReporterContext): string

Resolves where the JUnit document is written: --junit=<path> (relative to the project root) when given a string, else <output>/junit.xml.

f
toCase(
context: ReporterContext,
details: TestDetails
): JUnitCase

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).

lib/reporters/spec.ts

Classes

c
SpecReporter

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.

Functions

f
formatFailureBlock(failures: FailureInfo[]): string

Renders every failing assertion of one test: message, values, and source location.

lib/reporters/tap.ts

Classes

c
TAPReporter

The default reporter: streams TAP version 13 to stdout. Stateless — every number it prints comes from context.counts, which the dispatcher updates before onTestEnd.

lib/reporters/types.ts

Functions

f
updateCounter(
counter: Counter,
details: TestDetails
): void

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.

Interfaces

I
BrowserLog

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), or pageerror.

I
Notice

One diagnostic from qunitx itself: which files a narrowing flag scoped the run to, a filter that matched nothing, a build error, a timeout.

I
Reporter

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.

I
ReporterContext

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.

I
RunEndInfo

Final run info; the counts themselves live on config.state.results.counter.

I
RunStartInfo

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).

I
TestAssertion

One QUnit assertion inside a testEnd payload.

I
TestDetails

The QUnit testEnd payload as it arrives over the WebSocket. Passing tests carry the trimmed { status, fullName, runtime }; failing tests additionally carry assertions.

Type Aliases

T
ReporterName = (REPORTERS)[number]

A valid --reporter value.

Variables

v
REPORTERS: "tap" | "spec" | "dot" | "github"[]

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.

lib/result/failure.ts

Classes

c
Failure<Code extends string = string, Data = unknown>(
code: Code,
message: string,
data: Data,
options?: FailureOptions
)

A structured, discriminable error.

Functions

f
attributes(failure: Any): TraceAttributes

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.

f
causes(error: unknown): unknown[]

Flattens an error's cause chain into an array, error first and the root cause last.

f
format(
error: unknown,
unnamed 1?: { stacks?: boolean; }
): string

Renders an error and its whole cause chain as indented, human-readable lines.

f
from(thrown: unknown): Any

Coerces any caught value into a Failure, leaving existing Failures untouched.

f
fromJSON(json: SerializedFailure): Any

Revives a SerializedFailure into a real Failure, reconstructing the cause chain.

f
hasCode<Codes extends readonly string[]>(
value: unknown,
...codes: Codes
): value is Failure<Codes[number], unknown>

Narrows a Failure to one of several codes — the multi-code sibling of Factory.is.

f
ignore(context: string): (error: unknown) => void

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.

f
is(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
isFactory(value: unknown): value is FailureFactory<string, never>

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.

f
isFailure(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
observed(failure: Any): void

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.

f
onIgnored(observer: IgnoredObserver | null): void

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.

f
onObserved(observer: ObservedObserver | null): void

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.

f
rootCause(error: unknown): unknown

The deepest cause in the chain — the original failure, whatever wrapped it since.

f
setDebug(enabled: boolean): void

Toggles ignored-failure reporting at runtime, overriding the QUNITX_DEBUG default.

f
toJSON(error: unknown): SerializedFailure

Converts a Failure (or any error) into plain JSON.

Interfaces

I
DefineOptions

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.

I
FailureFactory

A callable failure constructor produced by define(), carrying its own type guard.

I
FailureOptions

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.

I
SerializedFailure

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 toJSON so it cannot fail later.

  • failure: true

    Wire marker. Symbol.for keys survive neither JSON.stringify nor structuredClone, 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 if stack was never set.

Type Aliases

T
Any = Failure<string, unknown>

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.

T
IgnoredObserver = (
context: string,
error: unknown
) => void

The callback shape onIgnored installs: every ignored failure arrives with the label its call site declared.

T
ObservedObserver = (failure: Any) => void

The callback shape onObserved installs: every declared failure a consumer classified arrives right as it is handed to application code.

T
Of<F> = F extends FailureFactory<infer Code, infer Data> ? Failure<Code, Data> : never

The Failure type a factory produces: Failure.Of<typeof FileMissing>.

T
TraceAttributes = Record<string, string | number | boolean>

The attribute primitives tracing systems accept (OpenTelemetry's span-attribute values) — what a trace mapper returns and attributes yields.

Variables

v
IGNORED_CHANNEL_NAME: "qunitx.failure.ignored"

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.

v
OBSERVED_CHANNEL_NAME: "qunitx.failure.observed"

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:

v
Unknown: FailureFactory<"Unknown", { thrown: unknown; }>

The failure from() produces for a throwable that is not already a Failure.

lib/result/index.ts

Classes

c
Failure.Failure<Code extends string = string, Data = unknown>(
code: Code,
message: string,
data: Data,
options?: FailureOptions
)

A structured, discriminable error.

Functions

f
all<O>(outcomes: ReadonlyArray<O>): Result<Exclude<O, Any>[], Extract<O, Any>>

Collects an array of outcomes into an array of values, short-circuiting on the first failure — the Result-shaped analogue of Promise.all.

f
expect<O>(
outcome: O,
message: string
): Exclude<O, Any>

Returns the success value, or throws new Error(message, { cause: failure }).

f
Failure.attributes(failure: Any): TraceAttributes

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.

f
Failure.causes(error: unknown): unknown[]

Flattens an error's cause chain into an array, error first and the root cause last.

f
Failure.format(
error: unknown,
unnamed 1?: { stacks?: boolean; }
): string

Renders an error and its whole cause chain as indented, human-readable lines.

f
Failure.from(thrown: unknown): Any

Coerces any caught value into a Failure, leaving existing Failures untouched.

f
Failure.fromJSON(json: SerializedFailure): Any

Revives a SerializedFailure into a real Failure, reconstructing the cause chain.

f
Failure.hasCode<Codes extends readonly string[]>(
value: unknown,
...codes: Codes
): value is Failure<Codes[number], unknown>

Narrows a Failure to one of several codes — the multi-code sibling of Factory.is.

f
Failure.ignore(context: string): (error: unknown) => void

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.

f
Failure.is(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.is(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.isFactory(value: unknown): value is FailureFactory<string, never>

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.

f
Failure.isFailure(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.isFailure(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.observed(failure: Any): void

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.

f
Failure.onIgnored(observer: IgnoredObserver | null): void

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.

f
Failure.onObserved(observer: ObservedObserver | null): void

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.

f
Failure.rootCause(error: unknown): unknown

The deepest cause in the chain — the original failure, whatever wrapped it since.

f
Failure.setDebug(enabled: boolean): void

Toggles ignored-failure reporting at runtime, overriding the QUNITX_DEBUG default.

f
Failure.toJSON(error: unknown): SerializedFailure

Converts a Failure (or any error) into plain JSON.

f
isErrno(
value: unknown,
...codes: string[]
): value is ErrnoError

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).

f
partition<O>(outcomes: ReadonlyArray<O>): { values: Exclude<O, Any>[]; errors: Extract<O, Any>[]; }

Splits outcomes into their successes and their failures, keeping both.

f
rescue<T, F extends Any, A extends readonly unknown[]>(
fn: (...args: A) => T,
classify: (cause: unknown) => F,
...args: A
): Rescued<T, F>

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.

f
tryCatch<T, A extends readonly unknown[]>(
fn: (...args: A) => T,
...args: A
): Tried<T>

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.

f
tryCatch<T, A extends readonly unknown[]>(
fn: (...args: A) => T,
...args: A
): Tried<T>

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.

f
unwrap<O>(outcome: O): Exclude<O, Any>

Returns the success value, or throws the failure.

f
unwrapOr<O, U>(
outcome: O,
fallback: U
): Exclude<O, Any> | U

Returns the success value, or fallback if the outcome is a failure.

Interfaces

I
ErrnoError

Minimal shape of a Node system error, declared locally so this module stays runtime-free.

I
Failure.DefineOptions

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.

I
Failure.FailureFactory

A callable failure constructor produced by define(), carrying its own type guard.

I
Failure.FailureOptions

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.

I
Failure.SerializedFailure

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 toJSON so it cannot fail later.

  • failure: true

    Wire marker. Symbol.for keys survive neither JSON.stringify nor structuredClone, 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 if stack was never set.

Namespaces

N
Failure

Structured, discriminable errors — the E half of Result<T, E>.

Type Aliases

T
Caught<T, E = unknown> = Ok<T> | Err<E>

What the boundary hands back: the value, or whatever was caught — unknown, honestly, because a catch binding is exactly as untrustworthy.

T
Failure.Any = Failure<string, unknown>

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.

T
Failure.IgnoredObserver = (
context: string,
error: unknown
) => void

The callback shape onIgnored installs: every ignored failure arrives with the label its call site declared.

T
Failure.ObservedObserver = (failure: Any) => void

The callback shape onObserved installs: every declared failure a consumer classified arrives right as it is handed to application code.

T
Failure.Of<F> = F extends FailureFactory<infer Code, infer Data> ? Failure<Code, Data> : never

The Failure type a factory produces: Failure.Of<typeof FileMissing>.

T
Failure.TraceAttributes = Record<string, string | number | boolean>

The attribute primitives tracing systems accept (OpenTelemetry's span-attribute values) — what a trace mapper returns and attributes yields.

T
Ok<T> = { readonly ok: true; readonly value: T; readonly error?: undefined; }

The success variant of a caught outcome. error is present-but-undefined for shape stability.

T
Rescued<T, F> = 0 extends 1 & T ? unknown : [T] extends [PromiseLike<unknown>] ? Promise<Awaited<T> | F> : T | F

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.

T
Result<T, E = Any> = T | E

The success value or a declared failure — a bare union, discriminated by the Failure brand.

Variables

v
Failure.IGNORED_CHANNEL_NAME: "qunitx.failure.ignored"

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.

v
Failure.OBSERVED_CHANNEL_NAME: "qunitx.failure.observed"

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:

v
Failure.Unknown: FailureFactory<"Unknown", { thrown: unknown; }>

The failure from() produces for a throwable that is not already a Failure.

lib/result/result.ts

Functions

f
all<O>(outcomes: ReadonlyArray<O>): Result<Exclude<O, Any>[], Extract<O, Any>>

Collects an array of outcomes into an array of values, short-circuiting on the first failure — the Result-shaped analogue of Promise.all.

f
expect<O>(
outcome: O,
message: string
): Exclude<O, Any>

Returns the success value, or throws new Error(message, { cause: failure }).

f
partition<O>(outcomes: ReadonlyArray<O>): { values: Exclude<O, Any>[]; errors: Extract<O, Any>[]; }

Splits outcomes into their successes and their failures, keeping both.

f
unwrap<O>(outcome: O): Exclude<O, Any>

Returns the success value, or throws the failure.

f
unwrapOr<O, U>(
outcome: O,
fallback: U
): Exclude<O, Any> | U

Returns the success value, or fallback if the outcome is a failure.

Type Aliases

T
Result<T, E = Any> = T | E

The success value or a declared failure — a bare union, discriminated by the Failure brand.

lib/result/try.ts

Functions

f
isErrno(
value: unknown,
...codes: string[]
): value is ErrnoError

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).

f
rescue<T, F extends Any, A extends readonly unknown[]>(
fn: (...args: A) => T,
classify: (cause: unknown) => F,
...args: A
): Rescued<T, F>

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.

f
tryCatch<T, A extends readonly unknown[]>(
fn: (...args: A) => T,
...args: A
): Tried<T>

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.

Interfaces

I
ErrnoError

Minimal shape of a Node system error, declared locally so this module stays runtime-free.

Type Aliases

T
Caught<T, E = unknown> = Ok<T> | Err<E>

What the boundary hands back: the value, or whatever was caught — unknown, honestly, because a catch binding is exactly as untrustworthy.

T
Ok<T> = { readonly ok: true; readonly value: T; readonly error?: undefined; }

The success variant of a caught outcome. error is present-but-undefined for shape stability.

T
Rescued<T, F> = 0 extends 1 & T ? unknown : [T] extends [PromiseLike<unknown>] ? Promise<Awaited<T> | F> : T | F

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.

lib/selection/filter.ts

Functions

f
buildQUnitFilterQuery(config: FilterConfig): string

Builds the ?filter=… query that carries the test filter (-t/--filter/-m/--module) into the page.

f
describeActiveFilters(config: FilterConfig): string

Human-readable description of the active filters, for the "nothing matched" message.

f
isFilteredRun(config: FilterConfig): boolean

True when this run selects a subset of the tests inside the files it loads.

Type Aliases

lib/selection/line-targets.ts

Functions

f
selectorsFromScan(
scan: DeclarationScan,
lines: number[],
displayPath: string
): LineTargetResolution

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.

Interfaces

I
LineTargetResolution

Result of resolving a file's line targets into selectors, plus any diagnostics to surface.

I
QUnitSelector

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.

lib/selection/parse-test-declarations.ts

Functions

f
parseTestDeclarations(
source: string,
filePath: string
): Promise<DeclarationScan | null>

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?".

Interfaces

I
DeclarationScan

Every declaration found in a file, plus whether it uses only().

I
TestDeclaration

A test(...) or module(...) call found in a test file, in 1-based source lines.

lib/selection/qunit-matcher.ts

Functions

f
buildQUnitFullName(
modulePath: string,
testName: string
): string

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.

f
matchQUnitFilter(
filter: string | undefined,
fullName: string
): boolean

True when filter selects fullName, using QUnit's semantics:

lib/setup/browser.ts

Functions

f
launch(
config: LaunchTarget,
skipPrelaunch?: boolean
): Promise<Browser>

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]).

f
setup(
config: Config,
existingBrowser?: Browser | null,
sharedServer?: HTTPServer | null
): Promise<Connections>

Launches a Playwright browser (or reuses an existing one), starts the web server, and returns the page/server/browser connection object.

Interfaces

I
LaunchTarget

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.

lib/setup/config.ts

Functions

f
setup(options?: ConfigOptions): Task<Config, ConfigFailure>

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.

Interfaces

I
ConfigOptions

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; pass silentConsole for a run that prints nothing at all. Named apart from output — 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/junit would 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.

Type Aliases

Variables

lib/setup/file-watcher.ts

Functions

f
handleWatchEvent(
config: Config,
extensions: string[],
event: string,
filePath: string,
onEventFunc: (
event: string,
file: string
) => unknown
,
onFinishFunc: ((
path: string,
event: string
) => void) | null | undefined
): Promise<void>

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).

f
mutateFSTree(
fsTree: FSTree,
event: string,
filePath: string
): void

Mutates fsTree in place based on a file-system event.

f
readFileStable(
filePath: string,
read?: (p: string) => Promise<Buffer>
): Promise<Buffer>

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.

f
rescanDirectoryForDelta(
watchPath: string,
config: Config,
extensions: string[],
onEventFunc: (
event: string,
file: string
) => unknown
,
onFinishFunc: ((
path: string,
event: string
) => void) | null | undefined
,
trackSymlinkFn?: (filePath: string) => void,
deps?: RescanDeps
): Promise<void>

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.

f
setup(
testFileLookupPaths: string[],
config: Config,
onEventFunc: (
event: string,
file: string
) => unknown
,
onFinishFunc: ((
path: string,
event: string
) => void) | null | undefined
): { fileWatchers: Record<string, FSWatcher>; killFileWatchers: () => Record<string, FSWatcher>; ready: Promise<void>; }

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.

f
toWatchableRoot(lookupPath: string): string

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).

Interfaces

I
RescanDeps

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.

lib/setup/fs-tree.ts

Functions

f
build(
fileAbsolutePaths: string[],
config?: { extensions?: string[]; }
): Task<FSTree, InputUnreadableFailure>

Resolves an array of file paths, directories, or glob patterns into a flat { absolutePath: null } map.

Type Aliases

Variables

v
InputUnreadable: Failure.FailureFactory<"InputUnreadable", { input: string; }>

One of the configured test inputs could not be globbed, stat'd or walked.

lib/setup/get-changed-fs-tree.ts

Functions

f
getChangedFsTree(
fsTree: FSTree,
config: Config,
changedSince: string,
getChanged?: getChangedFilePathsInGitSince
): Promise<FSTree>

Returns a new fsTree containing only the test files affected by changes since ref, per the cached esbuild metafile's reverse-dependency graph.

lib/setup/keyboard-events.ts

Functions

f
setup(session: WatchSession): void

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.

lib/setup/qunitx-runtime-plugin.ts

Functions

f
qunitxRuntimePlugin(cwd?: string): Plugin

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.

lib/setup/run-state.ts

Functions

f
clearBundles(build: BuildState): void

Invalidates a group's compiled bundles so the next run rebuilds them from disk.

f
create(): RunState

Fresh run state for a single qunitx invocation. Built once per run in Config.setup().

f
newGroup(
index?: number,
selectors?: QUnitSelector[]
): GroupState

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.

f
requestAbort(state: RunState): void

Asks every live server to tell its pages to drop the rest of the QUnit queue, and records that this run was cut short.

f
reset(
results: RunResults,
coverageEnabled: boolean
): void

Clears the run accumulators in place for a re-run.

f
reusablePageSlot(state: RunState): { page: Page | null; } | null

The daemon's reusable Page slot, or null when reuse does not apply.

lib/setup/test-file-paths.ts

Functions

f
setup(inputs: string[]): string[]

Deduplicates a list of file, folder, and glob inputs so that more-specific paths covered by broader ones are removed.

lib/setup/web-server.ts

Functions

f
buildErrorHTML(buildError: { type: string; formatted: string; }): string

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).

f
buildNoTestsHTML(files: string[]): string

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.

f
registerGroupRoutes(
server: HTTPServer,
groupConfig: Config
): void

Registers HTML and JS bundle routes for one concurrent group on a shared HTTPServer. Routes: GET /group-${groupId}/ and GET /group-${groupId}/tests.js.

f
registerSharedStaticHandler(
server: HTTPServer,
groupConfigs: Config[]
): void

Registers a GET /* wildcard handler on a shared HTTPServer that serves static assets from each group's output directory, routing by /group-{id}/ URL prefix.

f
setup(config: Config): HTTPServer

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.

f
setupGroupWSHandler(
server: HTTPServer,
groupConfigs: Config[]
): void

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.

f
testRuntimeSource(
config: Config,
groupId?: number
): string

The same runtime as bare JavaScript, for a page that injects it rather than serving it.

f
testRuntimeToInject(
config: Config,
groupId?: number
): string

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.

Variables

lib/setup/write-output-static-files.ts

Functions

f
writeOutputStaticFiles(
unnamed 0: { projectRoot: string; output: string; },
htmlAssets: HtmlAssets
): Promise<void>

Copies static HTML files and referenced assets from the project into the configured output directory.

lib/stream/index.ts

Classes

c
Failure.Failure<Code extends string = string, Data = unknown>(
code: Code,
message: string,
data: Data,
options?: FailureOptions
)

A structured, discriminable error.

Functions

f
Failure.attributes(failure: Any): TraceAttributes

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.

f
Failure.causes(error: unknown): unknown[]

Flattens an error's cause chain into an array, error first and the root cause last.

f
Failure.format(
error: unknown,
unnamed 1?: { stacks?: boolean; }
): string

Renders an error and its whole cause chain as indented, human-readable lines.

f
Failure.from(thrown: unknown): Any

Coerces any caught value into a Failure, leaving existing Failures untouched.

f
Failure.fromJSON(json: SerializedFailure): Any

Revives a SerializedFailure into a real Failure, reconstructing the cause chain.

f
Failure.hasCode<Codes extends readonly string[]>(
value: unknown,
...codes: Codes
): value is Failure<Codes[number], unknown>

Narrows a Failure to one of several codes — the multi-code sibling of Factory.is.

f
Failure.ignore(context: string): (error: unknown) => void

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.

f
Failure.is(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.is(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.isFactory(value: unknown): value is FailureFactory<string, never>

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.

f
Failure.isFailure(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.isFailure(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.observed(failure: Any): void

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.

f
Failure.onIgnored(observer: IgnoredObserver | null): void

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.

f
Failure.onObserved(observer: ObservedObserver | null): void

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.

f
Failure.rootCause(error: unknown): unknown

The deepest cause in the chain — the original failure, whatever wrapped it since.

f
Failure.setDebug(enabled: boolean): void

Toggles ignored-failure reporting at runtime, overriding the QUNITX_DEBUG default.

f
Failure.toJSON(error: unknown): SerializedFailure

Converts a Failure (or any error) into plain JSON.

Interfaces

I
Channel

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. 0 unless a consumer fell behind.

  • emit(value: T): boolean

    Offers a value. Returns false when there is no room left — Node's write() 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.

I
ChannelOptions

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: (
    dropped: T | E,
    buffered: number
    ) => void

    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 fail or abort.

  • overflow: Overflow

    What to do once capacity is reached: drop from either end, or 'fail' — end the stream with a ChannelOverflowFailure element instead of losing anything quietly. Default 'dropOldest'.

I
Failure.DefineOptions

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.

I
Failure.FailureFactory

A callable failure constructor produced by define(), carrying its own type guard.

I
Failure.FailureOptions

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.

I
Failure.SerializedFailure

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 toJSON so it cannot fail later.

  • failure: true

    Wire marker. Symbol.for keys survive neither JSON.stringify nor structuredClone, 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 if stack was never set.

Namespaces

N
Failure

Structured, discriminable failures — the E elements of a Stream.

Type Aliases

T
ChannelOverflowFailure = Of<ChannelOverflow>

The failure element a 'fail' channel ends with.

T
Failure.Any = Failure<string, unknown>

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.

T
Failure.IgnoredObserver = (
context: string,
error: unknown
) => void

The callback shape onIgnored installs: every ignored failure arrives with the label its call site declared.

T
Failure.ObservedObserver = (failure: Any) => void

The callback shape onObserved installs: every declared failure a consumer classified arrives right as it is handed to application code.

T
Failure.Of<F> = F extends FailureFactory<infer Code, infer Data> ? Failure<Code, Data> : never

The Failure type a factory produces: Failure.Of<typeof FileMissing>.

T
Failure.TraceAttributes = Record<string, string | number | boolean>

The attribute primitives tracing systems accept (OpenTelemetry's span-attribute values) — what a trace mapper returns and attributes yields.

T
Overflow = "dropOldest" | "dropNewest" | "fail"

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.

T
Source<T> = AsyncIterable<T> | Iterable<T>

Anything a Stream can be built from or flattened into: sync or async iterables (a web ReadableStream is async-iterable on every modern runtime).

Variables

v
ChannelOverflow: FailureFactory<"ChannelOverflow", { capacity: number; }>

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.

v
Failure.IGNORED_CHANNEL_NAME: "qunitx.failure.ignored"

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.

v
Failure.OBSERVED_CHANNEL_NAME: "qunitx.failure.observed"

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:

v
Failure.Unknown: FailureFactory<"Unknown", { thrown: unknown; }>

The failure from() produces for a throwable that is not already a Failure.

v
T
Stream

The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only entry points — there is no public constructor and no call form.

v
T
Stream

The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only entry points — there is no public constructor and no call form.

v
T
Task: TaskConstructor

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.

v
T
Task: TaskConstructor

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.

lib/stream/stream.ts

Classes

Interfaces

I
Channel

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. 0 unless a consumer fell behind.

  • emit(value: T): boolean

    Offers a value. Returns false when there is no room left — Node's write() 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.

I
ChannelOptions

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: (
    dropped: T | E,
    buffered: number
    ) => void

    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 fail or abort.

  • overflow: Overflow

    What to do once capacity is reached: drop from either end, or 'fail' — end the stream with a ChannelOverflowFailure element instead of losing anything quietly. Default 'dropOldest'.

Type Aliases

T
ChannelOverflowFailure = Of<ChannelOverflow>

The failure element a 'fail' channel ends with.

T
Overflow = "dropOldest" | "dropNewest" | "fail"

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.

T
Source<T> = AsyncIterable<T> | Iterable<T>

Anything a Stream can be built from or flattened into: sync or async iterables (a web ReadableStream is async-iterable on every modern runtime).

Variables

v
ChannelOverflow: FailureFactory<"ChannelOverflow", { capacity: number; }>

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.

v
T
Stream

The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only entry points — there is no public constructor and no call form.

lib/tap/display-final-result.ts

Functions

f
displayFinalResult(
unnamed 0: Counter,
timeTaken: number,
output?: Console
): void

Prints the TAP plan line and test-run summary (total, pass, skip, fail, duration).

lib/tap/display-test-result.ts

Functions

f
displayTestResult(
testNumber: number,
details: TestDetails,
failures?: FailureInfo[],
output?: Console
): void

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.

lib/tap/dump-yaml.ts

Functions

f
dumpYaml(unnamed 0: { name: string; actual: unknown; expected: unknown; message: string | null; stack: string | null; source: string | null; at: string | null; }): string

Serializes the fixed TAP assertion object to a YAML string. Uses a template literal (no Object.entries overhead) for the known top-level keys.

lib/tap/index.ts

Functions

f
displayFinalResult(
unnamed 0: Counter,
timeTaken: number,
output?: Console
): void

Prints the TAP plan line and test-run summary (total, pass, skip, fail, duration).

f
displayTestResult(
testNumber: number,
details: TestDetails,
failures?: FailureInfo[],
output?: Console
): void

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.

f
dumpYaml(unnamed 0: { name: string; actual: unknown; expected: unknown; message: string | null; stack: string | null; source: string | null; at: string | null; }): string

Serializes the fixed TAP assertion object to a YAML string. Uses a template literal (no Object.entries overhead) for the known top-level keys.

lib/task/index.ts

Classes

c
Failure.Failure<Code extends string = string, Data = unknown>(
code: Code,
message: string,
data: Data,
options?: FailureOptions
)

A structured, discriminable error.

Functions

f
Failure.attributes(failure: Any): TraceAttributes

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.

f
Failure.causes(error: unknown): unknown[]

Flattens an error's cause chain into an array, error first and the root cause last.

f
Failure.format(
error: unknown,
unnamed 1?: { stacks?: boolean; }
): string

Renders an error and its whole cause chain as indented, human-readable lines.

f
Failure.from(thrown: unknown): Any

Coerces any caught value into a Failure, leaving existing Failures untouched.

f
Failure.fromJSON(json: SerializedFailure): Any

Revives a SerializedFailure into a real Failure, reconstructing the cause chain.

f
Failure.hasCode<Codes extends readonly string[]>(
value: unknown,
...codes: Codes
): value is Failure<Codes[number], unknown>

Narrows a Failure to one of several codes — the multi-code sibling of Factory.is.

f
Failure.ignore(context: string): (error: unknown) => void

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.

f
Failure.is(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.is(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.isFactory(value: unknown): value is FailureFactory<string, never>

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.

f
Failure.isFailure(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.isFailure(value: unknown): value is Any

Whether value is a Failure — from this realm or any other.

f
Failure.observed(failure: Any): void

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.

f
Failure.onIgnored(observer: IgnoredObserver | null): void

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.

f
Failure.onObserved(observer: ObservedObserver | null): void

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.

f
Failure.rootCause(error: unknown): unknown

The deepest cause in the chain — the original failure, whatever wrapped it since.

f
Failure.setDebug(enabled: boolean): void

Toggles ignored-failure reporting at runtime, overriding the QUNITX_DEBUG default.

f
Failure.toJSON(error: unknown): SerializedFailure

Converts a Failure (or any error) into plain JSON.

f
partition<O>(outcomes: ReadonlyArray<O>): { values: Exclude<O, Any>[]; errors: Extract<O, Any>[]; }

Splits outcomes into their successes and their failures, keeping both.

f
unwrap<O>(outcome: O): Exclude<O, Any>

Returns the success value, or throws the failure.

Interfaces

I
Failure.DefineOptions

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.

I
Failure.FailureFactory

A callable failure constructor produced by define(), carrying its own type guard.

I
Failure.FailureOptions

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.

I
Failure.SerializedFailure

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 toJSON so it cannot fail later.

  • failure: true

    Wire marker. Symbol.for keys survive neither JSON.stringify nor structuredClone, 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 if stack was never set.

Namespaces

N
Failure

Structured, discriminable failures — the rejection reason of a Task.

Type Aliases

T
Failure.Any = Failure<string, unknown>

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.

T
Failure.IgnoredObserver = (
context: string,
error: unknown
) => void

The callback shape onIgnored installs: every ignored failure arrives with the label its call site declared.

T
Failure.ObservedObserver = (failure: Any) => void

The callback shape onObserved installs: every declared failure a consumer classified arrives right as it is handed to application code.

T
Failure.Of<F> = F extends FailureFactory<infer Code, infer Data> ? Failure<Code, Data> : never

The Failure type a factory produces: Failure.Of<typeof FileMissing>.

T
Failure.TraceAttributes = Record<string, string | number | boolean>

The attribute primitives tracing systems accept (OpenTelemetry's span-attribute values) — what a trace mapper returns and attributes yields.

T
Result<T, E = Any> = T | E

The success value or a declared failure — a bare union, discriminated by the Failure brand.

Variables

v
AwaitTimeout: FailureFactory<"AwaitTimeout", { ms: number; }>

The deadline in TaskClass#await elapsed before the work settled.

v
Failure.IGNORED_CHANNEL_NAME: "qunitx.failure.ignored"

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.

v
Failure.OBSERVED_CHANNEL_NAME: "qunitx.failure.observed"

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:

v
Failure.Unknown: FailureFactory<"Unknown", { thrown: unknown; }>

The failure from() produces for a throwable that is not already a Failure.

v
T
Task: TaskConstructor

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.

v
T
Task: TaskConstructor

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.

lib/task/task.ts

Classes

Interfaces

I
RetryOptions

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 0 retries 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: (
    error: unknown,
    attempt: number
    ) => boolean

    Which failures are worth another attempt. Returning false rethrows immediately, spending no further attempts and no delay.

Type Aliases

T
Executor<T> = (
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason?: unknown) => void,
signal: AbortSignal
) => unknown

The new Promise shape, made lazy: settle imperatively through resolve/reject, with the Task's AbortSignal third.

T
Recipe<T> = () => T | PromiseLike<T>

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.

T
RetryDelay = number | ((attempt: number) => number)

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.

Variables

v
AwaitTimeout: FailureFactory<"AwaitTimeout", { ms: number; }>

The deadline in TaskClass#await elapsed before the work settled.

v
T
Task: TaskConstructor

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.

lib/types.ts

Interfaces

I
BuildError

An esbuild failure, captured for display on the run's error page.

I
BuildState

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.js route awaits this before serving, so Chrome can navigate concurrently while esbuild finishes. Cleared by run after the build settles.

  • allTestCode: Buffer | string | null

    Full test bundle source, or null before the first build completes.

  • fallbackPage: FallbackPage | null

    Replaces the normal test page for this run, or null when 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

    true if the most recent build ended in an esbuild error. Keeps state.watch.lastBuildEndMs pinned 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.ts before Chrome setup completes (initial run) or before run is called (reruns), so esbuild races navigation. Consumed and cleared by the first run() call.

I
ChromeHandle

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().

I
Config

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/--after hook paths. process.cwd() for the CLI; the JS API's cwd option otherwise. Distinct from projectRoot, which is wherever the nearest package.json sits — running from a subdirectory keeps that subdirectory's node_modules on 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 / --after hook surface — qunitx itself never reads it back. Hooks use it to register extra routes (mock APIs) before tests start.

I
Connections

Live handles for the three resources allocated at the start of a test run. Passed through the run pipeline and closed together on shutdown.

I
Counter

Running totals of test outcomes for a single test run. Mutated in place as TAP events arrive from the browser.

I
DaemonState

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 through RunState.reusablePageSlot(), never directly — reuse is only valid for single-group runs.

I
EarlyChrome

A ChromeHandle plus the CDP endpoint, resolved once Chrome is listening.

I
EsbuildCache

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.

I
FileCoverage

Per-source-file line coverage, accumulated across every executed bundle. Keyed by absolute source path. Lines are 1-based, matching editor/lcov conventions.

I
GroupState

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

    true while running as one of several concurrent groups.

  • index: number

    Index within the run's group array; 0 for 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 via QUnit.config.testFilter, which QUnit ANDs after filter/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 testEnd arrivals 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.setup call. > 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).

I
HtmlAssets

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.

I
JUnitCase

One collected JUnit <testcase> — accumulated per testEnd and serialized into junit.xml at run end when --reporter=junit is active.

I
QUnitResult

The run summary the browser-side runtime publishes on window.QUNIT_RESULT.

I
RunGroup

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 on output.

  • output: string

    Absolute path of this group's build output directory.

I
RunResults

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 aborted signal. 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 coverage is enabled; null when it is off. Reassigned only by RunState.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.

I
RunSignals

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.

I
RunState

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 aborted signal all go through.

  • console: Console

    Where this run's text goes: the TAP document, every reporter line, every # diagnostic and every forwarded page log. processConsole for the CLI, silentConsole for 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 RunState is 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 RunResult reports. Assigned once per run alongside groupCount and 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 buildCachedContent before 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.create in Config.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.

I
WatchState

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

    true while 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 → ms of 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. 0 before the first build.

  • pendingBuildTrigger: (() => void) | null

    Queued build-trigger callback; fires once the in-progress build completes.

Type Aliases

T
CoverageFileMap = Map<string, FileCoverage>

Absolute source path → its accumulated FileCoverage.

T
FallbackPage =
{ kind: "build-error"; error: BuildError; }
| { 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).

T
FSTree = Record<string, null>

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.

lib/utils/borrowed-globals.ts

Functions

f
borrowArgv(argv: string[]): Disposable

Replaces process.argv for the scope and restores the previous value on exit.

f
borrowEnv(overrides: Record<string, string | undefined>): Disposable

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.

lib/utils/close-with-grace.ts

Functions

f
closeWithGrace(
closes: Readonly<Record<string, Promise<unknown> | null | undefined>>,
graceMs?: number
): Promise<Abandoned>

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.

Interfaces

I
Abandoned

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.

Variables

v
CLEANUP_GRACE_MS: 10000

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.

lib/utils/color.ts

Functions

f
createColors(enabled: boolean)

Creates a set of ANSI color helpers with coloring enabled or disabled.

f
magenta(text?: string): string | MagentaReturn
2 overloads

ANSI magenta text. Call without arguments to chain: magenta().bold(text).

Interfaces

lib/utils/convert-to-pascal-case.ts

Functions

f
convertToPascalCase(str: string): string

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.

lib/utils/exit-on-signal.ts

Functions

f
exitOnSignal(unnamed 0?: { once?: (
signal: string,
handler: () => void
) => void
; exit?: (code: number) => void; }
): void

Turns a termination signal into an ordinary exit, so process.on('exit') handlers still run.

lib/utils/failure-cache.ts

Functions

f
build(config: Config): FailureCachePayload

Assembles the cache payload from the shared per-run failure slots on config.

f
filesToRerun(
projectRoot: string,
hasInputTargets: boolean,
fsTree: FSTree
): Promise<string[] | null>

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.

f
read(projectRoot: string): Task<FailureCachePayload | null, never>

Reads the failure cache; returns null on a missing file or any parse/shape error.

f
record(
config: Config,
details: FailedTestDetails
): void

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.

f
write(
projectRoot: string,
cache: FailureCachePayload
): Promise<void>

Writes the failure cache. Best-effort; callers fire-and-forget like Timings.persist.

Interfaces

I
FailedTestRecord

One failed test, kept for display and future -t (test-name filter) wiring.

I
FailureCachePayload

On-disk shape of tmp/.qunitx-last-failures.json.

lib/utils/find-internal-assets-from-html.ts

Functions

f
findInternalAssetsFromHTML(htmlContent: string): string[]

Parses an HTML string and returns all internal (non-absolute-URL) <script src> and <link href> paths.

lib/utils/find-project-root.ts

Functions

f
findProjectRoot(cwd?: string): Task<string, ProjectRootNotFoundFailure>

Walks up from the working directory to the nearest package.json and resolves to its directory.

Type Aliases

T
ProjectRootNotFoundFailure = Failure.Of<ProjectRootNotFound>

The one failure findProjectRoot declares.

Variables

v
ProjectRootNotFound: Failure.FailureFactory<"ProjectRootNotFound", { cwd: string; }>

No package.json at or above the working directory, so there is no project to run in.

lib/utils/find-sidecar-esbuild.ts

Functions

f
findSidecarEsbuild(
execDir: string,
platform?: NodeJS.Platform
): string | null

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.

lib/utils/get-changed-file-paths-in-git-since.ts

Functions

f
getChangedFilePathsInGitSince(
projectRoot: string,
ref: string,
timeoutMs?
): Task<ChangeScan, GitScanFailure>

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.

f
runGit(
args: string[],
cwd: string,
timeoutMs?,
command?: string
): Task<string>

Runs one git command with a hard upper bound on how long it can take.

Type Aliases

T
GitScanFailure = Failure.Of<GitScanFailed>

The failure a git-change scan declares — the E of its Task, the Err of .result().

Variables

v
BLAST_RADIUS_FILES: Set

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.

v
BLAST_RADIUS_PATTERNS: RegExp[]

Basename regexes with the same blast-radius semantics. Currently catches tsconfig.json and editor variants like tsconfig.test.json / tsconfig.build.json.

v
GIT_TIMEOUT_MS: 30000

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.

v
GitScanFailed

git could not answer: not a repo, unknown ref, git missing, or it exceeded timeoutMs.

lib/utils/get-changed-files.ts

Functions

f
getChangedFiles(
metafile: AffectedMetafile,
esbuildCwd: string,
changedAbsPaths: ReadonlySet<string>,
testFiles: readonly string[]
): Set<string>

Returns the subset of testFiles (absolute paths) whose transitive imports, per the cached esbuild metafile, include any file in changedAbsPaths.

Interfaces

I
AffectedMetafile

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.

lib/utils/html.ts

Functions

f
findScriptPlaceholder(html: string): string | undefined

Returns the explicit {{qunitxScript}} placeholder when it exists in the template.

f
injectScript(
html: string,
content: string
): string

Injects the qunitx runner script block into a dynamic HTML template.

f
isCustomTemplate(html: string): boolean

Reports whether an HTML template looks dynamic enough to act as a custom runner template.

lib/utils/indent-string.ts

Functions

f
indentString(
string: string,
count?: number,
options?: { indent?: string; includeEmptyLines?: boolean; }
): string

Prepends count repetitions of indent (default: one space) to each non-empty line of string.

lib/utils/kill-process-group.ts

Functions

f
isTargetablePid(pid: number): boolean

Whether pid is safe to hand to a negated process.kill.

f
killProcessGroup(pid: number): void

Sends SIGKILL to a process and its entire process group. Requires the target to have been spawned with detached: true so that PGID === pid.

lib/utils/listen-to-keyboard-key.ts

Functions

f
listenToKeyboardKey(
inputString: string,
closure: (input: string) => void,
options?: { caseSensitive: boolean; }
): void

Registers a stdin listener that fires closure when the user types inputString (case-insensitive by default).

lib/utils/metafile-cache.ts

Functions

f
path(projectRoot: string): string

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."

f
read(projectRoot: string): Task<MetafileCachePayload | null, never>

Reads the cached metafile. Returns null on miss or corruption.

f
write(
projectRoot: string,
esbuildCwd: string,
metafile: AffectedMetafile
): Promise<void>

Best-effort write; failures are swallowed because a cache miss on the next read just degrades to "run all tests."

Interfaces

I
MetafileCachePayload

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/).

lib/utils/open-output-in-browser.ts

Functions

f
openOutputInBrowser(config: Config): Task<void, never>

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').

lib/utils/path-exists.ts

Functions

f
pathExists(path: string): Task<boolean, never>

Returns true if the given filesystem path is accessible, false otherwise.

lib/utils/perf-log.ts

Functions

f
perfLog(
label: string,
...details: unknown[]
): void

Writes a timestamped perf trace line to stderr when --trace-perf is active.

lib/utils/read-template.ts

Functions

f
readTemplate(relativePath: string): Promise<string>

Reads a template file by relative path. Two runtimes to satisfy:

lib/utils/run-user-module.ts

Functions

f
isDenoCompiledBinary(
hasDeno?: boolean,
execPath?: string
): boolean

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.

f

Type Aliases

T
UserScriptFailedFailure = Failure.Of<UserScriptFailed>

The one failure runUserModule declares.

Variables

v
UserScriptFailed

A user-supplied --before/--after script threw, or could not be imported.

lib/utils/search-in-parent-directories.ts

Functions

f
searchInParentDirectories(
directory: string,
targetEntry: string
): Promise<string | undefined>

Recursively searches directory and its ancestors for a file or folder named targetEntry; returns the absolute path or undefined.

lib/utils/source-map.ts

Functions

f
decodeMappings(mappings: string): Segment[][]

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).

f
extractInline(
bundle: ArrayBufferView | string | null,
outDir: string
): SourceMapDecoder | null

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.

f
isBundleUrl(url: string): boolean

Returns true when url points to a test bundle (/tests.js or /filtered-tests.js) served by the local HTTP server.

f
lookupPosition(
decoder: SourceMapDecoder,
generatedLine: number,
generatedCol: number
):
{ absolutePath: string; line: number; col: number; sourceText: string | null; }
| 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.

f
parse(
json: string,
outDir: string
): SourceMapDecoder

Parses a source-map V3 JSON string into a SourceMapDecoder ready for position lookup.

f
parseFrameLocation(text: string): { url: string; line: number; col: number; } | null

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.

f
readVLQ(
text: string,
position: number
): [number, number]

Reads one VLQ-encoded integer from text starting at position. Returns [decodedValue, positionAfterLastConsumedChar].

f
resolveFrame(
frame: string,
decoder: SourceMapDecoder,
projectRoot: string
):
{ resolved: string; userPath: string | null; sourceText: string | null; }
| 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.

f
sourceAbsolutePath(
decoder: SourceMapDecoder,
sourceIndex: number
): string | null

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.

Interfaces

I
Segment

One decoded mapping entry. All coordinates are 0-based.

I
SourceMapDecoder

Parsed representation of a source-map V3 JSON, ready for position lookup.

lib/utils/time-counter.ts

Functions

f
start(): { startTime: Date; stop: () => number; }

Returns a timer object with a startTime Date and a stop() method that returns elapsed milliseconds.

lib/web/index.ts

Classes

c
HTTPServer()

Minimal HTTP + WebSocket server used to serve test bundles and push reload events.

Interfaces

I
Request

The request a route handler receives: node's, plus the four conveniences this server attaches before dispatching.

I
Response

The response a route handler receives: node's, plus a JSON shorthand.

I
Route

One registered route: the parsed shape get()/post()/… store and #findRouteHandler matches against.

Type Aliases

T
Middleware = (
req: Request,
res: Response,
next: () => void
) => void

Middleware function signature — call next() to continue the chain.

T
RouteHandler = (
req: Request,
res: Response
) => unknown | Promise<unknown>

Route handler function signature for registered GET/POST/etc. routes.

Variables

v
MIME_TYPES: Record<string, string>

Map of file extensions to their corresponding MIME type strings.

README.md

qunitx-cli