From 87c070415cbeebcc12e492eb2f491520675520ee Mon Sep 17 00:00:00 2001 From: truffle Date: Fri, 29 May 2026 12:15:51 +0000 Subject: [PATCH] fix(vitest): preserve subproperties on chained access through it proxy The `makeItProxy` get trap bound returned functions to the target with `value.bind(target)`, which strips each function's own properties. Chained access like `it.describe.each`, `it.skip.each`, or `it.only.each` therefore resolved to `undefined` and threw `TypeError: ... is not a function`. Drop the bind and return the value as-is. Adds a regression case covering `it.describe.each`, `it.skip.each`, and `it.only.each`. Closes #2301 --- .../fix-vitest-it-proxy-subproperties.md | 5 +++++ packages/vitest/src/internal/internal.ts | 3 +-- packages/vitest/test/index.test.ts | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 .changeset/fix-vitest-it-proxy-subproperties.md diff --git a/.changeset/fix-vitest-it-proxy-subproperties.md b/.changeset/fix-vitest-it-proxy-subproperties.md new file mode 100644 index 0000000000..f4b781757c --- /dev/null +++ b/.changeset/fix-vitest-it-proxy-subproperties.md @@ -0,0 +1,5 @@ +--- +"@effect/vitest": patch +--- + +Fix `it.describe.each`, `it.skip.each`, `it.only.each` (and similar chained access on the `it` proxy) by removing an unnecessary `value.bind(target)` from `makeItProxy`'s `get` trap. The bind stripped each function's own properties (`.each`, `.skip`, `.only`, ...), so `it.describe.each` resolved to `undefined` and threw `TypeError: it.describe.each is not a function`. diff --git a/packages/vitest/src/internal/internal.ts b/packages/vitest/src/internal/internal.ts index 31c7ea1299..03a5f324a3 100644 --- a/packages/vitest/src/internal/internal.ts +++ b/packages/vitest/src/internal/internal.ts @@ -64,8 +64,7 @@ const makeItProxy = ( if (property in overrides) { return Reflect.get(overrides, property) } - const value = Reflect.get(target, property, receiver) - return typeof value === "function" ? value.bind(target) : value + return Reflect.get(target, property, receiver) } }) diff --git a/packages/vitest/test/index.test.ts b/packages/vitest/test/index.test.ts index e6d17d7e5b..74d7b270bf 100644 --- a/packages/vitest/test/index.test.ts +++ b/packages/vitest/test/index.test.ts @@ -33,6 +33,25 @@ it.effect.skip( () => Effect.die("skipped anyway") ) +// chained access through proxy preserves subproperties (regression for +// https://github.com/Effect-TS/effect-smol/issues/2301) + +it.describe("it.describe.each", () => { + it.describe.each(["a", "b"] as const)("%s", (text) => { + it("matches the case label", () => { + assert.include(["a", "b"], text) + }) + }) +}) + +it.skip.each([1, 2])("it.skip.each is skipped (%s)", (n) => { + assert.fail(`should never run for ${n}`) +}) + +it.only.each([] as Array)("it.only.each has no cases", () => { + assert.fail("no cases registered") +}) + // skipIf it.effect.skipIf(true)("effect skipIf (true)", () => Effect.die("skipped anyway"))