一键导入
effect-testing
Effect testing with @effect/vitest. Use when any test needs to run Effect programs, test errors, or provide layers.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Effect testing with @effect/vitest. Use when any test needs to run Effect programs, test errors, or provide layers.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Effect service definition, interface design, error types, retries. Use when creating new services or defining error hierarchies.
AXM - Agent Extension Manager: Use for any operation (install/create/new/edit/update/add/remove/delete/publish/find/discover) on agent skills, subagents, slash commands/stored prompts, MCP servers, context packages, rule extensions, hook extensions, or packs — e.g. "create a skill", "make a /command", "add a subagent", "build an MCP server", "publish an extension". Use this BEFORE hand-authoring or editing any SKILL.md, slash-command, subagent, MCP, rule, hook, or extension manifest file: route extension authoring through AXM instead of writing these files directly.
Native skill manifest with two unknown top-level keys.
Effect CLI + Effect architecture. Use when adding commands, defining flags, or wiring handlers. Covers file organization, argument/flag patterns, and testing.
"unterminated
Native skill with an invalid extension name in manifest.
| name | effect-testing |
| description | Effect testing with @effect/vitest. Use when any test needs to run Effect programs, test errors, or provide layers. |
| user-invocable | false |
Use @effect/vitest to run Effect programs directly in tests without bridging
to Promise-land. Stay in Effect-land for cleaner, more idiomatic code.
pnpm add -D @effect/vitest
Requires vitest 1.6.0 or later.
Import from @effect/vitest instead of vitest:
import { Effect } from "effect";
import { describe, expect, it } from "@effect/vitest";
describe("myFunction", () => {
it.effect("returns expected value", () =>
Effect.gen(function* () {
const result = yield* myFunction("input");
expect(result).toBe("expected");
}),
);
});
No async, no await, no runPromise. The test stays in Effect-land.
Use Effect.flip to test expected failures. Flip swaps success and error
channels—if the effect fails, the error becomes the success value:
it.effect("fails with ParseError for invalid input", () =>
Effect.gen(function* () {
const error = yield* parseSource("invalid").pipe(Effect.flip);
expect(error).toBeInstanceOf(ParseError);
}),
);
For asserting the full Exit (success or failure):
import { Exit } from "effect";
it.effect("returns expected exit", () =>
Effect.gen(function* () {
const exit = yield* Effect.exit(divide(4, 0));
expect(exit).toStrictEqual(Exit.fail("Cannot divide by zero"));
}),
);
| Type | Use case |
|---|---|
it.effect | Standard tests with TestContext (TestClock) |
it.live | Tests requiring real time (see below) |
it.scoped | Tests with resources requiring Scope |
it.scopedLive | Scoped tests with live environment |
it.effect.skip | Temporarily skip a test |
it.effect.only | Run only this test |
it.effect.fails | Assert test fails (for tracking known issues) |
When to use it.live:
Date.now() and expect real valuesit.live("...", () => ..., { timeout: 10000 }))Use Effect.provide within the test:
import { NodeFileSystem } from "@effect/platform-node";
it.effect("reads file contents", () =>
Effect.gen(function* () {
const result = yield* readConfig("/path/to/config.json");
expect(result.version).toBe(1);
}).pipe(Effect.provide(NodeFileSystem.layer)),
);
For shared layers across tests, define a helper:
describe("myHandler", () => {
const withTestLayer = <A, E>(effect: Effect.Effect<A, E, MyService>) =>
effect.pipe(Effect.provide(TestMyService));
it.effect("succeeds with valid input", () =>
withTestLayer(
Effect.gen(function* () {
const result = yield* myHandler({ valid: true });
expect(result).toBeDefined();
}),
),
);
});
it.effect provides TestContext including TestClock (starts at 0ms):
import { TestClock, Clock } from "effect";
it.effect("handles timeout", () =>
Effect.gen(function* () {
const fiber = yield* Effect.sleep("1 second").pipe(Effect.fork);
yield* TestClock.adjust("1 second");
yield* fiber.join;
const now = yield* Clock.currentTimeMillis;
expect(now).toBe(1000);
}),
);
it.effect suppresses logs by default. To enable:
import { Logger } from "effect";
it.effect("with logging", () =>
Effect.gen(function* () {
yield* Effect.log("debug message");
}).pipe(Effect.provide(Logger.pretty)),
);
// Or use it.live for real logging
it.live("with live logging", () =>
Effect.gen(function* () {
yield* Effect.log("visible in output");
}),
);