first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
# `internal/create-integration-setup-internal`
## Purpose
This module exposes `createIntegrationSetupWithInject()` — the dependency-injected core of the public `createIntegrationSetup()` factory. Splitting the implementation into a wired core plus a thin public facade keeps the `vitest` runtime import isolated to one file (`../setup/create-integration-setup.ts`) and lets the unit tests cover the registration / inject hand-off without booting Vitest's global-setup machinery.
It is deliberately under `src/internal/` and not listed in `package.json` `exports`. Consumers MUST NOT import it; the public contract is `createIntegrationSetup()` from the package barrel. Tests in this package import this module directly because they own the implementation; downstream packages do not.
## Features
- Generic over the fixture map; preserves precise per-fixture config types end-to-end via `InferConfig`.
- Pluggable `injectFn` so unit tests can verify the indirection through Vitest's `inject` without importing `vitest` from the test file under inspection.
- Side-effect: mutates `fixtureRegistry` so the Vitest global-setup module sees the fixtures at boot.
## Usage: Basic Example
```ts
// PRIVATE — shown for documentation only. Use createIntegrationSetup() in app code.
import { createIntegrationSetupWithInject } from "./internal/create-integration-setup-internal.js";
const { globalSetup, inject } = createIntegrationSetupWithInject(
{ redis: redisFixture },
(key) => ({ redis: { url: "redis://injected" } })
);
```
## Usage: Advanced Example
The public `createIntegrationSetup` (in `../setup/create-integration-setup.ts`) is exactly this with Vitest's real `inject` wired in:
```ts
import { inject as vitestInject } from "vitest";
import { createIntegrationSetupWithInject } from "../internal/create-integration-setup-internal.js";
export function createIntegrationSetup<TFixtures>(fixtures: TFixtures) {
return createIntegrationSetupWithInject(
fixtures,
vitestInject as (key: string) => Record<string, Record<string, unknown>>
);
}
```
## API Reference
- `createIntegrationSetupWithInject<TFixtures>(fixtures, injectFn)` — returns `{ globalSetup: string; inject: <K extends keyof TFixtures>(key: K) => InferConfig<TFixtures[K]> }`. Writes every entry of `fixtures` into the shared `fixtureRegistry`.
## Implementation Notes
Resolves the global-setup path via `new URL("../setup/global-setup.js", import.meta.url).pathname`. This path is what consumers feed into `test.globalSetup` in their `vitest.config.ts`; using `import.meta.url` makes the reference robust to workspace layout differences.

View File

@@ -0,0 +1,45 @@
# `internal/fixture-registry`
## Purpose
This module exposes the module-level `fixtureRegistry` `Map<string, ServiceFixture<Record<string, unknown>>>` that bridges `createIntegrationSetup()` and the Vitest `global-setup.ts` entry point. It exists because Vitest's global-setup hook cannot accept arguments across the configuration boundary — so the registration step (called from `vitest.config.ts`) and the consumption step (called by Vitest before any test file loads) must communicate via a shared, in-process singleton.
The registry is deliberately placed under `src/internal/` and is **not** listed in `package.json` `exports`. It is private build-system plumbing. Consumers MUST NOT import it; doing so means relying on an unstable surface that the package may rearrange without a SemVer breaking change. The public surface remains `createIntegrationSetup()` + `globalSetup` + `inject()`; everything in `internal/` is implementation detail.
## Features
- Singleton `Map` keyed by user-chosen fixture names.
- Stores the `ServiceFixture<Record<string, unknown>>` instances; the variant fixtures (`@suaveplan/testing-integration-redis`, etc.) all conform to this contract.
- Mutated by `createIntegrationSetup()` (writes) and by `global-setup.ts` (reads + clear).
## Usage: Basic Example
```ts
// PRIVATE — internal/* is not a published subpath. Shown for documentation only.
import { fixtureRegistry } from "./internal/fixture-registry.js";
console.log(fixtureRegistry.size);
```
## Usage: Advanced Example
`global-setup.ts` snapshot the registry into a plain object so the `TestEnvironment` constructor receives a stable view, then clears it so re-runs in watch mode start fresh:
```ts
import { fixtureRegistry } from "./internal/fixture-registry.js";
import { TestEnvironment } from "../environment/test-environment.js";
const fixtures = Object.fromEntries(fixtureRegistry);
const env = new TestEnvironment(fixtures);
const { configs, failed } = await env.setup();
context.provide("__integration_configs__", configs);
context.provide("__integration_failed__", failed);
```
## API Reference
- `fixtureRegistry: Map<string, ServiceFixture<Record<string, unknown>>>` — mutable singleton, lifetime equal to the Node process. Reads and writes are not synchronised because Vitest serialises setup vs test execution.
## Implementation Notes
The registry uses `Record<string, unknown>` rather than the precise per-fixture config because the Vitest bridge erases the type at the cross-module boundary. The strongly-typed projection is restored at the `inject()` call site via the `InferConfig<TFixtures[K]>` mapping in `IntegrationSetupResult`.

View File

@@ -0,0 +1,41 @@
# `internal/skip-if-unavailable-internal`
## Purpose
This module exposes `createSkipIfUnavailableWithInject()` — the dependency-injected core of the public `skipIfUnavailable()` helper. Splitting the implementation lets the public façade (`../helpers/skip-if-unavailable.ts`) hold the only `import { inject } from "vitest"` runtime call site, while unit tests exercise this factory with a fake injector and verify the behaviour without booting Vitest's `provide`/`inject` infrastructure.
It lives under `src/internal/` and is deliberately omitted from `package.json` `exports`. Consumers MUST NOT import it. The public surface is `skipIfUnavailable()` from the package barrel.
## Features
- Generic over `TName extends string` so consumers using a typed `createIntegrationSetup` registry get key auto-completion and compile-time errors when they typo a fixture name.
- Pluggable `injectFn` so unit tests can pass a fake without `vitest`.
- Treats `null` / `undefined` returns from `injectFn` as the empty failed-list (no skip).
## Usage: Basic Example
```ts
// PRIVATE — shown for documentation only. Use skipIfUnavailable() in app code.
import { createSkipIfUnavailableWithInject } from "./internal/skip-if-unavailable-internal.js";
const cb = createSkipIfUnavailableWithInject("redis", (key) => ["redis"]);
cb({ skip: () => console.log("skipped") });
```
## Usage: Advanced Example
The public `skipIfUnavailable()` uses Vitest's `inject` internally. When paired with a typed `createIntegrationSetup` registry, the generic preserves key safety:
```ts
import { skipIfUnavailable } from "@suaveplan/testing-integration/helpers/skip-if-unavailable";
beforeAll(skipIfUnavailable<"redis" | "postgres">("redis"));
// skipIfUnavailable<"redis" | "postgres">("typeo") // compile error — typo caught
```
## API Reference
- `createSkipIfUnavailableWithInject<TName extends string>(fixtureName, injectFn)` — returns `(ctx: { skip: () => void }) => void`. The returned callback reads the failed-fixture list via `injectFn("__integration_failed__")` and calls `ctx.skip()` if `fixtureName` is in it.
## Implementation Notes
The cast `null as unknown as string[]` in tests verifies the `?? []` guard. Production callers never pass a function that returns `null`, but Vitest's `inject` typing is loose, so the guard is load-bearing in real-world consumers.