Skip to content

feat(testing)!: the harness is a package, and the examples dogfood it - #43

Merged
btravers merged 2 commits into
mainfrom
feat/testing-package
Aug 16, 2026
Merged

feat(testing)!: the harness is a package, and the examples dogfood it#43
btravers merged 2 commits into
mainfrom
feat/testing-package

Conversation

@btravers

Copy link
Copy Markdown
Contributor

Closes #21.

Why the examples never imported the harness (acceptance 1)

The repo's test conventions mandate test.extend fixtures with teardown in the fixture; withApp(module, options, use) is a callback wrapper, so it cannot be handed to use() and give the test the app back. Every suite therefore hand-rolled the same start(…, { signals: false, probes: false, preDrainDelayMs: 0 }) + stop(); await expect(exited).toBeOk(). A second gap: start hands the application context to the runtime alone, so order-api and the two workers each wrote a LoggerTap / ServicesTap provider just to reach a service of the running app.

@btravstack/testing

A package, the way @nestjs/testing is — @btravstack/core/testing is gone (breaking, unreleased). It ships testRuntime() / TestRuntimePort, createFakeClock(), withApp() (moved unchanged, with their specs) plus:

  • bootFixture(defaults?) — a test.extend fixture giving the test boot(module, options?) with a test's defaults baked in and every application stopped when the test ends. Teardown mirrors withApp: a Defect on exited fails the test, a modeled Err passes through (so serveBroken's Err exit stays the test's to assert).
  • tapped(module, [Port, …]){ module, services() }; the gate refuses a port the module does not export, and services() is loud before the graph is built.

No vitest peer: bootFixture returns vitest's fixture shape as a plain function, so the package stays runner-agnostic.

Migrated

The kernel's own specs and the fixtures of packages/{http,temporal,amqp} and examples/{order-api,order-temporal-worker,order-amqp-worker} — eight files. order-api's LoggerTap and the two workers' ServicesTap are now tapped.

The one wrinkle

@btravstack/testing peers on @btravstack/core, and core's specs use it — a package-graph cycle turbo refuses. Broken without a cycle: a tsconfig paths entry to the built declarations, a vitest alias to its source (with @btravstack/core aliased back to src, so one kernel is in play), a @btravstack/core#typecheck → @btravstack/testing#build edge, a knip ignoreDependencies, and packages/core/tsconfig.build.json so the published dist never sees any of it.

Test plan

  • format / lint / typecheck / knip / build green; @btravstack/testing at 100% lines/functions, core unchanged
  • tests green locally minus the two Docker suites (CI)
  • docs: /reference/testing, the testing how-to and the API reference rebuilt; zero dead links
  • CI

Closes #21. `@btravstack/core/testing` is gone; `@btravstack/testing` ships
what it did — testRuntime, TestRuntimePort, createFakeClock, withApp — plus
the two things every suite had been hand-rolling:

- bootFixture(defaults?): a test.extend fixture handing the test
  boot(module, options?) with a test's defaults (signals off always, probes
  off unless asked, preDrainDelayMs 0, silent onEvent) and stopping every
  application it started when the test ends. Teardown mirrors withApp: a
  Defect on exited fails the test, a modeled Err passes through.
- tapped(module, ports): read services out of a booted application, since
  start hands the context to the runtime alone. The gate refuses a port the
  module does not export; services() is loud before the graph is built.

Why the examples never used withApp (the issue's first question): the test
conventions mandate test.extend fixtures with teardown in the fixture, and a
callback harness cannot be handed to use(). The eight fixture files now boot
through bootFixture, and order-api / order-temporal-worker / order-amqp-worker
drop their hand-rolled LoggerTap / ServicesTap for tapped.

core's specs reach the package without a package-graph cycle: a tsconfig
paths entry to its built declarations, a vitest alias to its source (with
@btravstack/core aliased back to src), a turbo edge, a knip ignore, and
tsconfig.build.json so the published dist never sees any of it.
Copilot AI lite review requested due to automatic review settings August 16, 2026 09:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extracts the test harness into a new published package (@btravstack/testing) and migrates the starters + example deployments to dogfood it, replacing the former @btravstack/core/testing entry point. It also updates the monorepo toolchain (turbo, vitest aliasing, knip) and documentation/TypeDoc to reflect the new package layout.

Changes:

  • Add @btravstack/testing package (bootFixture/boot types, tapped, plus moved testRuntime/createFakeClock/withApp) and its test/TypeDoc setup.
  • Remove @btravstack/core/testing export surface and adjust core build/typecheck to avoid a turbo cycle while still letting core specs consume @btravstack/testing.
  • Migrate starter + example test fixtures to use bootFixture for lifecycle teardown and tapped to access services from a running graph; update docs accordingly.

Reviewed changes

Copilot reviewed 82 out of 85 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
turbo.json Orders @btravstack/testing#build before core typecheck; adds testing build to docs build deps.
README.md Adds @btravstack/testing to the package list.
pnpm-lock.yaml Adds workspace links for @btravstack/testing across affected workspaces.
packages/testing/vitest.config.ts New vitest config + 100% coverage thresholds for the testing package.
packages/testing/tsconfig.json New TS config for the testing package output/typecheck.
packages/testing/src/with-app.ts Switches withApp to import core APIs from @btravstack/core (now that core/testing is gone).
packages/testing/src/with-app.spec.ts Updates spec imports to the new core entry point.
packages/testing/src/vitest.d.ts Adds matcher type augmentation via @unthrown/vitest.
packages/testing/src/test-runtime.ts Moves runtime types/imports to @btravstack/core; updates started-tracking implementation.
packages/testing/src/test-runtime.spec.ts New/ported specs for testRuntime, including abort forwarding.
packages/testing/src/test-fixtures.ts Adds local package test fixtures (runtimeModule, greetingApp, extended it).
packages/testing/src/tapped.ts Introduces tapped() helper to capture exported services from a booted graph.
packages/testing/src/tapped.spec.ts Adds specs for tapped() capture + misuse guard.
packages/testing/src/index.ts Exports the new bootFixture and tapped surface from the package entrypoint.
packages/testing/src/fake-clock.ts Switches Clock import to @btravstack/core.
packages/testing/src/fake-clock.spec.ts Adds specs for fake clock behavior.
packages/testing/src/boot-fixture.ts Implements bootFixture() vitest-fixture body with Defect-only teardown semantics.
packages/testing/src/boot-fixture.spec.ts Adds specs covering fixture defaults + teardown behavior.
packages/testing/README.md New package README describing usage and exported surface.
packages/testing/package.json New package manifest (dual build, peers, scripts).
packages/testing/LICENSE Adds license file for the new package.
packages/testing/CLAUDE.md Adds package-local spec for the testing surface + its invariants/tests/tooling arrangement.
packages/temporal/src/test-fixtures.ts Migrates temporal starter fixtures to use bootFixture and remove hand-rolled teardown.
packages/temporal/package.json Adds @btravstack/testing devDependency for fixtures.
packages/temporal/CLAUDE.md Updates temporal package spec to reference new fixture composition/boot behavior.
packages/http/src/test-fixtures.ts Migrates HTTP starter fixtures to bootFixture; removes manual stop/expect teardown.
packages/http/package.json Adds @btravstack/testing devDependency for fixtures.
packages/http/CLAUDE.md Updates HTTP package spec to reflect bootFixture-driven teardown.
packages/core/vitest.config.ts Adds vitest aliases so core specs can import @btravstack/testing without a dependency cycle.
packages/core/tsconfig.json Adds paths mapping to built @btravstack/testing d.ts for typecheck.
packages/core/tsconfig.build.json New build tsconfig to clear paths and exclude tests from published output.
packages/core/src/test-runtime.spec.ts Removes core-local testRuntime specs (moved to @btravstack/testing).
packages/core/src/test-fixtures.ts Switches core fixtures to import testRuntime types from @btravstack/testing.
packages/core/src/start.test-d.ts Updates type tests to use testRuntime from @btravstack/testing.
packages/core/src/start.spec.ts Updates core tests to use createFakeClock/testRuntime from @btravstack/testing.
packages/core/src/run-main.spec.ts Updates core tests to use createFakeClock/testRuntime from @btravstack/testing.
packages/core/src/invariants.spec.ts Updates core invariant tests to use withApp/clock/runtime from @btravstack/testing.
packages/core/src/docs-examples.test-d.ts Updates compiled docs samples to reference @btravstack/testing.
packages/core/README.md Removes references to core/testing; points to @btravstack/testing instead.
packages/core/package.json Removes ./testing export; updates tsdown invocation to use tsconfig.build.json.
packages/core/CLAUDE.md Documents the new “core specs consume testing package” arrangement and points to new spec locations.
packages/amqp/src/test-fixtures.ts Migrates AMQP starter fixtures to bootFixture; removes manual stop/expect teardown.
packages/amqp/package.json Adds @btravstack/testing devDependency for fixtures.
packages/amqp/CLAUDE.md Updates AMQP package spec to reference bootFixture-driven teardown behavior.
knip.json Ignores @btravstack/testing for core workspace to accommodate non-package.json import resolution.
examples/README.md Documents that deployments now test via @btravstack/testing (boot + tapped).
examples/order-temporal-worker/src/test-fixtures.ts Migrates example worker fixtures to bootFixture + tapped (removes custom ServicesTap).
examples/order-temporal-worker/README.md Updates fixture documentation to mention boot/tapped from testing package.
examples/order-temporal-worker/package.json Adds @btravstack/testing devDependency for fixtures.
examples/order-api/src/test-fixtures.ts Migrates API example fixtures to bootFixture + tapped (removes LoggerTap).
examples/order-api/README.md Updates fixture documentation to mention boot/tapped from testing package.
examples/order-api/package.json Adds @btravstack/testing devDependency for fixtures.
examples/order-amqp-worker/src/test-fixtures.ts Migrates AMQP example fixtures to bootFixture + tapped (removes custom ServicesTap).
examples/order-amqp-worker/README.md Updates fixture documentation to mention boot/tapped from testing package.
examples/order-amqp-worker/package.json Adds @btravstack/testing devDependency for fixtures.
docs/typedoc.testing.json Adds TypeDoc config for the new testing package API docs.
docs/typedoc.core.json Removes core/testing entry point from core TypeDoc generation.
docs/tutorial/getting-started.md Updates tutorial link text to reference bootFixture/@btravstack/testing.
docs/scripts/build-api.ts Adds testing to the package list for API generation.
docs/reference/testing.md Replaces the old core/testing reference page with the new @btravstack/testing reference.
docs/reference/packages.md Updates package list, peer matrix, and install snippets to include testing package.
docs/reference/core/start.md Updates gate discussion to include Boot/testing withApp.
docs/reference/core/runtime.md Updates fake clock reference to point at @btravstack/testing.
docs/reference/core/probes.md Updates probes note to reflect bootFixture defaults + how to opt into probes in tests.
docs/reference/core/events.md Updates events note to reflect bootFixture default sink and pass-through behavior.
docs/index.md Updates landing page package count/list to include testing package.
docs/how-to/write-a-runtime.md Updates testing pointer to use bootFixture.
docs/how-to/test-an-application.md Rewrites the how-to around bootFixture + tapped, retaining withApp for one-offs.
docs/how-to/swap-an-adapter.md Updates guidance to reference @btravstack/testing boot/withApp instead of core/testing.
docs/how-to/open-a-per-request-scope.md Updates guidance to include testing boot/withApp as valid unit carriers.
docs/how-to/embed-without-run-main.md Updates related links to mention bootFixture and withApp.
docs/explanation/why-start.md Updates “family” section to include @btravstack/testing.
docs/explanation/nothing-throws.md Updates the “Promise exceptions” section to include testing package + bootFixture rationale.
docs/explanation/design-decisions.md Adds explicit design decision section: test harness is a package.
docs/explanation/compile-time-wiring.md Updates gate explanation to include testing Boot/withApp.
docs/examples/order-temporal-worker.md Updates example docs to mention boot fixture and tapped usage.
docs/examples/order-api.md Updates example docs to show bootFixture-based fixtures and tapped logger access.
docs/examples/order-amqp-worker.md Updates example docs to show bootFixture-based fixtures and tapped service access.
docs/api/index.md Updates API index to reflect core’s single entry point + adds testing package API page.
docs/.vitepress/config.ts Updates sidebar and API nav to include @btravstack/testing.
CLAUDE.md Updates repo-wide spec to add the testing package and its toolchain/test conventions integration.
.changeset/unit-module.md Extends changeset to include testing package (signal availability note).
.changeset/testing-package.md Adds changeset describing the new testing package + removal of core/testing.
.changeset/runtime-port.md Updates changeset text to refer to @btravstack/testing.
.changeset/initial-kernel.md Updates initial-kernel changeset to refer to testing package.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/testing/src/tapped.ts Outdated
Comment thread packages/testing/src/test-runtime.spec.ts Outdated
- Port("Tap") -> Port("@btravstack/testing/Tap"): the port is invisible to
  the application that would collide with it, and di keys services by the
  literal id, so a bare "Tap" would shadow an application's own with a
  warning naming a port its author never wrote
- test-runtime.spec.ts's two moved tests now assert once, deeply, per the
  test conventions rule 4 and 5 that bind everywhere
@btravers
btravers merged commit 84f0156 into main Aug 16, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Examples never import @btravstack/start/testing — dogfood the shipped harness or fix it

2 participants