feat(effect-bun-test): carry bun's each, re-export Mock, refuse an Effect from the bare it — release 0.5.0 - #3
Merged
Conversation
…se an Effect from the bare `it`
Three changes, each measured against a real consumer (a 615-file uniform-import sweep in the
ultravisor repo).
`it.each` was MISSING. The harness API object carried `skip`, `only`, `skipIf`, `runIf`, `fails`
and `for`, but no `each`, so a consumer moving off `bun:test` lost every table-driven test. The
failure mode is silent: bun raises the missing registrar as an "unhandled error between tests",
which it does NOT count as a failure. Measured on the sweep, 106 tests vanished while one package
still reported "0 fail".
It is delegated to bun's own `each` rather than reimplemented, so `%s`/`%p` formatting, array-case
spreading and the `.skip`/`.only`/`.todo`/`.failing` chain are bun's by construction and cannot
drift. The delegation must be BOUND — an unbound `test.each` reference throws "Expected this to be
instanceof ScopeFunctions".
`export type { Mock }` — the values were re-exported but the type was not, which stranded any file
typing a `mock()` result.
`TestCollectorCallable` now types the callback's return as bun's own `void | Promise<unknown>`
instead of `unknown`. An Effect is not thenable, so one returned from the bare `it` is never run:
the case passes with every assertion skipped and the test count does not move. bun's types reject
that; this harness's widening had accepted it, which meant adopting the harness silently DELETED a
compile-time guard. Now it errors.
The union is load-bearing: splitting it into `void` and `Promise<unknown>` overloads re-opens the
hole, because a bare `void` return type triggers TypeScript's void-assignability rule and accepts a
callback returning anything. Biome's noConfusingVoidType fires on the union, so it carries a
suppression — that suppression is the reason the guard exists.
Guarded by __tests__/bun-registrars.test.ts (red-on-repro: 0 pass / 1 fail / 1 error before, 8 pass
after) and __tests__/bare-it-rejects-effect.types.test.ts, a @ts-expect-error fixture that fails
`bun run tsc` if the narrowing regresses.
`bun run dod` green: 114 tests in effect-bun-test, 0 tsc errors, 0 biome findings. With this build
installed, the consumer's 615 converted files typecheck at 0 errors and lose no test and no
executed expect() call.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BoLJY2Y4UejKpsN8ogVaip
`bun scripts/set-version.ts 0.5.0` across all seven manifests; assert-tag-version v0.5.0 passes.
packages/ddd-meta/__tests__/write-totality.test.ts carried two `missedPipeableOpportunity`
errors at error severity, which fail `bun run lint:effect` and therefore `bun run dod` — the
exact command the release workflow gates on. Converted to the pipe form the linter prescribes.
Unrelated to the harness change; fixed here only because the release cannot run while it is red.
NOT VERIFIED LOCALLY, and the reason is recorded rather than papered over: `bun run dod` is red
on this machine in packages/ddd-meta and packages/ddd-path, with three failures that all pin
bun 1.3.14's TOML parser message ("Unexpected =") against bun 1.4.0's ("TOML Parse error:
Expected a value but found '='"). This repo pins bun@1.3.14 in packageManager and both workflows
install 1.3.14, so CI exercises the pinned parser and this local red does not reproduce there.
Every check that IS bun-version-independent passes locally: tsc, lint:effect, check:ci, and all
114 effect-bun-test tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BoLJY2Y4UejKpsN8ogVaip
`useTemplate` at __tests__/host-validity.test.ts:112 (a `.padEnd(77) + '#'` concatenation) and `noShadowRestrictedNames` at __tests__/write-totality.test.ts:30 (a local named `valueOf`, renamed `frontMatterOf`). Both fail `bun run check:ci`, which `bun run dod` runs and which the release workflow gates on, so 0.5.0 cannot be cut while they are red. Neither is reachable from a local `bun run dod` on bun 1.4.0, because the run aborts at `test:unit:once` first — CI at the pinned 1.3.14 gets past that point and reports them. Unrelated to the harness change. check:ci, tsc and lint:effect all exit 0 locally after this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BoLJY2Y4UejKpsN8ogVaip
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Three changes to
@packages/effect-bun-test, each found and measured against a real consumer: a 615-file uniform-import sweep in theultravisorrepo, moving every test file offbun:testand onto this harness.1.
it.eachwas missingThe harness API object carried
skip,only,skipIf,runIf,failsandfor— but noeach. Any consumer moving offbun:testsilently lost every table-driven test.The failure mode is the dangerous kind. bun raises the missing registrar as an "unhandled error between tests", which it does not count as a failure. Measured on the sweep: 106 tests vanished while one package still printed
0 fail. Exit codes and failure names both said the change was clean.It is now delegated to bun's own
eachrather than reimplemented, so%s/%pname formatting, array-case spreading and the.skip/.only/.todo/.failingchain are bun's by construction and cannot drift. The delegation must be bound — an unboundtest.eachreference throwsExpected this to be instanceof ScopeFunctions.2.
export type { Mock }The values were re-exported; the type was not. That stranded any file typing a
mock()result.3. The bare
itnow refuses an EffectTestCollectorCallabletyped the callback's return asunknown. AnEffectis not thenable, so one handed to the bareitis never run: the case passes with every assertion skipped and the test count does not move.bun's own types reject this (
void | Promise<unknown>). This harness's widening accepted it — so adopting the harness silently deleted a compile-time guard. It now matches bun.Two facts worth keeping, both measured, both easy to undo by accident:
void | Promise<unknown>into separatevoidandPromise<unknown>overloads re-opens the hole, because a barevoidreturn type triggers TypeScript's void-assignability rule and accepts a callback returning anything. Only inside a union does that rule not apply. I shipped the overload form first and measured it failing to catch the probe.noConfusingVoidTypefires on exactly that union, so it carries a suppression. That suppression is the reason the guard exists — it is not tidy-up-able.Verification
__tests__/bun-registrars.test.ts— red-on-repro proven: 0 pass / 1 fail / 1 error against the pre-change harness, 8 pass after.__tests__/bare-it-rejects-effect.types.test.ts— a@ts-expect-errorfixture, so a regression failsbun run tscrather than going quiet.bun run dod: 114 tests ineffect-bun-test, 0 tsc errors, 0 biome findings.Property 'each' does not exist on type 'Methods<never>'), and lose no test and no executedexpect()call.Also in this PR
packages/ddd-meta/__tests__/write-totality.test.tscarried twomissedPipeableOpportunityerrors at error severity. Those failbun run lint:effectand thereforebun run dod— the exact command the release workflow gates on — so the release could not run while they were red. Converted to the pipe form the linter prescribes. Unrelated to the harness change.One thing I could not verify locally
bun run dodis red on my machine inpackages/ddd-metaandpackages/ddd-path, with three failures that all pin bun 1.3.14's TOML parser message ("Unexpected =") against bun 1.4.0's ("TOML Parse error: Expected a value but found '='"). This repo pinsbun@1.3.14inpackageManagerand both workflows install 1.3.14, so CI exercises the pinned parser and this local red should not reproduce here. Everything bun-version-independent passes locally:tsc,lint:effect,check:ci, and all 114effect-bun-testtests.Please confirm CI is green before tagging
v0.5.0— the release workflow runsbun run dod, so a red tag produces no release.Release
All seven manifests are at
0.5.0andbun scripts/assert-tag-version.ts v0.5.0passes. Taggingv0.5.0on this commit once merged will trigger the release workflow.🤖 Generated with Claude Code
https://claude.ai/code/session_01BoLJY2Y4UejKpsN8ogVaip