diff options
| author | Shoubhit Dash <[email protected]> | 2026-04-16 17:30:14 +0530 |
|---|---|---|
| committer | Shoubhit Dash <[email protected]> | 2026-04-16 17:30:14 +0530 |
| commit | 2e18a603f0ea24154908e748493fd4bfaa74fc00 (patch) | |
| tree | b723e00af2821b213573b16fa199b64babd5f1f5 /packages/shared/test/lib/effect.ts | |
| parent | 9819eb04614fd607cacb07d754052f1531a82331 (diff) | |
| parent | 7341718f9234b0cf3a8758c87e91d2006b71bff6 (diff) | |
| download | opencode-2e18a603f0ea24154908e748493fd4bfaa74fc00.tar.gz opencode-2e18a603f0ea24154908e748493fd4bfaa74fc00.zip | |
merge dev
Diffstat (limited to 'packages/shared/test/lib/effect.ts')
| -rw-r--r-- | packages/shared/test/lib/effect.ts | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/packages/shared/test/lib/effect.ts b/packages/shared/test/lib/effect.ts new file mode 100644 index 000000000..131ec5cc6 --- /dev/null +++ b/packages/shared/test/lib/effect.ts @@ -0,0 +1,53 @@ +import { test, type TestOptions } from "bun:test" +import { Cause, Effect, Exit, Layer } from "effect" +import type * as Scope from "effect/Scope" +import * as TestClock from "effect/testing/TestClock" +import * as TestConsole from "effect/testing/TestConsole" + +type Body<A, E, R> = Effect.Effect<A, E, R> | (() => Effect.Effect<A, E, R>) + +const body = <A, E, R>(value: Body<A, E, R>) => Effect.suspend(() => (typeof value === "function" ? value() : value)) + +const run = <A, E, R, E2>(value: Body<A, E, R | Scope.Scope>, layer: Layer.Layer<R, E2>) => + Effect.gen(function* () { + const exit = yield* body(value).pipe(Effect.scoped, Effect.provide(layer), Effect.exit) + if (Exit.isFailure(exit)) { + for (const err of Cause.prettyErrors(exit.cause)) { + yield* Effect.logError(err) + } + } + return yield* exit + }).pipe(Effect.runPromise) + +const make = <R, E>(testLayer: Layer.Layer<R, E>, liveLayer: Layer.Layer<R, E>) => { + const effect = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) => + test(name, () => run(value, testLayer), opts) + + effect.only = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) => + test.only(name, () => run(value, testLayer), opts) + + effect.skip = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) => + test.skip(name, () => run(value, testLayer), opts) + + const live = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) => + test(name, () => run(value, liveLayer), opts) + + live.only = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) => + test.only(name, () => run(value, liveLayer), opts) + + live.skip = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) => + test.skip(name, () => run(value, liveLayer), opts) + + return { effect, live } +} + +// Test environment with TestClock and TestConsole +const testEnv = Layer.mergeAll(TestConsole.layer, TestClock.layer()) + +// Live environment - uses real clock, but keeps TestConsole for output capture +const liveEnv = TestConsole.layer + +export const it = make(testEnv, liveEnv) + +export const testEffect = <R, E>(layer: Layer.Layer<R, E>) => + make(Layer.provideMerge(layer, testEnv), Layer.provideMerge(layer, liveEnv)) |
