# createIntegrationSetup ## Purpose `createIntegrationSetup` is the primary entry point for wiring integration test fixtures into the Vitest global-setup lifecycle. It accepts a named map of `ServiceFixture` instances, registers them in a module-level registry that `global-setup.ts` reads at startup, and returns two things: the absolute path of the Vitest global-setup module (ready to drop into `test.globalSetup`) and a typed `inject` helper that test files use to retrieve fixture configs. This one-call configuration model means consumers never need to import from `global-setup.ts` directly. ## Features - **Typed `inject` helper** — the return type of `inject(key)` is inferred from the fixture's `TConfig` type parameter via `InferConfig`, so no type casts are needed in test files. - **Auto-resolved `globalSetup` path** — the path is derived from `import.meta.url`, so it works regardless of where the consumer's `vitest.config.ts` lives. - **Additive registry** — multiple calls to `createIntegrationSetup` accumulate fixtures into a shared registry; this allows split configuration across multiple config files. - **Injectable test double** — `createIntegrationSetupWithInject` (under the package-private `internal/` directory) exposes the factory with a replaceable `injectFn` for unit testing without real Vitest `provide`/`inject` infrastructure. - **Zero runtime overhead** — the function does no async work; startup cost is deferred entirely to `global-setup.ts`. ## Usage: Basic Example ```ts // 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 { inject } from "../vitest.config.js"; import { beforeEach } from "vitest"; import { skipIfUnavailable } from "@suaveplan/testing-integration/helpers/skip-if-unavailable"; beforeEach(skipIfUnavailable("redis")); it("connects to redis", async () => { const { url } = inject("redis"); // typed as RedisConfig // ... }); ``` ## Usage: Advanced Example Accumulating fixtures across multiple config calls: ```ts // vitest.config.ts import { createIntegrationSetup } from "@suaveplan/testing-integration/setup/create-integration-setup"; // Split fixture definitions across modules const { globalSetup: gsA } = createIntegrationSetup({ redis: redisFixture }); const { globalSetup: gsB, inject } = createIntegrationSetup({ postgres: postgresFixture }); // Both fixture sets are registered in the shared package-private fixtureRegistry export default defineConfig({ test: { globalSetup: [gsA], // only one path needed — registry is shared }, }); ``` ## API Reference ### `createIntegrationSetup(fixtures)` **Parameters:** - `fixtures: Record>` — named map of fixtures to register. **Returns:** `IntegrationSetupResult` ### `IntegrationSetupResult` | Property | Type | Description | |---|---|---| | `globalSetup` | `string` | Absolute path to `global-setup.js`. Add to `test.globalSetup`. | | `inject` | `(key: K) => InferConfig` | Typed accessor for fixture configs populated by global-setup. | ### Package-private internals `createIntegrationSetupWithInject(fixtures, injectFn)` and the `fixtureRegistry` `Map` live under `src/internal/` and are deliberately NOT exported via `package.json` `exports`. They are reachable only from within this package's own source tree (used by tests and by the public façade above) and consumers MUST NOT rely on them. ## Implementation Notes The `globalSetup` path is computed via `new URL("./global-setup.js", import.meta.url).pathname`. This resolves relative to the compiled output location so the path is always valid after `vite build`. It does not depend on `__dirname` or any Node.js path resolution, making it compatible with ES module environments. The `inject` closure captures `injectFn` at creation time and calls it lazily — only when `inject(key)` is invoked inside a test. This lazy evaluation is necessary because Vitest's `inject` only returns values after the global-setup `provide` calls have run.