4.3 KiB
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
injecthelper — the return type ofinject(key)is inferred from the fixture'sTConfigtype parameter viaInferConfig, so no type casts are needed in test files. - Auto-resolved
globalSetuppath — the path is derived fromimport.meta.url, so it works regardless of where the consumer'svitest.config.tslives. - Additive registry — multiple calls to
createIntegrationSetupaccumulate fixtures into a shared registry; this allows split configuration across multiple config files. - Injectable test double —
createIntegrationSetupWithInject(under the package-privateinternal/directory) exposes the factory with a replaceableinjectFnfor unit testing without real Vitestprovide/injectinfrastructure. - Zero runtime overhead — the function does no async work; startup cost is deferred entirely to
global-setup.ts.
Usage: Basic Example
// 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:
// 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<string, ServiceFixture<…>>— named map of fixtures to register.
Returns: IntegrationSetupResult<TFixtures>
IntegrationSetupResult<TFixtures>
| Property | Type | Description |
|---|---|---|
globalSetup |
string |
Absolute path to global-setup.js. Add to test.globalSetup. |
inject |
<K extends keyof TFixtures>(key: K) => InferConfig<TFixtures[K]> |
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.