Files
2026-05-27 23:47:53 +01:00

118 lines
12 KiB
Markdown

# @suaveplan/testing-integration - Core integration test infrastructure: ServiceFixture<T> interface, TestEnvironment, createIntegrationSetup() factory, HealthPoller, skipIfUnavailable() helper
## Summary
Core integration test infrastructure for Vitest: fixture lifecycle management, health polling, and the global-setup bridge.
<!-- begin:auto-docs -->
## Documentation tree
- [environment](./src/environment/test-environment.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [test-environment](./src/environment/test-environment.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [fixture](./src/fixture/service-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [service-fixture](./src/fixture/service-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [health-poller](./src/helpers/health-poller.md) — `HealthPoller` repeatedly calls a `ServiceFixture`'s `healthCheck()` method at a configurable interval until the servic…
- [skip-if-unavailable](./src/helpers/skip-if-unavailable.md) — `skipIfUnavailable` returns a `beforeAll`-compatible callback that marks the current test as skipped when the named ser…
- [create-integration-setup-internal](./src/internal/create-integration-setup-internal.md) — This module exposes `createIntegrationSetupWithInject()` — the dependency-injected core of the public `createIntegratio…
- [fixture-registry](./src/internal/fixture-registry.md) — This module exposes the module-level `fixtureRegistry` `Map<string, ServiceFixture<Record<string, unknown>>>` that brid…
- [skip-if-unavailable-internal](./src/internal/skip-if-unavailable-internal.md) — This module exposes `createSkipIfUnavailableWithInject()` — the dependency-injected core of the public `skipIfUnavailab…
- [create-integration-setup](./src/setup/create-integration-setup.md) — `createIntegrationSetup` is the primary entry point for wiring integration test fixtures into the Vitest global-setup l…
- [global-setup](./src/setup/global-setup.md) — `global-setup.ts` is the Vitest global-setup module that bridges the fixture registry populated by `createIntegrationSe…
<!-- end:auto-docs --> - [test-environment](./src/environment/test-environment.md) — <!-- begin:auto-docs --> _(no submodules)_- [fixture](./src/fixture/service-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [service-fixture](./src/fixture/service-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [health-poller](./src/helpers/health-poller.md) — `HealthPoller` repeatedly calls a `ServiceFixture`'s `healthCheck()` method at a configurable interval until the servic…
- [skip-if-unavailable](./src/helpers/skip-if-unavailable.md) — `skipIfUnavailable` returns a `beforeAll`-compatible callback that marks the current test as skipped when the named ser…
- [create-integration-setup-internal](./src/internal/create-integration-setup-internal.md) — This module exposes `createIntegrationSetupWithInject()` — the dependency-injected core of the public `createIntegratio…
- [fixture-registry](./src/internal/fixture-registry.md) — This module exposes the module-level `fixtureRegistry` `Map<string, ServiceFixture<Record<string, unknown>>>` that brid…
- [skip-if-unavailable-internal](./src/internal/skip-if-unavailable-internal.md) — This module exposes `createSkipIfUnavailableWithInject()` — the dependency-injected core of the public `skipIfUnavailab…
- [create-integration-setup](./src/setup/create-integration-setup.md) — `createIntegrationSetup` is the primary entry point for wiring integration test fixtures into the Vitest global-setup l…
- [global-setup](./src/setup/global-setup.md) — `global-setup.ts` is the Vitest global-setup module that bridges the fixture registry populated by `createIntegrationSe…
- [test-environment](./src/environment/test-environment.md) — <!-- begin:auto-docs --> _(no submodules)_- [fixture](./src/fixture/service-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [service-fixture](./src/fixture/service-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [health-poller](./src/helpers/health-poller.md) — `HealthPoller` repeatedly calls a `ServiceFixture`'s `healthCheck()` method at a configurable interval until the servic…
- [skip-if-unavailable](./src/helpers/skip-if-unavailable.md) — `skipIfUnavailable` returns a `beforeAll`-compatible callback that marks the current test as skipped when the named ser…
- [create-integration-setup-internal](./src/internal/create-integration-setup-internal.md) — This module exposes `createIntegrationSetupWithInject()` — the dependency-injected core of the public `createIntegratio…
- [fixture-registry](./src/internal/fixture-registry.md) — This module exposes the module-level `fixtureRegistry` `Map<string, ServiceFixture<Record<string, unknown>>>` that brid…
- [skip-if-unavailable-internal](./src/internal/skip-if-unavailable-internal.md) — This module exposes `createSkipIfUnavailableWithInject()` — the dependency-injected core of the public `skipIfUnavailab…
- [create-integration-setup](./src/setup/create-integration-setup.md) — `createIntegrationSetup` is the primary entry point for wiring integration test fixtures into the Vitest global-setup l…
- [global-setup](./src/setup/global-setup.md) — `global-setup.ts` is the Vitest global-setup module that bridges the fixture registry populated by `createIntegrationSe…
- [test-environment](./src/environment/test-environment.md) — <!-- begin:auto-docs --> _(no submodules)_- [fixture](./src/fixture/service-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [service-fixture](./src/fixture/service-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [health-poller](./src/helpers/health-poller.md) — `HealthPoller` repeatedly calls a `ServiceFixture`'s `healthCheck()` method at a configurable interval until the servic…
- [skip-if-unavailable](./src/helpers/skip-if-unavailable.md) — `skipIfUnavailable` returns a `beforeAll`-compatible callback that marks the current test as skipped when the named ser…
- [create-integration-setup-internal](./src/internal/create-integration-setup-internal.md) — This module exposes `createIntegrationSetupWithInject()` — the dependency-injected core of the public `createIntegratio…
- [fixture-registry](./src/internal/fixture-registry.md) — This module exposes the module-level `fixtureRegistry` `Map<string, ServiceFixture<Record<string, unknown>>>` that brid…
- [skip-if-unavailable-internal](./src/internal/skip-if-unavailable-internal.md) — This module exposes `createSkipIfUnavailableWithInject()` — the dependency-injected core of the public `skipIfUnavailab…
- [create-integration-setup](./src/setup/create-integration-setup.md) — `createIntegrationSetup` is the primary entry point for wiring integration test fixtures into the Vitest global-setup l…
- [global-setup](./src/setup/global-setup.md) — `global-setup.ts` is the Vitest global-setup module that bridges the fixture registry populated by `createIntegrationSe…
- [test-environment](./src/environment/test-environment.md) — <!-- begin:auto-docs --> _(no submodules)_- [fixture](./src/fixture/service-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_ - [service-fixture](./src/fixture/service-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [health-poller](./src/helpers/health-poller.md) — `HealthPoller` repeatedly calls a `ServiceFixture`'s `healthCheck()` method at a configurable interval until the servic…
- [skip-if-unavailable](./src/helpers/skip-if-unavailable.md) — `skipIfUnavailable` returns a `beforeAll`-compatible callback that marks the current test as skipped when the named ser…
- [create-integration-setup-internal](./src/internal/create-integration-setup-internal.md) — This module exposes `createIntegrationSetupWithInject()` — the dependency-injected core of the public `createIntegratio…
- [fixture-registry](./src/internal/fixture-registry.md) — This module exposes the module-level `fixtureRegistry` `Map<string, ServiceFixture<Record<string, unknown>>>` that brid…
- [skip-if-unavailable-internal](./src/internal/skip-if-unavailable-internal.md) — This module exposes `createSkipIfUnavailableWithInject()` — the dependency-injected core of the public `skipIfUnavailab…
- [create-integration-setup](./src/setup/create-integration-setup.md) — `createIntegrationSetup` is the primary entry point for wiring integration test fixtures into the Vitest global-setup l…
- [global-setup](./src/setup/global-setup.md) — `global-setup.ts` is the Vitest global-setup module that bridges the fixture registry populated by `createIntegrationSe…
## Quick Start
```ts
// fixtures/redis.ts
import type { ServiceFixture } from "@suaveplan/testing-integration/fixture/service-fixture";
export const redisFixture: ServiceFixture<{ url: string }> = {
name: "redis",
async start() {
// start your real Redis container or in-process server
return { url: "redis://localhost:6379" };
},
async stop() { /* stop it */ },
async healthCheck() { return true; },
};
// vitest.config.ts
import { defineConfig } from "vitest/config";
import { createIntegrationSetup } from "@suaveplan/testing-integration/setup/create-integration-setup";
import { redisFixture } from "./fixtures/redis.js";
const { globalSetup, inject } = createIntegrationSetup({ redis: redisFixture });
export default defineConfig({ test: { globalSetup: [globalSetup] } });
export { inject };
// redis.test.ts
import { beforeEach } from "vitest";
import { inject } from "../vitest.config.js";
import { skipIfUnavailable } from "@suaveplan/testing-integration/helpers/skip-if-unavailable";
beforeEach(skipIfUnavailable("redis"));
it("reads from redis", async () => {
const { url } = inject("redis"); // typed as { url: string }
// ...
});
```
## Module Reference
| Module | Purpose | Docs |
|---|---|---|
| `./fixture/service-fixture` | `ServiceFixture<TConfig>` interface + `InferConfig<F>` | [service-fixture.md](src/fixture/service-fixture.md) |
| `./helpers/health-poller` | `HealthPoller` + `TestEnvironmentError` | [health-poller.md](src/helpers/health-poller.md) |
| `./helpers/skip-if-unavailable` | `skipIfUnavailable()` + `_createSkipIfUnavailableWithInject()` | [skip-if-unavailable.md](src/helpers/skip-if-unavailable.md) |
| `./environment/test-environment` | `TestEnvironment` parallel fixture orchestrator | [test-environment.md](src/environment/test-environment.md) |
| `./setup/create-integration-setup` | `createIntegrationSetup()` factory + `_fixtureRegistry` | [create-integration-setup.md](src/setup/create-integration-setup.md) |
| `./setup/global-setup` | Vitest `setup`/`teardown` hooks (global-setup module) | [global-setup.md](src/setup/global-setup.md) |
## Environment Bridge
The package uses two `provide`/`inject` keys as an internal implementation detail:
| Key | Type | Description |
|---|---|---|
| `__integration_configs__` | `Record<string, Record<string, unknown>>` | Config objects keyed by fixture key, populated in global-setup. |
| `__integration_failed__` | `string[]` | Names of fixtures whose `start()` threw, used by `skipIfUnavailable`. |
Do not read these keys directly — use `inject(key)` from `createIntegrationSetup` for configs and `skipIfUnavailable(name)` for skip guards.
## Adding a New `testing-integration-<service>` Plugin
When creating a sibling fixture package (e.g. `@suaveplan/testing-integration-clickhouse`):
1. Mirror the `vite.config.ts` of an existing fixture (e.g. `testing-integration-redis`). The `build.rollupOptions.output` block MUST contain all three of `preserveModules: true`, `preserveModulesRoot: "src"`, **and `entryFileNames: "[name].js"`**. Without the third line, Vite's lib mode derives the entry filename from the package name and the consumer-facing `dist/index.js` is never written — the package will appear to build but fail to resolve from any sibling workspace.
2. Run `bun run check:fixture-resolves` from the repo root to verify the new package resolves. The repo-level CI gate `//#check:fixture-resolves` (in `turbo.json`) will fail otherwise.