cd /news/developer-tools/bun-effect-ts · home topics developer-tools article
[ARTICLE · art-10844] src=gist.github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

bun-effect.ts

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.

read2 min views22 publishedJan 15, 2026

bun-effect.ts

  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

Show hidden characters

/**

  • Minimal Effect test wrapper for Bun's native test runner.

  • This provides it.effect() and it.scoped() that work with bun test, bun's native test runner,

  • similar to @effect/vitest. When the official @effect/bun-test package

  • is released, replace this with that package.

  • @see https://github.com/Effect-TS/effect/pull/5973

  • @example

  • 
    
  • import { describe, expect, it } from "./bun-effect"

  • import { Effect, Layer } from "effect"

  • describe("my test", () => {

  • it.effect("runs an effect", () =>

  • Effect.gen(function* () {
    
  •   const result = yield* someEffect
    
  •   expect(result).toBe(expected)
    
  • }).pipe(Effect.provide(TestLayer))
    
  • )

  • it.scoped("runs a scoped effect", () =>

  • Effect.gen(function* () {
    
  •   const resource = yield* acquireResource
    
  •   expect(resource).toBeDefined()
    
  • })
    
  • )

  • it.effect.skip("skipped test", () => Effect.succeed(1))

  • it.effect.only("only this test", () => Effect.succeed(1))

  • })

  • 
    

*/

import { afterAll, beforeAll, describe, expect, test } from "bun:test"

import { Effect, TestServices } from "effect"

import type { Scope } from "effect"

export { afterAll, beforeAll, describe, expect }

type TestOptions = { timeout?: number }

const runTest = <E, A>(

effect: Effect.Effect<A, E, TestServices.TestServices>,

) => Effect.runPromise(effect.pipe(Effect.provide(TestServices.liveServices)))

const runTestScoped = <E, A>(

effect: Effect.Effect<A, E, TestServices.TestServices | Scope.Scope>,

) =>

Effect.runPromise(

effect.pipe(Effect.scoped, Effect.provide(TestServices.liveServices)),

)

type EffectFn<A, E, R> = () => Effect.Effect<A, E, R>

type EffectTester = {

<A, E>(

name: string,

fn: EffectFn<A, E, TestServices.TestServices>,

options?: number | TestOptions,

): void

skip: <A, E>(

name: string,

fn: EffectFn<A, E, TestServices.TestServices>,

options?: number | TestOptions,

) => void

only: <A, E>(

name: string,

fn: EffectFn<A, E, TestServices.TestServices>,

options?: number | TestOptions,

) => void

}

type ScopedTester = {

<A, E>(

name: string,

fn: EffectFn<A, E, TestServices.TestServices | Scope.Scope>,

options?: number | TestOptions,

): void

skip: <A, E>(

name: string,

fn: EffectFn<A, E, TestServices.TestServices | Scope.Scope>,

options?: number | TestOptions,

) => void

only: <A, E>(

name: string,

fn: EffectFn<A, E, TestServices.TestServices | Scope.Scope>,

options?: number | TestOptions,

) => void

}

const makeEffectTest =

(runner: typeof test) =>

<A, E>(

name: string,

fn: EffectFn<A, E, TestServices.TestServices>,

options?: number | TestOptions,

) => {

const timeout = typeof options === "number" ? options : options?.timeout

runner(name, () => runTest(fn()), timeout ? { timeout } : undefined)

}

const makeScopedTest =

(runner: typeof test) =>

<A, E>(

name: string,

fn: EffectFn<A, E, TestServices.TestServices | Scope.Scope>,

options?: number | TestOptions,

) => {

const timeout = typeof options === "number" ? options : options?.timeout

runner(name, () => runTestScoped(fn()), timeout ? { timeout } : undefined)

}

export const effect: EffectTester = Object.assign(makeEffectTest(test), {

skip: makeEffectTest(test.skip),

only: makeEffectTest(test.only),

})

export const scoped: ScopedTester = Object.assign(makeScopedTest(test), {

skip: makeScopedTest(test.skip),

only: makeScopedTest(test.only),

})

export const it = Object.assign(test, { effect, scoped })

── more in #developer-tools 4 stories · sorted by recency
── more on @effect-ts 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/bun-effect-ts] indexed:0 read:2min 2026-01-15 ·