diff --git a/.changeset/cyan-pans-tan.md b/.changeset/cyan-pans-tan.md new file mode 100644 index 00000000000..80dfaf34cfd --- /dev/null +++ b/.changeset/cyan-pans-tan.md @@ -0,0 +1,5 @@ +--- +"@effect/vitest": minor +--- + +Add fails method. diff --git a/.vscode/settings.json b/.vscode/settings.json index 393a3c822e7..a5826e77e08 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,8 @@ "typescript.tsdk": "node_modules/typescript/lib", "typescript.preferences.importModuleSpecifier": "relative", "typescript.enablePromptUseWorkspaceTsdk": true, + "deno.enable": false, + "biome.enabled": false, "editor.formatOnSave": true, "eslint.format.enable": true, "[json]": { diff --git a/packages/vitest/README.md b/packages/vitest/README.md index 75c9d5b6dd4..6886458b938 100644 --- a/packages/vitest/README.md +++ b/packages/vitest/README.md @@ -212,6 +212,30 @@ it.effect.only("test failure as Exit", () => ) ``` +## Expecting Tests to Fail + +When adding new failing tests, you might not be able to fix them right away. Instead of skipping them, you may want to assert it fails, so that when you fix them, you'll know and can re-enable them before it regresses. + +**Example** (Asserting one test fails) + +```ts +import { it } from "@effect/vitest" +import { Effect, Exit } from "effect" + +function divide(a: number, b: number): number { + if (b === 0) return Effect.fail("Cannot divide by zero") + return Effect.succeed(a / b) +} + +// Temporarily assert the test for divide by zero fails. +it.effect.fails("dividing by zero special cases", ({ expect }) => + Effect.gen(function* () { + const result = yield* Effect.exit(divide(4, 0)) + expect(result).toStrictEqual(0) + }) +) +``` + ## Logging By default, `it.effect` suppresses log output, which can be useful for keeping test results clean. However, if you want to enable logging during tests, you can use `it.live` or provide a custom logger to control the output. diff --git a/packages/vitest/src/index.ts b/packages/vitest/src/index.ts index dbed927fddc..6f385924fe7 100644 --- a/packages/vitest/src/index.ts +++ b/packages/vitest/src/index.ts @@ -53,6 +53,7 @@ export namespace Vitest { each: ( cases: ReadonlyArray ) => (name: string, self: TestFunction>, timeout?: number | V.TestOptions) => void + fails: Vitest.Test /** * @since 1.0.0 diff --git a/packages/vitest/src/internal.ts b/packages/vitest/src/internal.ts index c12b4b657b9..a0d23251dfb 100644 --- a/packages/vitest/src/internal.ts +++ b/packages/vitest/src/internal.ts @@ -97,6 +97,9 @@ const makeTester = ( (args, ctx) => run(ctx, [args], self) as any ) + const fails: Vitest.Vitest.Tester["fails"] = (name, self, timeout) => + V.it.fails(name, (ctx) => run(ctx, [ctx], self), timeout) + const prop: Vitest.Vitest.Tester["prop"] = (name, schemaObj, self, timeout) => { if (Array.isArray(schemaObj)) { const arbs = schemaObj.map((schema) => Arbitrary.make(schema)) @@ -123,7 +126,7 @@ const makeTester = ( ) } - return Object.assign(f, { skip, skipIf, runIf, only, each, prop }) + return Object.assign(f, { skip, skipIf, runIf, only, each, fails, prop }) } export const prop: Vitest.Vitest.Methods["prop"] = (name, schemaObj, self, timeout) => { diff --git a/packages/vitest/test/index.test.ts b/packages/vitest/test/index.test.ts index 4c58da1defd..9905480ba2a 100644 --- a/packages/vitest/test/index.test.ts +++ b/packages/vitest/test/index.test.ts @@ -68,7 +68,7 @@ it.effect.runIf(false)("effect runIf (false)", () => Effect.die("not run anyway" // The following test is expected to fail because it simulates a test timeout. // Be aware that eventual "failure" of the test is only logged out. -it.scopedLive("interrupts on timeout", (ctx) => +it.scopedLive.fails("interrupts on timeout", (ctx) => Effect.gen(function*() { let acquired = false @@ -84,7 +84,7 @@ it.scopedLive("interrupts on timeout", (ctx) => () => Effect.sync(() => acquired = false) ) yield* Effect.sleep(1000) - }), { timeout: 100, fails: true }) + }), 1) class Foo extends Context.Tag("Foo")() { static Live = Layer.succeed(Foo, "foo")