testing
This skill should be used when the user asks about "Effect testing", "@effect/vitest", "it.effect", "it.live", "it.scoped", "it.layer", "it.prop", "Schema Arbitrary", "property-based testing", "fast-check", "TestClock", "testing effects", "mocking services", "test layers", "TestContext", "Effect.provide test", "time testing", "Effect test utilities", "unit testing Effect", "generating test data", "flakyTest", "test coverage", "100% coverage", "service testing", "test doubles", "mock services", or needs to understand how to test Effect-based code.
What this skill does
# Testing in Effect
## Overview
Effect testing uses **`@effect/vitest`** as the standard test runner integration. This package provides Effect-aware test functions that handle Effect execution, scoped resources, layer composition, and TestClock injection automatically.
**The two pillars of Effect testing that enable 100% test coverage:**
1. **Service-Oriented Architecture** — Every external/effectful dependency (API calls, databases, file systems, third-party services, clocks, random number generators) MUST be wrapped in an Effect Service using `Context.Tag`. Tests provide test implementations via Layers, giving you complete control over all I/O and side effects.
2. **Schema-Driven Property Testing** — Since every data type has a Schema, every data type can generate test data via `Arbitrary`. This makes property-based testing the primary approach for verifying domain logic across thousands of automatically generated inputs.
Together, these two pillars mean: **services eliminate external dependencies from tests, and Arbitrary eliminates hand-crafted test data.** The result is fast, deterministic, comprehensive tests with 100% coverage.
**Core testing tools:**
- **@effect/vitest** - Effect-native test runner (`it.effect`, `it.scoped`, `it.live`, `it.layer`, `it.prop`)
- **Effect Services + Test Layers** - Replace ALL external dependencies with test doubles via `Context.Tag` and `it.layer`
- **Schema.Arbitrary** - Generate test data from any Schema (primary approach — never hand-craft test data)
- **Property Testing** - Test invariants with generated data via `it.prop` or fast-check
- **TestClock** - Control time in tests (automatically provided by `it.effect`)
## The Service-Oriented Testing Pattern (CRITICAL)
**This is the most important testing pattern in Effect.** Every external or effectful operation MUST be wrapped in a Service so that tests can provide a test implementation. This is how you achieve 100% test coverage without hitting real APIs, databases, or file systems.
### The Rule
> **If it makes a network call, reads from disk, talks to a database, calls a third-party API, generates random values, or performs any I/O — it MUST be behind an Effect Service.**
### Why Services Are Required for Testing
Without services, your code is **untestable** because it directly depends on external systems:
```typescript
// ❌ UNTESTABLE: Direct API call baked into business logic
const getUser = (id: string) =>
Effect.tryPromise({
try: () => fetch(`/api/users/${id}`).then((r) => r.json()),
catch: (error) => new NetworkError({ cause: error }),
});
// ❌ UNTESTABLE: Direct database access
const saveOrder = (order: Order) =>
Effect.tryPromise({
try: () => db.query("INSERT INTO orders ...", order),
catch: (error) => new DatabaseError({ cause: error }),
});
```
With services, your business logic is **pure and fully testable**:
```typescript
// ✅ TESTABLE: Service abstraction for API calls
class UserApi extends Context.Tag("UserApi")<
UserApi,
{
readonly getUser: (id: string) => Effect.Effect<User, UserNotFound | NetworkError>;
readonly saveUser: (user: User) => Effect.Effect<void, NetworkError>;
}
>() {}
// ✅ TESTABLE: Service abstraction for database
class OrderRepository extends Context.Tag("OrderRepository")<
OrderRepository,
{
readonly save: (order: Order) => Effect.Effect<void, DatabaseError>;
readonly findById: (id: string) => Effect.Effect<Order, OrderNotFound>;
}
>() {}
// ✅ Business logic is pure — depends only on service interfaces
const processOrder = (orderId: string) =>
Effect.gen(function* () {
const userApi = yield* UserApi;
const orderRepo = yield* OrderRepository;
const order = yield* orderRepo.findById(orderId);
const user = yield* userApi.getUser(order.userId);
// ... pure business logic using service abstractions
});
```
### What MUST Be a Service
Every one of these MUST be wrapped in a `Context.Tag` service:
| External Dependency | Service Example |
| ------------------------ | -------------------------------------------------- |
| REST/GraphQL API calls | `UserApi`, `PaymentGateway`, `NotificationService` |
| Database operations | `UserRepository`, `OrderRepository` |
| File system access | `FileStorage`, `ConfigReader` |
| Third-party SDKs | `StripeClient`, `SendGridClient`, `AwsS3Client` |
| Email/SMS sending | `EmailService`, `SmsService` |
| Message queues | `EventPublisher`, `QueueConsumer` |
| Caching systems | `CacheService`, `RedisClient` |
| Authentication providers | `AuthProvider`, `TokenService` |
| External clock/time | Use Effect's built-in `Clock` service |
| Random values | Use Effect's built-in `Random` service |
### Complete Service + Test Layer Pattern
```typescript
import { Context, Effect, Layer, Schema, Arbitrary } from "effect";
import { it, expect, layer } from "@effect/vitest";
import * as fc from "fast-check";
// 1. Define schemas for domain types
const TransactionId = Schema.String.pipe(
Schema.pattern(/^txn_[a-zA-Z0-9]{16}$/),
Schema.annotations({
arbitrary: () => (fc) => fc.stringMatching(/^txn_[a-zA-Z0-9]{16}$/),
}),
);
const PaymentStatus = Schema.Literal("succeeded", "pending", "failed");
class PaymentResult extends Schema.Class<PaymentResult>("PaymentResult")({
transactionId: TransactionId,
amount: Schema.Number.pipe(Schema.positive()),
currency: Schema.Literal("usd", "eur", "gbp"),
status: PaymentStatus,
}) {}
// 2. Define the service interface
class PaymentGateway extends Context.Tag("PaymentGateway")<
PaymentGateway,
{
readonly charge: (amount: number, currency: string) => Effect.Effect<PaymentResult, PaymentError>;
readonly refund: (transactionId: string) => Effect.Effect<void, RefundError>;
}
>() {}
// 3. Live implementation (used in production)
const PaymentGatewayLive = Layer.succeed(PaymentGateway, {
charge: (amount, currency) =>
Effect.tryPromise({
try: () => stripe.charges.create({ amount, currency }),
catch: (error) => new PaymentError({ cause: error }),
}),
refund: (transactionId) =>
Effect.tryPromise({
try: () => stripe.refunds.create({ charge: transactionId }),
catch: (error) => new RefundError({ cause: error }),
}),
});
// 4. Test implementation using Arbitrary — generates varied test data
const PaymentGatewayTest = Layer.effect(
PaymentGateway,
Effect.sync(() => ({
charge: (amount, currency) =>
Effect.succeed(
new PaymentResult({
transactionId: fc.sample(Arbitrary.make(TransactionId)(fc), 1)[0],
amount,
currency: currency as "usd" | "eur" | "gbp",
status: fc.sample(Arbitrary.make(PaymentStatus)(fc), 1)[0],
}),
),
refund: (_transactionId) => Effect.void,
})),
);
// 5. Property test with the test layer — 100% coverage, zero external calls
layer(PaymentGatewayTest)("PaymentService", (it) => {
it.effect.prop("should process payment for any valid amount", [Schema.Number.pipe(Schema.positive())], ([amount]) =>
Effect.gen(function* () {
const gateway = yield* PaymentGateway;
const result = yield* gateway.charge(amount, "usd");
expect(result.amount).toBe(amount);
expect(["succeeded", "pending", "failed"]).toContain(result.status);
}),
);
it.effect.prop("should handle refund for any transaction", [TransactionId], ([txnId]) =>
Effect.gen(function* () {
const gateway = yield* PaymentGateway;
yield* gateway.refund(txnId);
// No error = success
}),
);
});
```
### Stateful Test Layers (for Repository Testing)
For services that need to maintain state across operations within a test, use `Layer.effect` with `Ref`:
```typescript
import Related in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.