The tap runner

Every test is a .test.ts file run by tap. How to write one: testing with t.check. This page covers how the runner is set up.

What it is

Location: test/**/*.test.ts Runner: tap v21 with tsx Run: pnpm test

Each package has a .taprc. It loads tsx and the @ianbicking/tap-check/tap plugin (t.check) with --import.

The files themselves are the catalog: ls test/**/*.test.ts.

Failure modes

The tap plugin set is built at install time.

.taprc disables @tapjs/typescript (plugin: - "!@tapjs/typescript") because tsx resolves TypeScript here, and the typescript plugin's loader runs ahead of tsx and cannot resolve an extensionless directory import (ERR_UNSUPPORTED_DIR_IMPORT on src/frontend/src/lib/trpc).

That configured set only takes effect after tap build, which regenerates the Test class in node_modules/@tapjs/test/test-built/. tap does rebuild by itself when the built set differs from the configured one — but it computes the child processes' --import arguments from the already loaded class before it rebuilds, so the run that triggers the rebuild still spawns its children with the default plugins. Every pnpm install re-links @tapjs/test from the store and restores the shipped default build, so "the first tap run after an install uses the wrong loaders" is deterministic, not a flake.

The monorepo root's postinstall therefore runs tap build (~3s), so every workspace install builds it — a fresh worktree, a detached checkout, a deploy. It lives at the root rather than in beebox's own postinstall because beebox is packed and installed as a tarball dependency by boxes: a postinstall there would run in a consumer install that has no tap (a devDependency) and fail it. tap plugin list prints the configured set and never shows this; the built set is what tap versions lists under plugins:.

See issues/closed/bugs/2026-08-25-fresh-checkout-tap-default-plugins.md.