# @suaveplan/testing-integration - Core integration test infrastructure: ServiceFixture interface, TestEnvironment, createIntegrationSetup() factory, HealthPoller, skipIfUnavailable() helper ## Summary Core integration test infrastructure for Vitest: fixture lifecycle management, health polling, and the global-setup bridge. ## Documentation tree - [environment](./src/environment/test-environment.md) — _(no submodules)_ - [test-environment](./src/environment/test-environment.md) — _(no submodules)_ - [fixture](./src/fixture/service-fixture.md) — _(no submodules)_ - [service-fixture](./src/fixture/service-fixture.md) — _(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>>` 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) — _(no submodules)_- [fixture](./src/fixture/service-fixture.md) — _(no submodules)_- [service-fixture](./src/fixture/service-fixture.md) — _(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>>` 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) — _(no submodules)_- [fixture](./src/fixture/service-fixture.md) — _(no submodules)_- [service-fixture](./src/fixture/service-fixture.md) — _(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>>` 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) — _(no submodules)_- [fixture](./src/fixture/service-fixture.md) — _(no submodules)_- [service-fixture](./src/fixture/service-fixture.md) — _(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>>` 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) — _(no submodules)_- [fixture](./src/fixture/service-fixture.md) — _(no submodules)_ - [service-fixture](./src/fixture/service-fixture.md) — _(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>>` 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` interface + `InferConfig` | [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>` | 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-` 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.