first commit
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user