Merge commit '36c66dd290d3ce6eb1ccd310d0c658d4a32bb8eb' as 'repos/effect'

This commit is contained in:
-Puter
2026-07-19 03:25:10 +05:30
parent dd1071cc10
commit 2daf979036
2214 changed files with 673090 additions and 0 deletions

View File

@@ -0,0 +1,259 @@
/**
* @since 4.0.0
*/
import type * as Duration from "effect/Duration"
import type * as Effect from "effect/Effect"
import type * as Layer from "effect/Layer"
import type * as Schema from "effect/Schema"
import type * as Scope from "effect/Scope"
import type * as FC from "effect/testing/FastCheck"
import * as V from "vitest"
import * as internal from "./internal/internal.ts"
/**
* @since 4.0.0
*/
export * from "vitest"
/**
* @since 4.0.0
*/
export type API = V.TestAPI<{}>
/**
* @since 4.0.0
*/
export namespace Vitest {
/**
* @since 4.0.0
*/
export interface TestFunction<A, E, R, TestArgs extends Array<any>> {
(...args: TestArgs): Effect.Effect<A, E, R>
}
/**
* @since 4.0.0
*/
export interface Test<R> {
<A, E>(
name: string,
self: TestFunction<A, E, R, [V.TestContext]>,
timeout?: number | V.TestOptions
): void
}
/**
* @since 4.0.0
*/
export type Arbitraries =
| Array<Schema.Schema<any> | FC.Arbitrary<any>>
| { [K in string]: Schema.Schema<any> | FC.Arbitrary<any> }
/**
* @since 4.0.0
*/
export interface Tester<R> extends Vitest.Test<R> {
skip: Vitest.Test<R>
skipIf: (condition: unknown) => Vitest.Test<R>
runIf: (condition: unknown) => Vitest.Test<R>
only: Vitest.Test<R>
each: <T>(
cases: ReadonlyArray<T>
) => <A, E>(name: string, self: TestFunction<A, E, R, Array<T>>, timeout?: number | V.TestOptions) => void
fails: Vitest.Test<R>
/**
* @since 4.0.0
*/
prop: <const Arbs extends Arbitraries, A, E>(
name: string,
arbitraries: Arbs,
self: TestFunction<
A,
E,
R,
[
{
[K in keyof Arbs]: Arbs[K] extends FC.Arbitrary<infer T> ? T
: Arbs[K] extends Schema.Schema<infer T> ? T
: never
},
V.TestContext
]
>,
timeout?:
| number
| V.TestOptions & {
fastCheck?: FC.Parameters<
{
[K in keyof Arbs]: Arbs[K] extends FC.Arbitrary<infer T> ? T : Arbs[K] extends Schema.Schema<infer T> ? T
: never
}
>
}
) => void
}
/**
* @since 4.0.0
*/
export interface MethodsNonLive<R = never> extends API {
readonly effect: Vitest.Tester<R | Scope.Scope>
readonly flakyTest: <A, E, R2>(
self: Effect.Effect<A, E, R2 | Scope.Scope>,
timeout?: Duration.Input
) => Effect.Effect<A, never, R2>
readonly layer: <R2, E>(layer: Layer.Layer<R2, E, R>, options?: {
readonly timeout?: Duration.Input
}) => {
(f: (it: Vitest.MethodsNonLive<R | R2>) => void): void
(
name: string,
f: (it: Vitest.MethodsNonLive<R | R2>) => void
): void
}
/**
* @since 4.0.0
*/
readonly prop: <const Arbs extends Arbitraries>(
name: string,
arbitraries: Arbs,
self: (
properties: {
[K in keyof Arbs]: Arbs[K] extends FC.Arbitrary<infer T> ? T : Arbs[K] extends Schema.Schema<infer T> ? T
: never
},
ctx: V.TestContext
) => void,
timeout?:
| number
| V.TestOptions & {
fastCheck?: FC.Parameters<
{
[K in keyof Arbs]: Arbs[K] extends FC.Arbitrary<infer T> ? T : Arbs[K] extends Schema.Schema<infer T> ? T
: never
}
>
}
) => void
}
/**
* @since 4.0.0
*/
export interface Methods<R = never> extends MethodsNonLive<R> {
readonly live: Vitest.Tester<Scope.Scope | R>
readonly layer: <R2, E>(layer: Layer.Layer<R2, E, R>, options?: {
readonly memoMap?: Layer.MemoMap
readonly timeout?: Duration.Input
readonly excludeTestServices?: boolean
}) => {
(f: (it: Vitest.MethodsNonLive<R | R2>) => void): void
(
name: string,
f: (it: Vitest.MethodsNonLive<R | R2>) => void
): void
}
}
}
/**
* @since 4.0.0
*/
export const addEqualityTesters: () => void = internal.addEqualityTesters
/**
* @since 4.0.0
*/
export const effect: Vitest.Tester<Scope.Scope> = internal.effect
/**
* @since 4.0.0
*/
export const live: Vitest.Tester<Scope.Scope> = internal.live
/**
* Share a `Layer` between multiple tests, optionally wrapping
* the tests in a `describe` block if a name is provided.
*
* @since 4.0.0
*
* ```ts
* import { expect, layer } from "@effect/vitest"
* import { Effect, Layer, Context } from "effect"
*
* class Foo extends Context.Service("Foo")<Foo, "foo">() {
* static Live = Layer.succeed(Foo, "foo")
* }
*
* class Bar extends Context.Service("Bar")<Bar, "bar">() {
* static Live = Layer.effect(
* Bar,
* Effect.map(Foo, () => "bar" as const)
* )
* }
*
* layer(Foo.Live)("layer", (it) => {
* it.effect("adds context", () =>
* Effect.gen(function*() {
* const foo = yield* Foo
* expect(foo).toEqual("foo")
* }))
*
* it.layer(Bar.Live)("nested", (it) => {
* it.effect("adds context", () =>
* Effect.gen(function*() {
* const foo = yield* Foo
* const bar = yield* Bar
* expect(foo).toEqual("foo")
* expect(bar).toEqual("bar")
* }))
* })
* })
* ```
*/
export const layer: <R, E>(
layer_: Layer.Layer<R, E>,
options?: {
readonly memoMap?: Layer.MemoMap
readonly timeout?: Duration.Input
readonly excludeTestServices?: boolean
}
) => {
(f: (it: Vitest.MethodsNonLive<R>) => void): void
(name: string, f: (it: Vitest.MethodsNonLive<R>) => void): void
} = internal.layer
/**
* @since 4.0.0
*/
export const flakyTest: <A, E, R>(
self: Effect.Effect<A, E, R | Scope.Scope>,
timeout?: Duration.Input
) => Effect.Effect<A, never, R> = internal.flakyTest
/**
* @since 4.0.0
*/
export const prop: Vitest.Methods["prop"] = internal.prop
/**
* @since 4.0.0
*/
/**
* @since 4.0.0
*/
export const it: Vitest.Methods = internal.makeMethods(V.it)
/**
* @since 4.0.0
*/
export const makeMethods: (it: V.TestAPI) => Vitest.Methods = internal.makeMethods
/**
* @since 4.0.0
*/
export const describeWrapped: (name: string, f: (it: Vitest.Methods) => void) => V.SuiteCollector =
internal.describeWrapped

View File

@@ -0,0 +1,371 @@
/**
* @since 4.0.0
*/
import { getCurrentSuite } from "@vitest/runner"
import * as Cause from "effect/Cause"
import * as Duration from "effect/Duration"
import * as Effect from "effect/Effect"
import * as Exit from "effect/Exit"
import { flow, pipe } from "effect/Function"
import * as Layer from "effect/Layer"
import { isObject } from "effect/Predicate"
import * as Schedule from "effect/Schedule"
import * as Schema from "effect/Schema"
import * as Scope from "effect/Scope"
import * as fc from "effect/testing/FastCheck"
import * as TestClock from "effect/testing/TestClock"
import * as TestConsole from "effect/testing/TestConsole"
import * as V from "vitest"
import type * as Vitest from "../index.ts"
const runPromise: <E, A>(
_: Effect.Effect<A, E, never>,
ctx?: V.TestContext | undefined
) => Promise<A> = Effect.fnUntraced(function*<E, A>(effect: Effect.Effect<A, E>, _ctx?: Vitest.TestContext) {
const exit = yield* Effect.exit(effect)
if (Exit.isFailure(exit)) {
const errors = Cause.prettyErrors(exit.cause)
for (let i = 0; i < errors.length; i++) {
yield* Effect.logError(errors[i])
}
}
return yield* exit
}, (effect, _, ctx) => Effect.runPromise(effect, { signal: ctx?.signal }))
/** @internal */
const runTest = (ctx?: Vitest.TestContext) => <E, A>(effect: Effect.Effect<A, E>) => runPromise(effect, ctx)
/** @internal */
export type TestContext = TestConsole.TestConsole | TestClock.TestClock
const TestEnv = Layer.mergeAll(TestConsole.layer, TestClock.layer())
/** @internal */
export const addEqualityTesters = () => {
V.expect.addEqualityTesters([])
}
/** @internal */
const testOptions = (timeout?: number | V.TestOptions) => typeof timeout === "number" ? { timeout } : timeout ?? {}
const hookTimeout = (timeout?: Duration.Input) =>
timeout === undefined ? undefined : Duration.toMillis(Duration.fromInputUnsafe(timeout))
const makeItProxy = <Methods extends object>(
it: V.TestAPI,
overrides: Methods
): Methods & V.TestAPI =>
new Proxy(it as Methods & V.TestAPI, {
apply(target, thisArg, argArray) {
return Reflect.apply(target, thisArg, argArray)
},
get(target, property, receiver) {
if (property in overrides) {
return Reflect.get(overrides, property)
}
// do not bind: binding would strip vitest's static helpers (e.g. `describe.each`)
return Reflect.get(target, property, receiver)
}
})
type CollectedTask = {
readonly type: string
readonly mode?: string
readonly tasks?: ReadonlyArray<CollectedTask>
}
const collectTasks = (tasks: ReadonlyArray<CollectedTask>, acc: Array<V.TestContext["task"]> = []) => {
for (let i = 0; i < tasks.length; i++) {
const task = tasks[i]
if (task.type === "test" && task.mode !== "skip" && task.mode !== "todo") {
acc.push(task as V.TestContext["task"])
} else if (task.tasks !== undefined) {
collectTasks(task.tasks, acc)
}
}
return acc
}
/** @internal */
const makeTester = <R>(
mapEffect: <A, E>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, never>,
it: V.TestAPI = V.it
): Vitest.Vitest.Tester<R> => {
const run = <A, E, TestArgs extends Array<unknown>>(
ctx: V.TestContext & object,
args: TestArgs,
self: Vitest.Vitest.TestFunction<A, E, R, TestArgs>
) => pipe(Effect.suspend(() => self(...args)), mapEffect, runTest(ctx))
const f: Vitest.Vitest.Test<R> = (name, self, timeout) =>
it(name, testOptions(timeout), (ctx) => run(ctx, [ctx], self))
const skip: Vitest.Vitest.Tester<R>["only"] = (name, self, timeout) =>
it.skip(name, testOptions(timeout), (ctx) => run(ctx, [ctx], self))
const skipIf: Vitest.Vitest.Tester<R>["skipIf"] = (condition) => (name, self, timeout) =>
it.skipIf(condition)(name, testOptions(timeout), (ctx) => run(ctx, [ctx], self))
const runIf: Vitest.Vitest.Tester<R>["runIf"] = (condition) => (name, self, timeout) =>
it.runIf(condition)(name, testOptions(timeout), (ctx) => run(ctx, [ctx], self))
const only: Vitest.Vitest.Tester<R>["only"] = (name, self, timeout) =>
it.only(name, testOptions(timeout), (ctx) => run(ctx, [ctx], self))
const each: Vitest.Vitest.Tester<R>["each"] = (cases) => (name, self, timeout) =>
it.for(cases)(
name,
testOptions(timeout),
(args, ctx) => run(ctx, [args], self) as any
)
const fails: Vitest.Vitest.Tester<R>["fails"] = (name, self, timeout) =>
V.it.fails(name, testOptions(timeout), (ctx) => run(ctx, [ctx], self))
const prop: Vitest.Vitest.Tester<R>["prop"] = (name, arbitraries, self, timeout) => {
if (Array.isArray(arbitraries)) {
const arbs = arbitraries.map((arbitrary) => {
if (Schema.isSchema(arbitrary)) {
return Schema.toArbitrary(arbitrary)
}
return arbitrary as fc.Arbitrary<any>
})
return it(
name,
testOptions(timeout),
(ctx) =>
// @ts-ignore
fc.assert(
// @ts-ignore
fc.asyncProperty(...arbs, (...as) => run(ctx, [as as any, ctx], self)),
// @ts-ignore
isObject(timeout) ? timeout?.fastCheck : {}
)
)
}
const arbs = fc.record(
Object.keys(arbitraries).reduce(function(result, key) {
const arb: any = arbitraries[key]
result[key] = Schema.isSchema(arb) ? Schema.toArbitrary(arb) : arb
return result
}, {} as Record<string, fc.Arbitrary<any>>)
)
return it(
name,
testOptions(timeout),
(ctx) =>
// @ts-ignore
fc.assert(
fc.asyncProperty(arbs, (...as) =>
// @ts-ignore
run(ctx, [as[0] as any, ctx], self)),
// @ts-ignore
isObject(timeout) ? timeout?.fastCheck : {}
)
)
}
return Object.assign(f, { skip, skipIf, runIf, only, each, fails, prop })
}
/** @internal */
export const prop: Vitest.Vitest.Methods["prop"] = (name, arbitraries, self, timeout) => {
if (Array.isArray(arbitraries)) {
const arbs = arbitraries.map((arbitrary) => {
if (Schema.isSchema(arbitrary)) {
throw new Error("Schemas are not supported yet")
}
return arbitrary
})
return V.it(
name,
testOptions(timeout),
// @ts-ignore
(ctx) => fc.assert(fc.property(...arbs, (...as) => self(as, ctx)), isObject(timeout) ? timeout?.fastCheck : {})
)
}
const arbs = fc.record(
Object.keys(arbitraries).reduce(function(result, key) {
const arb: any = arbitraries[key]
if (Schema.isSchema(arb)) {
throw new Error("Schemas are not supported yet")
}
result[key] = arb
return result
}, {} as Record<string, fc.Arbitrary<any>>)
)
return V.it(
name,
testOptions(timeout),
// @ts-ignore
(ctx) => fc.assert(fc.property(arbs, (as) => self(as, ctx)), isObject(timeout) ? timeout?.fastCheck : {})
)
}
/** @internal */
export const layer = <R, E>(
layer_: Layer.Layer<R, E>,
options?: {
readonly memoMap?: Layer.MemoMap
readonly timeout?: Duration.Input
readonly excludeTestServices?: boolean
}
): {
(f: (it: Vitest.Vitest.MethodsNonLive<R>) => void): void
(
name: string,
f: (it: Vitest.Vitest.MethodsNonLive<R>) => void
): void
} =>
(
...args: [
name: string,
f: (
it: Vitest.Vitest.MethodsNonLive<R>
) => void
] | [
f: (it: Vitest.Vitest.MethodsNonLive<R>) => void
]
) => {
const excludeTestServices = options?.excludeTestServices ?? false
const withTestEnv = excludeTestServices
? layer_ as Layer.Layer<R, E>
: Layer.provideMerge(layer_, TestEnv)
const memoMap = options?.memoMap ?? Effect.runSync(Layer.makeMemoMap)
const scope = Effect.runSync(Scope.make())
const contextEffect = Layer.buildWithMemoMap(withTestEnv, memoMap, scope).pipe(
Effect.orDie,
Effect.cached,
Effect.runSync
)
let closed = false
const closeScope = (ctx?: Vitest.TestContext) => {
if (closed) {
return Promise.resolve()
}
closed = true
return runPromise(Scope.close(scope, Exit.void), ctx)
}
const makeIt = (it: V.TestAPI): Vitest.Vitest.MethodsNonLive<R> =>
makeItProxy(it, {
effect: makeTester<R | Scope.Scope>(
(effect) =>
Effect.flatMap(contextEffect, (context) =>
effect.pipe(
Effect.scoped,
Effect.provide(context)
)),
it
),
prop,
flakyTest,
layer<R2, E2>(nestedLayer: Layer.Layer<R2, E2, R>, options?: {
readonly timeout?: Duration.Input
}) {
return layer(Layer.provideMerge(nestedLayer, withTestEnv), {
...options,
memoMap: Layer.forkMemoMapUnsafe(memoMap),
excludeTestServices
})
}
})
if (args.length === 1) {
const currentSuite = getCurrentSuite()
const previousTasks = new Set(currentSuite.tasks)
args[0](makeIt(V.it))
const blockTasks = collectTasks(
currentSuite.tasks.filter((task) => !previousTasks.has(task)) as ReadonlyArray<CollectedTask>
)
if (blockTasks.length === 0) {
V.afterAll(() => closeScope(), hookTimeout(options?.timeout))
return
}
const blockTaskSet = new Set(blockTasks)
let remaining = blockTasks.length
V.beforeEach(
(ctx) => {
if (!blockTaskSet.has(ctx.task)) {
return
}
ctx.onTestFinished(() => {
remaining--
if (remaining === 0) {
return closeScope(ctx)
}
})
return runPromise(Effect.asVoid(contextEffect), ctx)
},
hookTimeout(options?.timeout)
)
V.afterAll(() => closeScope(), hookTimeout(options?.timeout))
return
}
return V.describe(args[0], () => {
V.beforeAll(
() => runPromise(Effect.asVoid(contextEffect)),
hookTimeout(options?.timeout)
)
V.afterAll(
() => closeScope(),
hookTimeout(options?.timeout)
)
return args[1](makeIt(V.it))
})
}
/** @internal */
export const flakyTest = <A, E, R>(
self: Effect.Effect<A, E, R | Scope.Scope>,
timeout: Duration.Input = Duration.seconds(30)
) =>
pipe(
self,
Effect.scoped,
Effect.sandbox,
Effect.retry(
pipe(
Schedule.recurs(10),
Schedule.while((_) =>
Effect.succeed(Duration.isLessThanOrEqualTo(
Duration.fromInputUnsafe(_.elapsed),
Duration.fromInputUnsafe(timeout)
))
)
)
),
Effect.orDie
)
/** @internal */
export const makeMethods = (it: V.TestAPI): Vitest.Vitest.Methods =>
makeItProxy(it, {
effect: makeTester<Scope.Scope>(flow(Effect.scoped, Effect.provide(TestEnv)), it),
live: makeTester<Scope.Scope>(Effect.scoped, it),
flakyTest,
layer,
prop
})
/** @internal */
export const {
/** @internal */
effect,
/** @internal */
live
} = makeMethods(V.it)
/** @internal */
export const describeWrapped = (name: string, f: (it: Vitest.Vitest.Methods) => void): V.SuiteCollector =>
V.describe(name, (it) => f(makeMethods(it)))

View File

@@ -0,0 +1,321 @@
/**
* Provides assertion helpers used by `@effect/vitest` tests.
*
* This module defines small assertion functions built on Node's `assert`,
* Vitest's instance checks, and Effect's equality support. The helpers cover
* basic equality, thrown errors, defined and undefined values, strings, regular
* expressions, class instances, `Option`, `Result`, and `Exit`. Most helpers are
* synchronous; `throwsAsync` handles rejected promises.
*
* @since 4.0.0
*/
import type * as Cause from "effect/Cause"
import * as Equal from "effect/Equal"
import * as Exit from "effect/Exit"
import * as Option from "effect/Option"
import * as Predicate from "effect/Predicate"
import * as Result from "effect/Result"
import * as assert from "node:assert"
import { assert as vassert } from "vitest"
// ----------------------------
// Primitives
// ----------------------------
/**
* Fails the current test with the provided error message.
*
* @category testing
* @since 4.0.0
*/
export function fail(message: string) {
assert.fail(message)
}
/**
* Asserts that `actual` is deeply strictly equal to `expected` using Node's `assert.deepStrictEqual`.
*
* @category testing
* @since 4.0.0
*/
export function deepStrictEqual<A>(actual: A, expected: A, message?: string, ..._: Array<never>) {
assert.deepStrictEqual(actual, expected, message as string)
}
/**
* Asserts that `actual` is not deeply strictly equal to `expected` using Node's `assert.notDeepStrictEqual`.
*
* @category testing
* @since 4.0.0
*/
export function notDeepStrictEqual<A>(actual: A, expected: A, message?: string, ..._: Array<never>) {
assert.notDeepStrictEqual(actual, expected, message as string)
}
/**
* Asserts that `actual` is strictly equal to `expected` using Node's `assert.strictEqual`.
*
* @category testing
* @since 4.0.0
*/
export function strictEqual<A>(actual: A, expected: A, message?: string, ..._: Array<never>) {
assert.strictEqual(actual, expected, message as string)
}
/**
* Asserts that `actual` is equal to `expected` using the `Equal.equals` trait.
*
* @category testing
* @since 4.0.0
*/
export function assertEquals<A>(actual: A, expected: A, message?: string, ..._: Array<never>) {
if (!Equal.equals(actual, expected)) {
deepStrictEqual(actual, expected, message) // show diff
fail(message ?? "Expected values to be Equal.equals")
}
}
/**
* Asserts that `thunk` does not throw an error.
*
* @category testing
* @since 4.0.0
*/
export function doesNotThrow(thunk: () => void, message?: string, ..._: Array<never>) {
assert.doesNotThrow(thunk, message)
}
// ----------------------------
// Derived
// ----------------------------
/**
* Asserts that `value` is an instance of `constructor`.
*
* @category testing
* @since 4.0.0
*/
export function assertInstanceOf<C extends abstract new(...args: any) => any>(
value: unknown,
constructor: C,
message?: string,
..._: Array<never>
): asserts value is InstanceType<C> {
vassert.instanceOf(value, constructor as any, message)
}
/**
* Asserts that `self` is `true`.
*
* @category testing
* @since 4.0.0
*/
export function assertTrue(self: unknown, message?: string, ..._: Array<never>): asserts self {
strictEqual(self, true, message)
}
/**
* Asserts that `self` is `false`.
*
* @category testing
* @since 4.0.0
*/
export function assertFalse(self: boolean, message?: string, ..._: Array<never>) {
strictEqual(self, false, message)
}
/**
* Asserts that `actual` includes `expected`.
*
* @category testing
* @since 4.0.0
*/
export function assertInclude(actual: string | undefined, expected: string, ..._: Array<never>) {
if (typeof expected === "string") {
if (!actual?.includes(expected)) {
fail(`Expected\n\n${actual}\n\nto include\n\n${expected}`)
}
}
}
/**
* Asserts that `actual` matches `regExp`.
*
* @category testing
* @since 4.0.0
*/
export function assertMatch(actual: string, regExp: RegExp, ..._: Array<never>) {
if (!regExp.test(actual)) {
fail(`Expected\n\n${actual}\n\nto match\n\n${regExp}`)
}
}
/**
* Asserts that `thunk` throws, optionally checking the thrown value against an expected `Error` or validation function.
*
* @category testing
* @since 4.0.0
*/
export function throws(thunk: () => void, error?: Error | ((u: unknown) => undefined), ..._: Array<never>) {
try {
thunk()
fail("Expected to throw an error")
} catch (e) {
if (error !== undefined) {
if (Predicate.isFunction(error)) {
error(e)
} else if (error) {
deepStrictEqual(e, error)
} else {
throw e
}
}
}
}
/**
* Asserts that `thunk` throws or returns a rejected promise, optionally checking the failure value against an expected `Error` or validation function.
*
* @category testing
* @since 4.0.0
*/
export async function throwsAsync(
thunk: () => Promise<void>,
error?: Error | ((u: unknown) => undefined),
..._: Array<never>
) {
try {
await thunk()
fail("Expected to throw an error")
} catch (e) {
if (error !== undefined) {
if (Predicate.isFunction(error)) {
error(e)
} else {
deepStrictEqual(e, error)
}
}
}
}
// ----------------------------
// Option
// ----------------------------
/**
* Asserts that `option` is `None`.
*
* @category testing
* @since 4.0.0
*/
export function assertNone<A>(option: Option.Option<A>, ..._: Array<never>): asserts option is Option.None<never> {
deepStrictEqual(option, Option.none())
}
/**
* Asserts that `a` is not `undefined`.
*
* @category testing
* @since 4.0.0
*/
export function assertDefined<A>(
a: A | undefined,
..._: Array<never>
): asserts a is Exclude<A, undefined> {
if (a === undefined) {
fail("Expected value to be defined")
}
}
/**
* Asserts that `a` is `undefined`.
*
* @category testing
* @since 4.0.0
*/
export function assertUndefined<A>(
a: A | undefined,
..._: Array<never>
): asserts a is undefined {
if (a !== undefined) {
fail("Expected value to be undefined")
}
}
/**
* Asserts that `option` is `Some` and contains a value equal to `expected`.
*
* @category testing
* @since 4.0.0
*/
export function assertSome<A>(
option: Option.Option<A>,
expected: A,
..._: Array<never>
): asserts option is Option.Some<A> {
deepStrictEqual(option, Option.some(expected))
}
// ----------------------------
// Result
// ----------------------------
/**
* Asserts that `result` is `Success` and contains a value equal to `expected`.
*
* @category testing
* @since 4.0.0
*/
export function assertSuccess<A, E>(
result: Result.Result<A, E>,
expected: A,
..._: Array<never>
): asserts result is Result.Success<A, never> {
deepStrictEqual(result, Result.succeed(expected))
}
/**
* Asserts that `result` is `Failure` and contains an error equal to `expected`.
*
* @category testing
* @since 4.0.0
*/
export function assertFailure<A, E>(
result: Result.Result<A, E>,
expected: E,
..._: Array<never>
): asserts result is Result.Failure<never, E> {
deepStrictEqual(result, Result.fail(expected))
}
// ----------------------------
// Exit
// ----------------------------
/**
* Asserts that `exit` is a failure with a cause equal to `expected`.
*
* @category testing
* @since 4.0.0
*/
export function assertExitFailure<A, E>(
exit: Exit.Exit<A, E>,
expected: Cause.Cause<E>,
..._: Array<never>
): asserts exit is Exit.Failure<never, E> {
deepStrictEqual(exit, Exit.failCause(expected))
}
/**
* Asserts that `exit` is a success with a value equal to `expected`.
*
* @category testing
* @since 4.0.0
*/
export function assertExitSuccess<A, E>(
exit: Exit.Exit<A, E>,
expected: A,
..._: Array<never>
): asserts exit is Exit.Success<A, never> {
deepStrictEqual(exit, Exit.succeed(expected))
}