68 lines
4.7 KiB
Markdown
68 lines
4.7 KiB
Markdown
# OpenSpec Change: testing-integration-bun-runtime-compat
|
|
|
|
- **Change ID**: testing-integration-bun-runtime-compat
|
|
- **Package**: `@suaveplan/testing-integration` (modify) + every `testing-integration-*` package
|
|
- **Status**: PROPOSED
|
|
- **Date**: 2026-04-28
|
|
|
|
## Summary
|
|
|
|
Make `bunx vitest run` actually start testcontainers in this monorepo. Today every `testing-integration-*` package lands in env-bridge mode only; the moment a fixture tries to spin a container it crashes or hangs. Two distinct Bun limitations are stacked on top of each other:
|
|
|
|
1. **Default wait strategy hangs** — testcontainers' default `Wait.forListeningPorts()` runs port probes inside Bun's net stack and never resolves on macOS/Linux. Bun issue [oven-sh/bun#21342](https://github.com/oven-sh/bun/issues/21342) (open since 2025-07-24, reproed on Bun 1.3.2 in March 2026) tracks this; community workaround is `Wait.forLogMessage(...)` + explicit port exposure.
|
|
2. **`uv_version_string` panic** — `dockerode` (which testcontainers uses for the Docker socket) pulls `ssh2`, whose NAPI sshcrypto.node calls `uv_version_string` at module-load. Bun's libuv shim doesn't implement it ([oven-sh/bun#18546](https://github.com/oven-sh/bun/issues/18546)). Crashes the runner before any fixture runs.
|
|
|
|
Today's symptom in this repo: `bun run --filter=@suaveplan/storage-s3 test:integration` panics on the second issue before the first is even reached.
|
|
|
|
## Current state
|
|
|
|
- Repo standard runner: `bunx vitest` via Turbo. CLAUDE.md mandates Bun for everything.
|
|
- All existing `testing-integration-*` unit tests inject fakes (`containerFactory`, `execFn`, `fetchFn`); no test in the monorepo has ever exercised a real container under Bun.
|
|
- `@suaveplan/storage-s3`'s `set-partial.integration.test.ts` is the first real consumer; on Bun it skips with no useful diagnostic.
|
|
|
|
## What changes
|
|
|
|
Three options, with cost increasing:
|
|
|
|
### Option A (cheapest): Document + dual-runner switch
|
|
|
|
- Add a project-wide `test:integration` Turbo pipeline that invokes `node $(bun pm ls -g vitest | grep ...)` (or shells `npx vitest run`) instead of `bunx vitest`. Keeps `test` (unit) on Bun, sends `test:integration` to Node where testcontainers works today.
|
|
- Add a clear log line + early-skip when `process.versions.bun !== undefined` and the fixture would start a container.
|
|
- Update CLAUDE.md to note the runtime split for `test:integration`.
|
|
|
|
Time-to-green: hours. Tradeoff: Bun-purity violation for one task.
|
|
|
|
### Option B (medium): Bun-friendly fixture defaults + bun-test-compatible wiring
|
|
|
|
Per Bun #21342 the wait-strategy hang is the load-bearing issue, not `uv_version_string`. The `ssh2` panic only fires because `dockerode` is in the dependency graph; testcontainers v11+ uses `dockerode-modem`-light paths for most operations, and **modeshift** ports of testcontainers exist that drop ssh2 entirely.
|
|
|
|
Plan:
|
|
|
|
- Pin every `*-fixture.ts` to `Wait.forLogMessage(<known-ready-line>, { times: <n> })` rather than the default `forListeningPorts`. Per #21342 thumbs-up workaround this resolves the hang on Bun 1.3.0+.
|
|
- Audit testcontainers deps for `ssh2`. If it's still pulled in transitively, replace `testcontainers` with a minimal in-repo `docker run -d` shell + `docker exec` polling wrapper (per `eyueldk`'s working pattern, comment 2025-11-23). The seven-step Garage init sequence already shells out, so this is mostly pre-paved.
|
|
- Migrate fixture self-tests to `bun:test` via the existing `@suaveplan/testing/runner` dual-runner abstraction.
|
|
|
|
Time-to-green: ~1 sprint. Tradeoff: forking testcontainers behaviour; carry-cost.
|
|
|
|
### Option C: Wait for upstream
|
|
|
|
Track Bun #21342. Currently the team has not assigned a milestone (open + unprioritised at 9 months old). Not a viable plan — would block real container coverage indefinitely.
|
|
|
|
## Recommendation
|
|
|
|
**Ship Option A immediately** — unblocks `@suaveplan/storage-s3` and any other package wanting real-container coverage today, with a one-runner-deviation cost that's clearly documented.
|
|
|
|
**Plan Option B as a follow-up** once we have ≥3 `*-integration` packages actively consuming containers. By then the Bun upstream picture may also have moved.
|
|
|
|
## Impact
|
|
|
|
- Option A: Adds a divergent runner for `test:integration` only. Default `test` stays on Bun. Roughly +20s startup per integration run (Node spin-up + module resolution).
|
|
- Unblocks every existing `testing-integration-*` package for real-container coverage today.
|
|
- `@suaveplan/storage-s3` integration test will run automatically once Option A lands; no test changes needed.
|
|
|
|
## Out of scope
|
|
|
|
- The `createIntegrationSetup` data-URL emission bug (separate change: `testing-integration-build-fix`).
|
|
- Adding new fixtures.
|
|
- Migrating to a different test runner for the unit-test path.
|