effect-patterns-testing
Effect-TS patterns for Testing. Use when working with testing in Effect-TS applications.
Install
mkdir -p .claude/skills/effect-patterns-testing && curl -L -o skill.zip "https://mcp.directory/api/skills/download/6402" && unzip -o skill.zip -d .claude/skills/effect-patterns-testing && rm skill.zipInstalls to .claude/skills/effect-patterns-testing
About this skill
Effect-TS Patterns: Testing
This skill provides 10 curated Effect-TS patterns for testing. Use this skill when working on tasks related to:
- testing
- Best practices in Effect-TS applications
- Real-world patterns and solutions
🟢 Beginner Patterns
Your First Effect Test
Rule: Use Effect.runPromise in tests to run and assert on Effect results.
Good Example:
import { describe, it, expect } from "vitest"
import { Effect } from "effect"
// ============================================
// Code to test
// ============================================
const add = (a: number, b: number): Effect.Effect<number> =>
Effect.succeed(a + b)
const divide = (a: number, b: number): Effect.Effect<number, Error> =>
b === 0
? Effect.fail(new Error("Cannot divide by zero"))
: Effect.succeed(a / b)
const fetchUser = (id: string): Effect.Effect<{ id: string; name: string }> =>
Effect.succeed({ id, name: `User ${id}` })
// ============================================
// Tests
// ============================================
describe("Basic Effect Tests", () => {
it("should add two numbers", async () => {
const result = await Effect.runPromise(add(2, 3))
expect(result).toBe(5)
})
it("should divide numbers", async () => {
const result = await Effect.runPromise(divide(10, 2))
expect(result).toBe(5)
})
it("should fail on divide by zero", async () => {
await expect(Effect.runPromise(divide(10, 0))).rejects.toThrow(
"Cannot divide by zero"
)
})
it("should fetch a user", async () => {
const user = await Effect.runPromise(fetchUser("123"))
expect(user).toEqual({
id: "123",
name: "User 123",
})
})
})
// ============================================
// Testing Effect.gen programs
// ============================================
const calculateDiscount = (price: number, quantity: number) =>
Effect.gen(function* () {
if (price <= 0) {
return yield* Effect.fail(new Error("Invalid price"))
}
const subtotal = price * quantity
const discount = quantity >= 10 ? 0.1 : 0
const total = subtotal * (1 - discount)
return { subtotal, discount, total }
})
describe("Effect.gen Tests", () => {
it("should calculate without discount", async () => {
const result = await Effect.runPromise(calculateDiscount(10, 5))
expect(result.subtotal).toBe(50)
expect(result.discount).toBe(0)
expect(result.total).toBe(50)
})
it("should apply bulk discount", async () => {
const result = await Effect.runPromise(calculateDiscount(10, 10))
expect(result.subtotal).toBe(100)
expect(result.discount).toBe(0.1)
expect(result.total).toBe(90)
})
it("should fail for invalid price", async () => {
await expect(
Effect.runPromise(calculateDiscount(-5, 10))
).rejects.toThrow("Invalid price")
})
})
Rationale:
Test Effect programs by running them with Effect.runPromise and using standard test assertions on the results.
Testing Effect code is straightforward:
- Effects are values - Build them in tests like any other value
- Run to get results - Use
Effect.runPromiseto execute - Assert normally - Standard assertions work on the results
Test Effects with Services
Rule: Provide test implementations of services to make Effect programs testable.
Good Example:
import { describe, it, expect } from "vitest"
import { Effect, Context } from "effect"
// ============================================
// 1. Define a service
// ============================================
class UserRepository extends Context.Tag("UserRepository")<
UserRepository,
{
readonly findById: (id: string) => Effect.Effect<User | null>
readonly save: (user: User) => Effect.Effect<void>
}
>() {}
interface User {
id: string
name: string
email: string
}
// ============================================
// 2. Code that uses the service
// ============================================
const getUser = (id: string) =>
Effect.gen(function* () {
const repo = yield* UserRepository
const user = yield* repo.findById(id)
if (!user) {
return yield* Effect.fail(new Error(`User ${id} not found`))
}
return user
})
const createUser = (name: string, email: string) =>
Effect.gen(function* () {
const repo = yield* UserRepository
const user: User = {
id: crypto.randomUUID(),
name,
email,
}
yield* repo.save(user)
return user
})
// ============================================
// 3. Create a test implementation
// ============================================
const makeTestUserRepository = (initialUsers: User[] = []) => {
const users = new Map(initialUsers.map(u => [u.id, u]))
return UserRepository.of({
findById: (id) => Effect.succeed(users.get(id) ?? null),
save: (user) => Effect.sync(() => { users.set(user.id, user) }),
})
}
// ============================================
// 4. Write tests
// ============================================
describe("User Service Tests", () => {
it("should find an existing user", async () => {
const testUser: User = {
id: "123",
name: "Alice",
email: "alice@example.com",
}
const testRepo = makeTestUserRepository([testUser])
const result = await Effect.runPromise(
getUser("123").pipe(
Effect.provideService(UserRepository, testRepo)
)
)
expect(result).toEqual(testUser)
})
it("should fail when user not found", async () => {
const testRepo = makeTestUserRepository([])
await expect(
Effect.runPromise(
getUser("999").pipe(
Effect.provideService(UserRepository, testRepo)
)
)
).rejects.toThrow("User 999 not found")
})
it("should create and save a user", async () => {
const savedUsers: User[] = []
const trackingRepo = UserRepository.of({
findById: () => Effect.succeed(null),
save: (user) => Effect.sync(() => { savedUsers.push(user) }),
})
const result = await Effect.runPromise(
createUser("Bob", "bob@example.com").pipe(
Effect.provideService(UserRepository, trackingRepo)
)
)
expect(result.name).toBe("Bob")
expect(result.email).toBe("bob@example.com")
expect(savedUsers).toHaveLength(1)
expect(savedUsers[0].name).toBe("Bob")
})
})
Rationale:
When testing Effects that require services, provide test implementations using Effect.provideService or test layers.
Effect's service pattern makes testing easy:
- Declare dependencies - Effects specify what they need
- Inject test doubles - Provide fake implementations for tests
- No mocking libraries - Just provide different service implementations
- Type-safe - Compiler ensures you provide all dependencies
🟡 Intermediate Patterns
Accessing the Current Time with Clock
Rule: Use the Clock service to get the current time, enabling deterministic testing with TestClock.
Good Example:
This example shows a function that checks if a token is expired. Its logic depends on Clock, making it fully testable.
import { Effect, Clock, Duration } from "effect";
interface Token {
readonly value: string;
readonly expiresAt: number; // UTC milliseconds
}
// This function is pure and testable because it depends on Clock
const isTokenExpired = (
token: Token
): Effect.Effect<boolean, never, Clock.Clock> =>
Clock.currentTimeMillis.pipe(
Effect.map((now) => now > token.expiresAt),
Effect.tap((expired) =>
Clock.currentTimeMillis.pipe(
Effect.flatMap((currentTime) =>
Effect.log(
`Token expired? ${expired} (current time: ${new Date(currentTime).toISOString()})`
)
)
)
)
);
// Create a test clock service that advances time
const makeTestClock = (timeMs: number): Clock.Clock => ({
currentTimeMillis: Effect.succeed(timeMs),
currentTimeNanos: Effect.succeed(BigInt(timeMs * 1_000_000)),
sleep: (duration: Duration.Duration) => Effect.succeed(void 0),
unsafeCurrentTimeMillis: () => timeMs,
unsafeCurrentTimeNanos: () => BigInt(timeMs * 1_000_000),
[Clock.ClockTypeId]: Clock.ClockTypeId,
});
// Create a token that expires in 1 second
const token = { value: "abc", expiresAt: Date.now() + 1000 };
// Check token expiry with different clocks
const program = Effect.gen(function* () {
// Check with current time
yield* Effect.log("Checking with current time...");
yield* isTokenExpired(token);
// Check with past time
yield* Effect.log("\nChecking with past time (1 minute ago)...");
const pastClock = makeTestClock(Date.now() - 60_000);
yield* isTokenExpired(token).pipe(
Effect.provideService(Clock.Clock, pastClock)
);
// Check with future time
yield* Effect.log("\nChecking with future time (1 hour ahead)...");
const futureClock = makeTestClock(Date.now() + 3600_000);
yield* isTokenExpired(token).pipe(
Effect.provideService(Clock.Clock, futureClock)
);
});
// Run the program with default clock
Effect.runPromise(
program.pipe(Effect.provideService(Clock.Clock, makeTestClock(Date.now())))
);
Anti-Pattern:
Directly calling Date.now() inside your business logic. This creates an impure function that cannot be tested reliably without manipulating the system clock, which is a bad practice.
import { Effect } from "effect";
interface Token {
readonly expiresAt: number;
}
// ❌ WRONG: This function's behavior changes every millisecond.
const isTokenExpiredUnsafely = (token: Token): Effect.Effect<boolean> =>
Effect.sync(() => Date.now() > token.expiresAt);
// Testing this function would require complex mocking of global APIs
// or would be non-deterministic.
Rationale:
Whenever you need to get the current ti
Content truncated.
More by PaulJPhilp
View all skills by PaulJPhilp →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversMCP server connects Claude and AI coding tools to shadcn/ui components. Accurate TypeScript props and React component da
Boost your AI code assistant with Context7: inject real-time API documentation from OpenAPI specification sources into y
Enhance software testing with Playwright MCP: Fast, reliable browser automation, an innovative alternative to Selenium s
Advanced MCP server enabling AI agents to autonomously run 150+ security and penetration testing tools. Covers reconnais
Supercharge browser tasks with Browser MCP—AI-driven, local browser automation for powerful, private testing. Inspired b
Playwright automates web browsers for web scraping, scraping, and internet scraping, enabling you to scrape any website
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.