> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackra.figentra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 0269 — @stackra/testing: entries, what it holds, and where domain helpers live

> Accepted · 2026-10-21

> [!NOTE]
>
> Amends [0022](/adr/0022-tests-live-in-tests-folders) (decision 4: shared fixtures and doubles live
> in `@stackra/testing`, and domain helpers in each owning package's `./testing` entry) and
> [0126](/adr/0126-member-shapes-and-scaffold-templates) (decision 2: a named exception for the
> `./e2e` and `./contract` entries of `@stackra/testing` only).

## Context

Every package and service needs the same test plumbing: a vitest preset, factories, fakes for the clock and ids, and
matchers. Before this decision each package wrote its own, and the domain helpers (a module under test, a dispatch
runner, actors, refusal and event matchers, a permission matcher) had no agreed home. [0022](/adr/0022-tests-live-in-tests-folders)
decision 4 asked for "an explicit `testing` entry of the package that owns the contract", but did not say what a shared
package holds. [0182](/adr/0182-testing-strategy-v2-tiers-coverage-infrastructure-and-policies) fixed the test tiers by
filename infix, so the entries below line up with those tiers. The owner settled the placement on 2026-10-21. That answer
reverses an earlier answer of the same day, which put every helper in one package.

## Decision

1. **`@stackra/testing` is a `tier:lib` package in the `developer` category** (`packages/developer/testing`, [0127](/adr/0127-package-categories-including-infrastructure)).
   It has six entries: `.`, `./node`, `./react`, `./native`, `./e2e` and `./contract`. Each entry is declared in `package.json`
   only when it holds real code, as [0126](/adr/0126-member-shapes-and-scaffold-templates) decision 2 says.

2. **The `.` entry holds only generic code.** It re-exports vitest, and it provides generic factories, fakes for the clock and
   ids, and generic matchers. It has no workspace dependency and no domain type. Nothing in `.` knows what a module, an action,
   a permission or an event is.

3. **Domain helpers live in the owning package's `./testing` entry, built on `@stackra/testing`.** The helpers of this class are
   `createTestingModule`, `run`, the actor helpers, `toRefuseWith`, `toEmit`, `toHavePermission` and `toMatchManifest`. Each one
   lives in the `./testing` entry of the package that owns the thing it tests. A package never reaches into another package's
   `./testing` entry.

4. **Mock hoisting is configured in the preset.** The shared vitest preset (`packages/tooling/vitest/src/preset.ts`) is set so that
   `vi.mock` calls in a test file hoist when the file imports from `@stackra/testing`. A test in `@stackra/testing` proves this.
   If that test fails, the work stops and returns to the owner. There is no fallback to global `vi` (`globals: true`).

5. **The entry names are fixed here, and the tier they serve is not.** `./contract` and `./e2e` are named for the `.contract` and `.e2e`
   tiers of [0182](/adr/0182-testing-strategy-v2-tiers-coverage-infrastructure-and-policies). Which kind of test uses which entry is
   set in the test-by-kind table (`standards/testing-by-kind`), and the contents of each entry are set by the package build.

6. **Named exception to [0126](/adr/0126-member-shapes-and-scaffold-templates) decision 2.** Decision 2 of 0126 lists the entries a
   package may have: `.`, `./contracts`, `./node`, `./react`, `./native`, `./testing` and `./devtools`. For `@stackra/testing`
   alone, the entries `./e2e` and `./contract` are added to that list, with these names. Nothing else in the entry list changes,
   and no other package gets these entries. `@stackra/testing/contract` is a subpath of the testing package; it is unrelated to a
   member's `./contracts` entry (the vocabulary entry of [0117](/adr/0117-contracts-placement-and-decorator-ownership)), and the two
   names do not mean the same thing.

## Consequences

* A package's tests import its domain helpers from its own `./testing` entry, so a helper is never copied between packages.
* `@stackra/testing` stays free of domain dependencies, so it can sit at the bottom of the dependency graph for tests.
* Each package that owns a contract grows a `./testing` entry when it first needs one. Until then it has none.
* The mock-hoisting test is a gate: if the preset changes and hoisting breaks, the change fails before any package relies on it.

## Enforcement

planned — the hoisting test in `packages/developer/testing/src/__tests__/` (built in Phase T, item T1) proves decision 4. The
`exports` of each package and the `./testing` placement are checked by `checkEntriesMatchExports` in
`tools/scripts/validate-repository.mjs` once the structure work (STA-220) lands. Nothing checks decision 3 today.

## Supersedes and sources

Supersedes: none. Amends: [0022](/adr/0022-tests-live-in-tests-folders) decision 4; [0126](/adr/0126-member-shapes-and-scaffold-templates)
decision 2 (named exception, decision 6 above). Sources: owner answers on testing helpers, 2026-10-21
(the reversal of the earlier answer of the same day); [0126](/adr/0126-member-shapes-and-scaffold-templates) decision 2 (entries).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.