{"slug": "bun-effect-ts", "title": "bun-effect.ts", "summary": "This file provides a minimal test wrapper for Bun's native test runner, implementing `it.effect()` and `it.scoped()` methods that allow testing Effect-TS effects directly with `bun test`. The wrapper includes support for `skip`, `only`, and timeout options, and is designed as a temporary solution until the official `@effect/bun-test` package is released.", "body_md": "bun-effect.ts\n\n      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.\n      \nLearn more about bidirectional Unicode characters\n\n \n    Show hidden characters\n\n/**\n\n * Minimal Effect test wrapper for Bun's native test runner.\n\n *\n\n * This provides `it.effect()` and `it.scoped()` that work with `bun test`, bun's native test runner,\n\n * similar to `@effect/vitest`. When the official `@effect/bun-test` package\n\n * is released, replace this with that package.\n\n *\n\n * @see https://github.com/Effect-TS/effect/pull/5973\n\n *\n\n * @example\n\n * ```ts\n\n * import { describe, expect, it } from \"./bun-effect\"\n\n * import { Effect, Layer } from \"effect\"\n\n *\n\n * describe(\"my test\", () => {\n\n *   it.effect(\"runs an effect\", () =>\n\n *     Effect.gen(function* () {\n\n *       const result = yield* someEffect\n\n *       expect(result).toBe(expected)\n\n *     }).pipe(Effect.provide(TestLayer))\n\n *   )\n\n *\n\n *   it.scoped(\"runs a scoped effect\", () =>\n\n *     Effect.gen(function* () {\n\n *       const resource = yield* acquireResource\n\n *       expect(resource).toBeDefined()\n\n *     })\n\n *   )\n\n *\n\n *   it.effect.skip(\"skipped test\", () => Effect.succeed(1))\n\n *   it.effect.only(\"only this test\", () => Effect.succeed(1))\n\n * })\n\n * ```\n\n */\n\nimport { afterAll, beforeAll, describe, expect, test } from \"bun:test\"\n\nimport { Effect, TestServices } from \"effect\"\n\nimport type { Scope } from \"effect\"\n\nexport { afterAll, beforeAll, describe, expect }\n\ntype TestOptions = { timeout?: number }\n\nconst runTest = <E, A>(\n\n  effect: Effect.Effect<A, E, TestServices.TestServices>,\n\n) => Effect.runPromise(effect.pipe(Effect.provide(TestServices.liveServices)))\n\nconst runTestScoped = <E, A>(\n\n  effect: Effect.Effect<A, E, TestServices.TestServices | Scope.Scope>,\n\n) =>\n\n  Effect.runPromise(\n\n    effect.pipe(Effect.scoped, Effect.provide(TestServices.liveServices)),\n\n  )\n\ntype EffectFn<A, E, R> = () => Effect.Effect<A, E, R>\n\ntype EffectTester = {\n\n  <A, E>(\n\n    name: string,\n\n    fn: EffectFn<A, E, TestServices.TestServices>,\n\n    options?: number | TestOptions,\n\n  ): void\n\n  skip: <A, E>(\n\n    name: string,\n\n    fn: EffectFn<A, E, TestServices.TestServices>,\n\n    options?: number | TestOptions,\n\n  ) => void\n\n  only: <A, E>(\n\n    name: string,\n\n    fn: EffectFn<A, E, TestServices.TestServices>,\n\n    options?: number | TestOptions,\n\n  ) => void\n\n}\n\ntype ScopedTester = {\n\n  <A, E>(\n\n    name: string,\n\n    fn: EffectFn<A, E, TestServices.TestServices | Scope.Scope>,\n\n    options?: number | TestOptions,\n\n  ): void\n\n  skip: <A, E>(\n\n    name: string,\n\n    fn: EffectFn<A, E, TestServices.TestServices | Scope.Scope>,\n\n    options?: number | TestOptions,\n\n  ) => void\n\n  only: <A, E>(\n\n    name: string,\n\n    fn: EffectFn<A, E, TestServices.TestServices | Scope.Scope>,\n\n    options?: number | TestOptions,\n\n  ) => void\n\n}\n\nconst makeEffectTest =\n\n  (runner: typeof test) =>\n\n  <A, E>(\n\n    name: string,\n\n    fn: EffectFn<A, E, TestServices.TestServices>,\n\n    options?: number | TestOptions,\n\n  ) => {\n\n    const timeout = typeof options === \"number\" ? options : options?.timeout\n\n    runner(name, () => runTest(fn()), timeout ? { timeout } : undefined)\n\n  }\n\nconst makeScopedTest =\n\n  (runner: typeof test) =>\n\n  <A, E>(\n\n    name: string,\n\n    fn: EffectFn<A, E, TestServices.TestServices | Scope.Scope>,\n\n    options?: number | TestOptions,\n\n  ) => {\n\n    const timeout = typeof options === \"number\" ? options : options?.timeout\n\n    runner(name, () => runTestScoped(fn()), timeout ? { timeout } : undefined)\n\n  }\n\nexport const effect: EffectTester = Object.assign(makeEffectTest(test), {\n\n  skip: makeEffectTest(test.skip),\n\n  only: makeEffectTest(test.only),\n\n})\n\nexport const scoped: ScopedTester = Object.assign(makeScopedTest(test), {\n\n  skip: makeScopedTest(test.skip),\n\n  only: makeScopedTest(test.only),\n\n})\n\nexport const it = Object.assign(test, { effect, scoped })", "url": "https://wpnews.pro/news/bun-effect-ts", "canonical_source": "https://gist.github.com/dan-myles/5025ffe07df7a0b17e010573e333dda7", "published_at": "2026-01-15 21:55:17+00:00", "updated_at": "2026-05-23 06:35:01.907439+00:00", "lang": "en", "topics": ["developer-tools", "open-source"], "entities": ["Effect-TS", "Bun"], "alternates": {"html": "https://wpnews.pro/news/bun-effect-ts", "markdown": "https://wpnews.pro/news/bun-effect-ts.md", "text": "https://wpnews.pro/news/bun-effect-ts.txt", "jsonld": "https://wpnews.pro/news/bun-effect-ts.jsonld"}}