Initial Commit
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# OpenSpec Change: testing-integration-build-fix
|
||||
|
||||
- **Change ID**: testing-integration-build-fix
|
||||
- **Package**: `@suaveplan/testing-integration` (modify)
|
||||
- **Status**: PROPOSED
|
||||
- **Date**: 2026-04-28
|
||||
|
||||
## Summary
|
||||
|
||||
Fix the Vite library build of `@suaveplan/testing-integration` so the `globalSetup` path returned by `createIntegrationSetup()` resolves to a real file instead of an inlined `data:video/mp2t;base64,…` URL. Currently the published artifact is unusable as a Vitest globalSetup target — the first downstream consumer (`@suaveplan/storage-s3`'s integration test) had to bypass `createIntegrationSetup` and write a hand-rolled global-setup module.
|
||||
|
||||
## Current state
|
||||
|
||||
- `packages/dev/testing-integration/src/internal/create-integration-setup-internal.ts:35` does `new URL("../setup/global-setup.js", import.meta.url).pathname`.
|
||||
- Vite library mode treats that pattern as an asset reference and inlines the source as a `data:` URL during `vite build`.
|
||||
- The compiled artifact at `dist/internal/create-integration-setup-internal.js:5` literally contains `new URL("data:video/mp2t;base64,LyoqCi…", import.meta.url).pathname`, so `globalSetup` becomes an unparseable string — `vitest` crashes with `ERR_LOAD_URL: Failed to load url …/storage-s3/video/mp2t;base64,…`.
|
||||
- Six downstream packages (`testing-integration-redis`, `-postgres`, `-mailpit`, `-typesense`, `-surrealdb`, `-garage-s3`, `-step-ca`) all rely on this entrypoint and would hit the same wall the moment they're consumed for real.
|
||||
|
||||
## What changes
|
||||
|
||||
### 1. Build-config fix
|
||||
|
||||
Two viable approaches; pick whichever the testing-integration build owner prefers:
|
||||
|
||||
- **Option A (preferred)**: Mark `src/setup/global-setup.ts` as a multi-entry rollup `lib.entry` and replace the runtime resolution with a sibling-path that Vite does not intercept (e.g. `path.join(fileURLToPath(import.meta.url), "..", "..", "setup", "global-setup.js")`).
|
||||
- **Option B**: Switch the API — return only a symbolic name and have callers wire the `globalSetup` path themselves in `vitest.config.ts`. Less elegant but immune to bundler quirks.
|
||||
|
||||
### 2. Runtime parity check
|
||||
|
||||
Add a build-output assertion test under `packages/dev/testing-integration/tests/dist-asserts.test.ts` that loads `dist/index.js`, calls `createIntegrationSetup({ x: stub })`, and asserts `existsSync(globalSetup) === true`. This catches future regressions of the same shape.
|
||||
|
||||
### 3. Audit downstream consumers
|
||||
|
||||
Walk every `testing-integration-*` package and migrate any test that reaches for `createIntegrationSetup` to the corrected pattern. None today consumes it for real-container starts, so this is a no-op in practice but worth confirming as part of this change.
|
||||
|
||||
## Impact
|
||||
|
||||
- API change is either zero (Option A) or additive (Option B). No runtime behaviour change once fixed.
|
||||
- Unblocks `@suaveplan/storage-s3` and any future package wanting Garage-backed integration tests using the standard factory instead of hand-rolled `TestEnvironment` plumbing.
|
||||
- Removes `testing-integration` from the project's "avoid the published API" list.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Bun-runtime compatibility for testcontainers (separate change: `testing-integration-bun-runtime-compat`).
|
||||
- Per-fixture `dist/index.js` emission for the seven `testing-integration-*` plugin packages — that is a distinct vite-config bug fixed by the separate change `testing-integration-vite-entry-fix`. The data-URL emission addressed here lives inside `@suaveplan/testing-integration` core; the entry-filename emission addressed there lives in each plugin package's own `vite.config.ts`.
|
||||
- Adding new fixtures or capabilities.
|
||||
- Changing `TestEnvironment` semantics.
|
||||
@@ -0,0 +1,75 @@
|
||||
# Capability Spec Delta: testing-integration (testing-integration-build-fix)
|
||||
|
||||
**Package**: `@suaveplan/testing-integration`
|
||||
**Status**: PROPOSED
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: globalSetup MUST resolve to a real on-disk file
|
||||
|
||||
`createIntegrationSetup()` returns an `IntegrationSetupResult.globalSetup: string` value. After `bun run build`, this string MUST be an absolute filesystem path that exists on disk and that `vitest` can load as a module. It MUST NOT contain a `data:` URL, an `import.meta.url`-derived expression that survives bundling, or any other URL scheme that Vitest cannot pass to `import()`.
|
||||
|
||||
The bug this requirement guards against: Vite library mode treats `new URL("../setup/global-setup.js", import.meta.url).pathname` as an asset reference and inlines the source file as a `data:video/mp2t;base64,<…>` URL during `vite build`. The published artifact at `dist/internal/create-integration-setup-internal.js` then literally returns `"data:video/mp2t;base64,…"` as the `globalSetup` field. Vitest crashes at startup with `ERR_LOAD_URL: Failed to load url <consumer-cwd>/video/mp2t;base64,…` and no consumer can use the public API.
|
||||
|
||||
The fix path declared by `testing-integration-build-fix` is to add `src/setup/global-setup.ts` as a second `lib.entry` in `vite.config.ts` (with `output.entryFileNames: "[name].js"` so `dist/setup/global-setup.js` is actually emitted) and to replace the asset-intercepted `new URL(...).pathname` expression in `src/internal/create-integration-setup-internal.ts` with a Vite-safe alternative — `path.join(fileURLToPath(import.meta.url), "..", "..", "setup", "global-setup.js")` — that Vite does not transform.
|
||||
|
||||
#### Scenario: globalSetup is an existing file path after build
|
||||
|
||||
- **WHEN** the package is built and `createIntegrationSetup({ x: stubFixture }).globalSetup` is read
|
||||
- **THEN** the returned string is an absolute path AND `existsSync(globalSetup) === true`
|
||||
|
||||
#### Scenario: globalSetup is not a data: URL
|
||||
|
||||
- **WHEN** the package is built and `createIntegrationSetup({ x: stubFixture }).globalSetup` is read
|
||||
- **THEN** the returned string does not start with `data:`, `blob:`, or any other non-`file://` URL scheme
|
||||
|
||||
#### Scenario: vitest can load the returned globalSetup
|
||||
|
||||
- **WHEN** a consumer wires `test.globalSetup = [createIntegrationSetup({...}).globalSetup]` in `vitest.config.ts` and runs `vitest run`
|
||||
- **THEN** the runner reaches the global-setup phase without `ERR_LOAD_URL` or any `Failed to load url` error
|
||||
|
||||
**Verified by:** `tests/dist-asserts.test.ts` (added by this change) — loads `dist/index.js`, calls `createIntegrationSetup({ x: stubFixture })`, asserts `existsSync(globalSetup) === true` and that the path does not start with `data:`.
|
||||
|
||||
---
|
||||
|
||||
### Requirement: createIntegrationSetup public API is preserved
|
||||
|
||||
The shape of `createIntegrationSetup<TFixtures>(fixtures: TFixtures): IntegrationSetupResult<TFixtures>` MUST NOT change as part of this fix. Consumers continue to receive `{ globalSetup: string; inject: <K extends keyof TFixtures>(key: K) => InferConfig<TFixtures[K]> }`. The fix is a build-config and internal-resolution change only; no consumer call site needs to be modified.
|
||||
|
||||
#### Scenario: existing callers compile unchanged
|
||||
|
||||
- **WHEN** an existing consumer's `createIntegrationSetup({ surrealdb: new SurrealDBFixture() })` call is type-checked against the post-fix package
|
||||
- **THEN** the call compiles without modification and `globalSetup` and `inject` are typed as before
|
||||
|
||||
**Verified by:** `src/setup/create-integration-setup.test.ts` (existing) AND `tests/dist-asserts.test.ts` (added by this change).
|
||||
|
||||
---
|
||||
|
||||
### Requirement: dist-asserts regression test
|
||||
|
||||
The package SHALL ship a `tests/dist-asserts.test.ts` that runs against the BUILT `dist/index.js` (not the `src/` source) and asserts the `globalSetup` resolution contract above. This test guards against any future refactor that re-introduces an asset-intercepted URL expression in the build output. The test MUST run after `build` so it exercises the published artifact, not the unbundled source.
|
||||
|
||||
#### Scenario: dist-asserts runs against the built artifact
|
||||
|
||||
- **WHEN** the test suite executes
|
||||
- **THEN** the test imports from `../dist/index.js` (or the published entry resolved via `package.json` `exports."."`) and not from `../src/`
|
||||
|
||||
#### Scenario: dist-asserts fails fast when globalSetup is broken
|
||||
|
||||
- **WHEN** `globalSetup` is a `data:` URL or a non-existent path
|
||||
- **THEN** the test fails with a message naming the actual offending value
|
||||
|
||||
**Verified by:** `tests/dist-asserts.test.ts` (added by this change).
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Storage-s3 consumer migrates back to the public API
|
||||
|
||||
After this change ships, `packages/storage/storage-s3/tests/integration/setup.ts` and `packages/storage/storage-s3/tests/integration/global-setup.ts` MUST be migrated from their current hand-rolled `TestEnvironment` driver pattern (the rebel pattern that bypasses the broken `createIntegrationSetup` API) back to the public `createIntegrationSetup({ garageS3: new GarageS3Fixture() })` factory. No subsequent `testing-integration-*` consumer is permitted to ship the rebel pattern.
|
||||
|
||||
#### Scenario: storage-s3 setup uses the public factory
|
||||
|
||||
- **WHEN** `packages/storage/storage-s3/tests/integration/setup.ts` is read after this change ships
|
||||
- **THEN** it imports `createIntegrationSetup` from `@suaveplan/testing-integration` and does not construct a `TestEnvironment` directly
|
||||
|
||||
**Verified by:** code-review against the migrated `setup.ts` and `global-setup.ts` files; the `set-partial.integration.test.ts` suite continues to pass via `bun run test:integration --filter=@suaveplan/storage-s3`.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Tasks: testing-integration-build-fix
|
||||
|
||||
## 1. Build config
|
||||
|
||||
- [x] 1.1 Add `src/setup/global-setup.ts` as a second `lib.entry` in `packages/dev/testing-integration/vite.config.ts` (already present — confirm `entryFileNames: "[name].js"`).
|
||||
- [x] 1.2 Replace `new URL("../setup/global-setup.js", import.meta.url).pathname` in `src/internal/create-integration-setup-internal.ts` with a Vite-safe equivalent (Option A: `path.join(fileURLToPath(import.meta.url), "..", "..", "setup", "global-setup.js")`).
|
||||
- [x] 1.3 Verify `dist/internal/create-integration-setup-internal.js` no longer contains `data:` URLs after build.
|
||||
|
||||
## 2. Regression test
|
||||
|
||||
- [x] 2.1 Add `tests/dist-asserts.test.ts`: build, then load `dist/index.js`, call `createIntegrationSetup({ x: stubFixture })`, assert `existsSync(globalSetup) === true`.
|
||||
- [x] 2.2 Wire it into the `test` script (it must exercise the *built* output, so the test runs after `build`).
|
||||
|
||||
## 3. Downstream sweep
|
||||
|
||||
- [x] 3.1 Confirm `testing-integration-redis|-postgres|-mailpit|-typesense|-surrealdb|-garage-s3|-step-ca` have no broken consumers (currently none).
|
||||
- [x] 3.2 Migrate `packages/storage/storage-s3/tests/integration/setup.ts` from the hand-rolled `TestEnvironment` driver back to `createIntegrationSetup`.
|
||||
|
||||
## 4. Verify
|
||||
|
||||
- [x] 4.1 `bunx turbo lint typecheck test --filter=@suaveplan/testing-integration` green.
|
||||
- [x] 4.2 `bun scripts/openspec-conformance.ts @suaveplan/testing-integration` PASS.
|
||||
Reference in New Issue
Block a user