tripwire

Test Support utilities, helpers, tools for testing in JavaScript and TypeScript.

View on GitHub

Runner Performance

Tripwire’s test runner is built to spend its time running tests rather than getting ready to. It builds one TypeScript Program per run and emits only the files the run actually loads; it answers --type-check with a checker walk over that same Program instead of a tsc child process; on the node target it caches the whole compile between runs so an unchanged tree compiles and type-checks nothing; and on the browser and worker targets it launches Chrome before it has even looked for test files, so the browser’s slow first navigation overlaps the compile. Measured on this repository’s own suites on 2026-10-18, and recorded in results/ (details and caveats in Measured): on the node target tripwire ran the 2,734-test core suite in 6.07 s against 9.13 s for ts-mocha, and the shim/chai suite in 1.06 s against 2.70 s; on the browser target 14.00 s against 19.42 s for karma on core, and 10.07 s against 11.19 s on shim/chai; on the worker target 12.57 s against 19.24 s, and 9.69 s against 10.98 s. Every browser and worker arm ran Chrome 155.0.8059.79, the build bundled with puppeteer 25.14.0, launched by puppeteer with no executable-path override. The compile cache took a type-checked core node run from 9.3 s with the cache off to 5.2 s over an unchanged tree, with the remaining time almost entirely the tests themselves. With coverage instrumentation on, tripwire’s own browser and worker coverage added 3.43 s (+24.5%) to the core browser run and 3.00 s (+23.9%) to the core worker run, while on the node target, where both runners sit under the same nyc wrapper, coverage added 3.49 s (+57.5%) to tripwire’s core run and 4.60 s (+50.4%) to mocha’s; tripwire stayed ahead of the alternate runner in all six instrumented comparisons.

What the runner does

The flags and config fields mentioned below are all documented in test-runner.md; this page explains what they are for and what they cost or save.

Node target

A first run. The runner resolves your tsconfig, matches the test globs and builds a single TypeScript Program for the project. That one Program is used for everything: when --type-check is on, ts.getPreEmitDiagnostics is asked of it, which is the checker walk and nothing else – no second parse, no second compile and no tsc child process. The same Program then backs a require hook, and each file is emitted individually, in memory, at the moment the run first requires it. Nothing is emitted up front and nothing is written next to your sources. A test project whose tsconfig covers more files than any one run loads (this repository’s test/tsconfig.test.json covers the node, browser and worker test directories together) pays the one-time parse for all of them but the emit for only the ones that load.

That is why --type-check costs so little relative to transpile-only: transpiling and type-checking are two questions asked of the same Program, which has to be built either way so that const enum values from dependencies resolve. On this repository’s suite the check moves work from the compile phase to the prep phase and lands within noise of the transpile-only total.

When the run ends, the compile cache (--emit-cache, on by default) records a manifest of the whole program – every source file it used, the roots it was built from, the compiler version and options, and the lock files that decide how imports resolve – together with the emitted output, in a cache directory inside the project’s node_modules (see compile caching for where, and for the no-node_modules fallback). It also records whether this run type-checked.

A repeat run over an unchanged tree. The runner verifies the manifest, which costs about 50 ms, finds that nothing changed, and reuses last run’s output. If last run type-checked cleanly, so has this one – same inputs, same verdict – so no Program is built and no checker runs. The run prints Compile cache: reused -- nothing changed, type-check skipped, and what remains is the tests. In the measurements below the type-check phase was 3501 ms with the cache off and 249-273 ms with it reused, and the whole run 9304 ms against 5168-5232 ms, of which about 4.6 s was the tests themselves. A run that only transpiled records that it did not check, so it can never let a later --type-check run skip checking on its behalf.

A run after an edit. Any change to any recorded input turns the whole cache over at once: the next run is a full one and prints Compile cache: rebuilt -- <the first thing found to have changed>, and the run after that is fast again. The coarseness is deliberate. A whole-program emit can inline a const enum member from another file, or elide an import whose binding turns out to be a type, so an unrelated-looking edit really can change what a file compiles to. Entries nothing has read for a week are swept, at most once a day, so an edit-and-run loop cannot grow the cache without bound, and the directory is always safe to delete.

Three further node-only options trade something for speed, and are off by default for that reason:

Browser and worker targets

The browser and worker targets never read or write the compile cache; they compile their module graph afresh on every run. What they optimise instead is the one thing that takes longer than the compile: starting the browser.

Chrome initialises its network stack on its first real navigation rather than at launch, and that first navigation is slow – around six seconds on Windows, against about twenty milliseconds for every one after it. Three things have to happen before the first test runs: Chrome must launch, Chrome must get that first-navigation initialisation over with, and the module graph must be built (about four seconds on this repository’s suite). They are independent, so the runner launches the browser before file discovery and sends it to a dead port before building the module graph, so the initialisation happens inside Chrome’s own process while the compile runs here. The run then takes as long as the slowest of the three rather than the sum. Nothing needs configuring, and a platform where the first navigation is already cheap simply sees the warm-up finish during the build.

The graph build itself follows the same discipline as the node path: one Program per tsconfig per process, cached and reused for every file in the graph, with per-file emit on demand for only the files reachable from the target’s entry points, and – under --type-check – a single checker walk over that Program at the moment it is created, with no second parse. By default (--bundle) the graph is then served to the browser as one concatenated bundle rather than one network request per module; --no-bundle switches to per-module requests, which is useful for debugging a single file but is not the fast path.

Coverage on these targets is part of the runner rather than a wrapper around it: --coverage instruments the module graph as it is built, explicitly loads the project’s own sources (--coverage-src, default src/**/*.ts) so that a file no test imported is still executed and counted rather than silently dropped, and writes coverage/<target>/coverage-final.json before running nyc report for each --coverage-reporter. Karma gets the equivalent only through plugins (karma-typescript’s instrumentation, or karma-coverage), and Mocha only through an external nyc wrapper. On the node target tripwire relies on that same external nyc wrapper (nyc node ./bin/tripwire.js ...), so the node-target coverage comparison in Measured: with coverage is nyc against nyc, and the overhead measured there is nyc’s on both sides.

--graph-thread moves the synchronous graph build onto a worker thread so the event loop stays free for the browser launch to settle. Measured, it is not a win: the build then competes for the CPU the browser needs to start, and the launch stretched from about 1.9 s to 3.5 s in exchange, with the main-thread build ahead in three interleaved A/B pairs. It is off by default and kept because that result is machine-specific.

One optimisation applies only to the interactive browser UI (--browser-launch open|manual), not to headless runs: the live results view used to re-apply its “Failed only” filter to every node in the tree on every status change and read the results list’s scroll position for every node added, both quadratic in the number of tests. On this repository’s ~2,700-test suite that blocked the main thread for seconds, delaying the timers the tests themselves were waiting on. The filter is now applied to just the changed test and its ancestors, and a batch of events reads and writes the scroll position once; the worst delay to a 5 ms timer during a run fell from seconds to ~100 ms, and the slowest test from ~5 s to ~0.8 s.

Mechanisms by target

Mechanism node browser / worker
One ts.Program per tsconfig per process, reused for every file yes yes
Per-file emit on demand, only for files the run loads yes (on require) yes (graph walk)
--type-check as a checker walk over that Program, no tsc process yes yes
Compile cache (--emit-cache, default on) yes no – never read or written
--type-check-scope run yes no – always the whole project
--isolated-transpile (opt-in) yes no
--incremental (opt-in, measured no benefit) yes no
Browser launched before file discovery; warm-up navigation overlaps graph build – yes
Graph served as one bundle (--bundle, default on) – yes
--graph-thread (opt-in, measured no benefit) – yes
Coverage external nyc wrapper (same as mocha) built in (--coverage, --coverage-src); karma needs karma-typescript / karma-coverage plugins
Live results view filter/scroll fix – interactive UI only

Measured

All numbers in this section were produced on the machine described under Machine on 2026-10-18 by the repository’s own benchmark harness, internal/benchmark, and are the two records it wrote with --record into docs/performance/results/:

The exception is the compile-cache table, which is the runner’s own console output rather than a harness arm. Nothing here is estimated or carried over from elsewhere; the records hold every individual duration in milliseconds, and the tables print them as the harness does, to two decimals.

The harness spawns each arm directly (not through npm run), discards its output, and times it with process.hrtime; “Avg”, “Median”, “Min” and “Max” are its own columns. Every arm was run once unmeasured (--warmup) and then three measured times (--runs=3); warmup durations are not in the records and are quoted from the console. All arms were type-checked. The three per-target tables immediately below are without coverage instrumentation; the whole matrix was then run a second time with --coverage, and those results are under Measured: with coverage. The tripwire and mocha arms are given each suite’s own test project and globs, byte-identical to its test:node script; the karma arms use the karma-only tsconfigs under internal/benchmark/tsconfig/, because karma-typescript’s bundler needs module: commonjs – see the harness README for exactly what is and is not held constant. The exact commands each arm ran are listed under Reproduce.

All twelve arms ran and exited zero, both without and with coverage; no arm failed and none was excluded.

Node target: tripwire vs mocha

Both runners were passed --type-check. core is 2,734 tests (2 skipped); shim/chai is the Chai compatibility shim’s suite.

Suite Runner Avg Median Min Max Runs Harness verdict
core tripwire 6.07 s 6.05 s 6.01 s 6.14 s 3 (+1 warmup)  
core mocha (ts-mocha) 9.13 s 9.28 s 8.79 s 9.31 s 3 (+1 warmup) tripwire faster by 33.5% (-3.06 s)
shim/chai tripwire 1.06 s 1.04 s 1.03 s 1.10 s 3 (+1 warmup)  
shim/chai mocha (ts-mocha) 2.70 s 2.72 s 2.64 s 2.75 s 3 (+1 warmup) tripwire faster by 60.9% (-1.65 s)

Individual measured runs: core tripwire 6.05 / 6.01 / 6.14 s; core mocha 9.28 / 9.31 / 8.79 s; chai tripwire 1.10 / 1.03 / 1.04 s; chai mocha 2.72 / 2.64 / 2.75 s. The unmeasured warmup runs were 5.71 s, 9.53 s, 1.09 s and 2.62 s respectively, and are not part of any statistic above.

The harness does not pass --no-emit-cache, so after the warmup every measured tripwire node run was a Compile cache: reused run; ts-mocha has no equivalent cache. That is the steady state a developer re-running a suite sees, but it means this table compares tripwire’s repeat run against mocha’s every run. For the uncached figure, see the compile-cache table: tripwire’s own clock put a type-checked core run with the cache off at 9.3 s.

Browser target: tripwire vs karma

Tripwire ran --target browser --type-check headless through puppeteer; karma ran karma start <conf> --single-run with karma-mocha, karma-typescript and karma-chrome-launcher. Both ran Chrome 155.0.8059.79, the build bundled with puppeteer 25.14.0, launched by puppeteer with no executable-path override (see Machine and Reproduce).

Suite Runner Avg Median Min Max Runs Harness verdict
core tripwire 14.00 s 13.60 s 13.39 s 15.01 s 3 (+1 warmup)  
core karma 19.42 s 19.37 s 19.28 s 19.61 s 3 (+1 warmup) tripwire faster by 27.9% (-5.42 s)
shim/chai tripwire 10.07 s 9.87 s 9.65 s 10.69 s 3 (+1 warmup)  
shim/chai karma 11.19 s 10.88 s 10.86 s 11.83 s 3 (+1 warmup) tripwire faster by 10.0% (-1.12 s)

Individual measured runs: core tripwire 15.01 / 13.39 / 13.60 s; core karma 19.37 / 19.28 / 19.61 s; chai tripwire 9.87 / 10.69 / 9.65 s; chai karma 11.83 / 10.86 / 10.88 s. Warmups: 11.97 s, 19.04 s, 9.15 s and 10.99 s respectively. The core tripwire arm’s first run (15.01 s) is 1.4 s above its other two, which is why its median (13.60 s) sits below its average.

Worker target: tripwire vs karma

Tripwire ran --target worker --type-check; karma ran its worker configs, which use the worker adapter in common/test/. Same browser build as the browser target.

Suite Runner Avg Median Min Max Runs Harness verdict
core tripwire 12.57 s 12.68 s 12.31 s 12.71 s 3 (+1 warmup)  
core karma 19.24 s 19.21 s 18.89 s 19.63 s 3 (+1 warmup) tripwire faster by 34.7% (-6.67 s)
shim/chai tripwire 9.69 s 9.59 s 9.49 s 10.00 s 3 (+1 warmup)  
shim/chai karma 10.98 s 10.54 s 10.03 s 12.38 s 3 (+1 warmup) tripwire faster by 11.8% (-1.29 s)

Individual measured runs: core tripwire 12.31 / 12.71 / 12.68 s; core karma 19.63 / 19.21 / 18.89 s; chai tripwire 10.00 / 9.59 / 9.49 s; chai karma 10.03 / 10.54 / 12.38 s. Warmups: 13.10 s, 19.55 s, 9.40 s and 10.49 s respectively. The shim/chai karma arm’s third run (12.38 s) is 1.8 s above its other two; on medians that comparison is 9.59 s against 10.54 s.

Measured: with coverage

The whole matrix was run a second time with the harness’s --coverage option, which instruments every arm at once so the comparison stays like for like. Same settings otherwise: --runs=3 --warmup, type-checked, the whole matrix in one invocation started after the uninstrumented one had finished. The harness labels these runs “instrumented”; the record is results/2026-10-18T193947-256efc4-coverage.json. How each arm was instrumented, read from the commands and configuration the harness resolved (npm run bench -- --list --coverage and internal/benchmark/karma/createConfig.js):

Arm Instrumentation
tripwire, node External: the whole CLI is wrapped in nyc --cache --reporter=json (the repository-root nyc), so nyc spawns a second Node process around tripwire
mocha, node External: the same nyc --cache --reporter=json wrapper around ts-mocha
tripwire, browser / worker Built in: the CLI’s own --coverage flag, with no wrapper or plugin
karma, browser / worker karma-typescript’s coverageOptions.instrumentation plus its karma-typescript reporter (json + text), switched on by TRIPWIRE_BENCH_COVERAGE=1 in the arm’s environment; off, the config leaves instrumentation: false and the reporter out

“Without” is the Avg from the matching table above; “With” is the Avg of the instrumented run. Overhead is With - Without, absolute and as a percentage of “Without”, computed from the two-decimal averages the harness printed, so the last digit carries up to 0.01 s of rounding.

Node target (both arms under nyc):

Suite Runner Without With coverage Overhead Harness verdict (instrumented)
core tripwire 6.07 s 9.56 s +3.49 s (+57.5%)  
core mocha (ts-mocha) 9.13 s 13.73 s +4.60 s (+50.4%) tripwire faster by 30.4% (-4.17 s)
shim/chai tripwire 1.06 s 1.98 s +0.92 s (+86.8%)  
shim/chai mocha (ts-mocha) 2.70 s 4.17 s +1.47 s (+54.4%) tripwire faster by 52.5% (-2.19 s)

Instrumented runs: core tripwire 9.77 / 9.51 / 9.41 s (median 9.51, warmup 9.75); core mocha 14.25 / 13.49 / 13.46 s (median 13.49, warmup 14.14); chai tripwire 1.96 / 2.01 / 1.98 s (median 1.98, warmup 1.99); chai mocha 4.03 / 4.29 / 4.19 s (median 4.19, warmup 3.88).

Browser target:

Suite Runner Without With coverage Overhead Harness verdict (instrumented)
core tripwire 14.00 s 17.43 s +3.43 s (+24.5%)  
core karma 19.42 s 20.33 s +0.91 s (+4.7%) tripwire faster by 14.3% (-2.90 s)
shim/chai tripwire 10.07 s 9.48 s -0.59 s (-5.9%)  
shim/chai karma 11.19 s 11.54 s +0.35 s (+3.1%) tripwire faster by 17.8% (-2.06 s)

Instrumented runs: core tripwire 17.50 / 17.49 / 17.31 s (median 17.49, warmup 16.82); core karma 21.29 / 20.72 / 18.98 s (median 20.72, warmup 20.86); chai tripwire 9.16 / 9.55 / 9.75 s (median 9.55, warmup 9.14); chai karma 11.23 / 11.45 / 11.94 s (median 11.45, warmup 10.64).

Worker target:

Suite Runner Without With coverage Overhead Harness verdict (instrumented)
core tripwire 12.57 s 15.57 s +3.00 s (+23.9%)  
core karma 19.24 s 20.81 s +1.57 s (+8.2%) tripwire faster by 25.2% (-5.24 s)
shim/chai tripwire 9.69 s 10.26 s +0.57 s (+5.9%)  
shim/chai karma 10.98 s 11.28 s +0.30 s (+2.7%) tripwire faster by 9.0% (-1.02 s)

Instrumented runs: core tripwire 14.71 / 16.11 / 15.89 s (median 15.89, warmup 14.73); core karma 20.47 / 21.32 / 20.64 s (median 20.64, warmup 18.90); chai tripwire 9.66 / 10.94 / 10.17 s (median 10.17, warmup 10.12); chai karma 10.96 / 11.44 / 11.43 s (median 11.43, warmup 9.87).

What the tables show, and no more than they show:

Compile cache: cold, warm and off

This table is not a harness arm and is not in the recorded results. It was run directly with the CLI from the core package directory in an earlier session on 2026-10-18, on the same machine, Node and core/bin/tripwire.js build as the recorded runs, with no other load on the machine. The command is the core-node-tripwire arm’s, without the harness’s -- --trace-uncaught. These are the runner’s own Total elapsed lines, whose clock starts after Node has loaded the CLI bundle, so they are not directly comparable with the harness wall times above (which include process start-up). All four runs reported 2734 passing 2 skipped and exited 0.

Run Flags Compile cache: line Type-check Total elapsed prep compile tests
1 --type-check reused -- nothing changed, type-check skipped 249 ms 5168 ms 274 ms 300 ms 4591 ms
2 --type-check reused -- nothing changed, type-check skipped 273 ms 5232 ms 298 ms 308 ms 4623 ms
3 --type-check reused -- nothing changed, type-check skipped 269 ms 5179 ms 295 ms 273 ms 4608 ms
4 --no-emit-cache --type-check (none printed – caching off) 3501 ms 9304 ms 3529 ms 1199 ms 4572 ms

“Type-check” is the Type-check completed in N ms line the runner prints; “prep”, “compile” and “tests” are the three components of the Total elapsed line. In runs 1-3 the TypeScript work (prep + compile) is 574 ms, 606 ms and 568 ms against 4728 ms in run 4; the tests themselves are 4.57-4.62 s in every run, and in the cached runs they are about 89% of the total.

All three cached runs reported reused rather than a first rebuilt: the harness’s node arms, which run the same command over the same tree, had already populated the cache minutes earlier, and nothing had changed since. This session therefore has no rebuilt run to show; run 4, with caching turned off, is its uncached figure, and the difference between it and runs 1-3 (about 4.1 s) is what the cache saves on this suite.

Caveats

Machine

   
Date 2026-10-18
OS Windows 11
CPU AMD Ryzen 9 5900X, 12 cores / 24 logical processors
Memory 128 GB
Node v20.19.5
puppeteer 25.14.0
Browser Chrome 155.0.8059.79, the build bundled with puppeteer 25.14.0, launched by puppeteer with no executable-path override – for the tripwire arms directly, and for the karma arms via the harness’s karma config, which asks puppeteer for the same executable
TypeScript 5.2.2 as resolved in internal/benchmark
karma / karma-typescript / ts-mocha / mocha / nyc 6.4.4 / 5.5.4 / 10.1.0 / 11.8.0 / 18.0.0 (karma, its plugins and ts-mocha are pinned; see the harness README)
tripwire 0.1.8, core/bin/tripwire.js as built from internal/runner at commit 256efc4 on branch nev21/testSuite (working tree dirty)
Records results/2026-10-18T193006-256efc4.json (uninstrumented) and results/2026-10-18T193947-256efc4-coverage.json (with coverage). Every row above is what those records carry in their machine and versions fields, the CPU core count aside (a record holds the 24 logical processors only)

Reproduce

The harness is internal/benchmark; npm run bench -- --list prints the resolved matrix and the exact command of every arm without running anything. The benchmark needs core/bin/tripwire.js to have been built (rush build), and needs the browser puppeteer bundles. Every browser and worker arm below ran Chrome 155.0.8059.79, the build bundled with puppeteer 25.14.0, launched by puppeteer with no executable-path override: the tripwire arms ask puppeteer for it directly, and the harness’s karma config (internal/benchmark/karma/createConfig.js) resolves require("puppeteer").executablePath() and hands karma-chrome-launcher the same executable. For that to hold, PUPPETEER_EXECUTABLE_PATH and CHROME_BIN must both be unset so puppeteer uses its own browser rather than a system one; if puppeteer’s cache is empty, node node_modules/puppeteer/install.mjs fetches it.

The tables under Measured are two complete runs of the twelve-arm matrix recorded with --record – one uninstrumented, one with --coverage – produced by exactly the two commands in Recording a run below, run one after the other so no arm competed with another for the CPU. The arms, as --list resolves them without coverage (<node> is the Node executable running the harness, and paths are shown relative to the repository root):

core-node-tripwire     (cwd core)      <node> core/bin/tripwire.js --type-check -p ./test/tsconfig.test.json ./test/src/!(browser|worker)/**/*.test.ts -- --trace-uncaught
core-node-mocha        (cwd core)      <node> common/temp/node_modules/ts-mocha/bin/ts-mocha --type-check -p ./test/tsconfig.test.json ./test/src/!(browser|worker)/**/*.test.ts --trace-uncaught
core-browser-tripwire  (cwd core)      <node> core/bin/tripwire.js --target browser --type-check -p ./test/tsconfig.test.json ./test/src/!(node|worker)/**/*.test.ts
core-browser-karma     (cwd benchmark) <node> common/temp/node_modules/karma/bin/karma start internal/benchmark/karma/core.browser.conf.js --single-run
core-worker-tripwire   (cwd core)      <node> core/bin/tripwire.js --target worker --type-check -p ./test/tsconfig.test.json ./test/src/!(node|browser)/**/*.test.ts
core-worker-karma      (cwd benchmark) <node> common/temp/node_modules/karma/bin/karma start internal/benchmark/karma/core.worker.conf.js --single-run
chai-node-tripwire     (cwd shim/chai) <node> core/bin/tripwire.js --type-check -p ./test/tsconfig.test.json ./test/src/!(browser|worker)/**/*.test.ts -- --trace-uncaught
chai-node-mocha        (cwd shim/chai) <node> common/temp/node_modules/ts-mocha/bin/ts-mocha --type-check -p ./test/tsconfig.test.json ./test/src/!(browser|worker)/**/*.test.ts --trace-uncaught
chai-browser-tripwire  (cwd shim/chai) <node> core/bin/tripwire.js --target browser --type-check -p ./test/tsconfig.test.json ./test/src/!(node|worker)/**/*.test.ts
chai-browser-karma     (cwd benchmark) <node> common/temp/node_modules/karma/bin/karma start internal/benchmark/karma/chai.browser.conf.js --single-run
chai-worker-tripwire   (cwd shim/chai) <node> core/bin/tripwire.js --target worker --type-check -p ./test/tsconfig.test.json ./test/src/!(node|browser)/**/*.test.ts
chai-worker-karma      (cwd benchmark) <node> common/temp/node_modules/karma/bin/karma start internal/benchmark/karma/chai.worker.conf.js --single-run

Under --coverage (npm run bench -- --list --coverage), the four node arms are prefixed with <node> node_modules/nyc/bin/nyc.js --cache --temp-dir internal/benchmark/.benchmark/nyc/<arm> --report-dir internal/benchmark/.benchmark/coverage/<arm> --reporter=json, the four tripwire browser/worker arms gain --coverage after --type-check, and the four karma commands are unchanged but run with TRIPWIRE_BENCH_COVERAGE=1 in their environment, which internal/benchmark/karma/createConfig.js turns into karma-typescript instrumentation and reporting.

The compile-cache table is not a harness arm. It came from the CLI directly, run from the core package directory in an earlier session on the same machine, with the same Node and the same core/bin/tripwire.js build:

cd core
# three times -- the first prints "rebuilt" if the cache is cold, the later ones "reused":
node ./bin/tripwire.js --type-check -p ./test/tsconfig.test.json "./test/src/!(browser|worker)/**/*.test.ts"
# once with the cache off:
node ./bin/tripwire.js --no-emit-cache --type-check -p ./test/tsconfig.test.json "./test/src/!(browser|worker)/**/*.test.ts"

Read the Compile cache:, Type-check completed in and Total elapsed: lines of each run. (In that session the cache was already warm from the harness’s node arms, so all three printed reused; to see a rebuilt first run, delete the cache directory named in compile caching first.)

Recording a run

Add --record to any benchmark command and the run is written, scrubbed, to docs/performance/results/<UTC date>T<hhmmss>-<commit>[-coverage].json, with the directory’s index.json rebuilt. The history page charts every record over time – per target, suite, runner and coverage setting – and lists the latest run, so the tables above can be read against what came before them. A record holds the measurements, options, commit, tool versions (including the Chrome build puppeteer resolved) and the machine class; it never holds a file-system path, a host or user name, or an OS build number, and validate.js checks the directory on every rush test. Commit the new file together with the index. The two commands that produce a complete pair of records, run one after the other:

npm run bench -- --runs=3 --warmup --record              # every arm, uninstrumented
npm run bench -- --runs=3 --warmup --coverage --record   # every arm, instrumented

What it does not do