Skip to content

Bun ​

This guide covers Bun 1.2.23 or newer. You need Node.js 22.12 or newer to run test-inventory and an existing JavaScript or TypeScript test suite. The scanner reads your source without executing your tests or starting a browser. These are minimum supported versions; CI comparisons list tested versions.

Choose another framework · Use an AI client

Install ​

sh
npm install --save-dev test-inventory

Scan your suite ​

Run from the folder containing your project's package.json:

sh
npx test-inventory --framework bun --pretty --output inventory.json

To select files explicitly, use quoted globs. This example matches the quote-gateway fixture used below; adjust the globs to your suite's layout:

sh
npx test-inventory "src/**/*.test.ts" "src/**/*.spec.ts" --framework bun --output inventory.json

The command replaces inventory.json once the new output is complete. It does not change your test files.

Check the result ​

Print the counts and diagnostics from the saved file:

sh
node -e "const i = require('./inventory.json'); console.log(i.summary); console.log(i.diagnostics)"

For matching tests, summary.fileCount and summary.testCount should be greater than zero. Review diagnostics even when the command exits with 0: errors can mean tests are missing. If the result is empty or unexpected, use troubleshooting.

The inventory describes source declarations, not execution results. Conditional skips are not proof that a run skipped the test. Loops and tables are one record by default; supported cases can be expanded with --expand-cases. Expected-to-fail tests execute and check for failure; they are not disabled tests.

Tests created by unreadable helpers can be missing without a diagnostic. A dependency hash does not prove complete coverage of runtime dependencies. Read the shared limits before using scans to make CI decisions.

Find skipped tests ​

sh
npx test-inventory --framework bun --state skip --fields fullName,state,condition,reason --pretty

This uses the same file selection as the first scan. If you supplied globs, --root or --framework-version, repeat those options here.

This selects source declarations marked skip; it is not a report of a test run. See query recipes for other inventory queries.

Example ​

quote-gateway tests a quote gateway with Bun's bun test, using Bun's own chains, as test.skipIf(condition), and a bunfig.toml that runs its routing specs at once.

Excerpt: toml
[test]
root = "src"
retry = 1
concurrentTestGlob = "**/routing/*.spec.ts"
sh
npx test-inventory "src/**/*.test.ts" "src/**/*.spec.ts" --framework bun --output inventory.json

Without the globs and --framework, the scan finds the same files from Bun's patterns under [test] root, and Bun from the test script. skipIf is a condition, and [test] retry applies to every test:

json
{
  "fullName": "spread > streams quotes from the venue",
  "state": "skip",
  "isConditional": true,
  "condition": "!process.env.VENUE_URL",
  "retries": 1
}

Bun parameterized tests ​

quote-gateway tests the same spread calculation with two rows of data:

Excerpt: ts
// src/quotes/spread.test.ts
test.each([
  { mic: 'XNAS', bid: 99.95, ask: 100.05 },
  { mic: 'XLON', bid: 49.9, ask: 50.1 },
])('quotes the $mic spread', ({ bid, ask }) => {
  expect(spreadBps({ bid, ask })).toBeGreaterThan(0);
});

First scan the declarations:

sh
npx test-inventory "src/**/*.test.ts" "src/**/*.spec.ts" --framework bun --pretty

The table is one record with two cases. This is an excerpt:

json
{
  "fullName": "spread > quotes the $mic spread",
  "caseCount": 2,
  "caseIndex": null
}

To list each resolvable case separately, add --expand-cases to the same scan:

sh
npx test-inventory "src/**/*.test.ts" "src/**/*.spec.ts" --framework bun --expand-cases --pretty

The table becomes two records with their substituted titles and zero-based indexes. These are record excerpts:

json
{
  "fullName": "spread > quotes the XNAS spread",
  "caseCount": 1,
  "caseIndex": 0
}
json
{
  "fullName": "spread > quotes the XLON spread",
  "caseCount": 1,
  "caseIndex": 1
}

Expansion follows the detected Bun version's title rules. If your project does not record its Bun version, pass --framework-version with the version you use to both commands. Unresolved data stays one record with a cases-not-expanded warning. See Bun's table syntax for the supported title formats. The scanner reads the table without running Bun or executing either test case.

Configuration and limits ​

The scan reads the root bunfig.toml [test] table. Without it, files have no config. Explicit globs count as files given to bun test. Supported settings include root, pathIgnorePatterns, concurrentTestGlob and, from Bun 1.3, retry. Invalid pattern settings are reported.

[test].preload files enter dependency hashes but are not executed. A focused test can make Bun omit other tests from its run report; the inventory keeps all declarations and their isOnly flags. Run the scanner with Node.js, even when the scanned tests use Bun.

See Bun file selection for exact defaults and version differences.

Supported syntax ​

Bun 1.2.23 and newer, which runs tests the way 1.3 and 1.4 do; see framework version.

Where test comes from ​

FormExample
Globalstest, it, describe, xtest, xit, xdescribe and the hooks, which bun test sets in its test files
Importsimport { describe, test } from 'bun:test', a namespace or default import, or require('bun:test'); imports from @jest/globals and vitest too, which Bun rewrites to bun:test
Kept in a variableconst later = test.skip: only what both branches of a choice share applies, also of one written in place, as (process.env.CI ? test.skip : test)(...)
Local helpers fileimport { it } from './helpers' or require('./helpers'), followed through local imports, and helper functions that declare tests, read at each call

Calls ​

CallRead as
test(title, fn, options), test(title, options, fn)A test. Options are a number, the timeout, or { timeout, retry, repeats }. A retry above 0 with any repeats, 0 too, is an invalid-chain error from Bun 1.3, which refuses them together.
.skip, .todo, .failing, .only, .concurrent, .serialA skipped, todo or expectedToFail test, isOnly, or isParallel. A chain may hold them in any order, but only one of skip, todo and failing, one only, and one of concurrent and serial; another is an invalid-chain error: Bun fails the file. skip wins over todo, and todo over failing.
.if(condition), .skipIf, .todoIf, .failingIf, .concurrentIf, .serialIfA state under a condition: if skips when its condition is false, the others set theirs when it is true. A condition that holds counts as its mode in the chain, so test.todoIf(true).failing is an invalid-chain error as test.todo.failing is; one the scan can't work out counts as not holding. A describe can't be failing.
.each(table)One record with caseCount, as for Jest; with expandCases, each case titled as Bun titles it: %s a string, %d and %f a number, %i an integer, %j and %o JSON, %# the index, %% a %, and $key a value of an object case, quoted before Bun 1.3. A value of another type leaves its placeholder as written, and once the values are used up, the rest stays as written. %p, and $key of an object, keep the cases as one record. A table that isn't an array is an invalid-chain error: Bun fails the file.
test(title) without a functionA test-without-body error: Bun fails the file. test.skip(title) and test.todo(title) are allowed; test.todo with a function is todo too.
beforeAll, afterAll, beforeEach, afterEachHooks.

A refusal inside a describe fails that describe, whose tests are notLoaded with stateSource: "suite"; tests outside it still run.

A .only makes Bun run only the focused tests of its file, and from 1.3 with --only, none of the files without one; from 1.3, with CI=true, as in GitHub Actions, it fails its file instead. The other tests of the file are listed as written, with isOnly on the focused ones.

The shared syntax rules also apply.

Next ​

Documentation for test-inventory 0.10.1. Released under the MIT License.