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,91 @@
# 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<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.