Skip to content

Testing

Effect programs are values that describe work, so testing them is mostly a matter of running those values and asserting on the result. The @effect/vitest package wires Effect into Vitest so a test can simply return an Effect, and the surrounding machinery runs it, fails the test on an unexpected error, and tears down any scoped resources for you.

Because Effect models time, services, and randomness as data rather than calling into the platform directly, tests can be fully deterministic. Sleeps, timeouts, retries, and schedules are driven by a controllable TestClock instead of real wall-clock time, and the services your code depends on are swapped for in-memory test implementations through Layer.

import { assert, describe, it } from "@effect/vitest"
import { Effect } from "effect"
// A test is just an Effect. `it.effect` runs it and provides the test
// services (TestClock, TestConsole) automatically.
describe("greeting", () => {
it.effect("uppercases the name", () =>
Effect.gen(function*() {
const result = "ada".toUpperCase()
assert.strictEqual(result, "ADA")
}))
})
  • Writing tests — use it.effect to run Effects, assert on results and failures, and parameterize tests with each and property-based testing.
  • TestClock — drive sleeps, timeouts, retries, and schedules forward in virtual time so time-dependent code runs instantly and deterministically.
  • Testing services — provide test implementations of your services as layers, share a layer across a block with layer(...), and inspect state through a test ref.

@effect/vitest builds on Vitest. Add both as dev dependencies:

Terminal window
pnpm add -D vitest @effect/vitest

Then import the enhanced it (and assert, describe, layer) from @effect/vitest instead of from vitest directly:

import { assert, describe, it, layer } from "@effect/vitest"

This it is the standard Vitest test function extended with Effect-aware methods. The most important ones:

MethodDescription
it.effectRun an Effect with the test services provided (TestClock, TestConsole).
it.liveRun an Effect against the live runtime — real clock, real console.
it.effect.eachRun the same Effect test over a table of cases.
it.effect.propProperty-based testing: generate inputs from Schema arbitraries.
it.flakyTestRetry an Effect until it succeeds (or a timeout elapses).
layer(...)Build a layer once and share its services across every test in a block.

Assertions come from the same import: the assert namespace re-exports Vitest’s assert (assert.strictEqual, assert.deepStrictEqual, assert.isTrue, …). Effect-aware helpers for Option, Result, and Exit (assertSome, assertSuccess, assertExitSuccess, …) live in @effect/vitest/utils.