4.7 KiB
OpenSpec Change: testing-integration-bun-runtime-compat
- Change ID: testing-integration-bun-runtime-compat
- Package:
@suaveplan/testing-integration(modify) + everytesting-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:
- 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 (open since 2025-07-24, reproed on Bun 1.3.2 in March 2026) tracks this; community workaround isWait.forLogMessage(...)+ explicit port exposure. uv_version_stringpanic —dockerode(which testcontainers uses for the Docker socket) pullsssh2, whose NAPI sshcrypto.node callsuv_version_stringat module-load. Bun's libuv shim doesn't implement it (oven-sh/bun#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 vitestvia 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'sset-partial.integration.test.tsis 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:integrationTurbo pipeline that invokesnode $(bun pm ls -g vitest | grep ...)(or shellsnpx vitest run) instead ofbunx vitest. Keepstest(unit) on Bun, sendstest:integrationto Node where testcontainers works today. - Add a clear log line + early-skip when
process.versions.bun !== undefinedand 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.tstoWait.forLogMessage(<known-ready-line>, { times: <n> })rather than the defaultforListeningPorts. 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, replacetestcontainerswith a minimal in-repodocker run -dshell +docker execpolling wrapper (pereyueldk'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:testvia the existing@suaveplan/testing/runnerdual-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:integrationonly. Defaultteststays 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-s3integration test will run automatically once Option A lands; no test changes needed.
Out of scope
- The
createIntegrationSetupdata-URL emission bug (separate change:testing-integration-build-fix). - Adding new fixtures.
- Migrating to a different test runner for the unit-test path.