effect-testing-mocking
Testing patterns with layers, mocks, and deterministic time. Use when preparing testable services and small smoke tests.
When & Why to Use This Skill
This Claude skill enables developers to implement robust testing patterns using layers, service mocking, and deterministic time control. It streamlines the creation of testable services and fast-executing smoke tests, ensuring high code quality and reliability by isolating side effects and eliminating flakiness in complex software architectures.
Use Cases
- Simulating time-dependent logic: Using TestClock to verify scheduled tasks or timeouts without waiting for real-world time to pass.
- Dependency Isolation: Injecting mock service layers to test business logic without making actual database calls or external API requests.
- Rapid Smoke Testing: Developing lightweight, fast-failing tests to validate core service wiring and basic functionality during CI/CD cycles.
- Deterministic Environment Setup: Creating consistent test environments by mocking system-level dependencies like file systems, OS operations, and environment variables.
| name | effect-testing-mocking |
|---|---|
| description | Testing patterns with layers, mocks, and deterministic time. Use when preparing testable services and small smoke tests. |
| allowed-tools | Read, Grep, Glob, Edit, Write |
Testing & Mocking
When to use
- You need deterministic tests without external IO
- You want to inject mock services via layers
Mock Layer
const RepoTest = Layer.succeed(Repo, Repo.of({ find: () => Effect.succeed(mock) }))
Provide Test Impl
const result = yield* Effect.provide(program, RepoTest)
Test Clock
// Provide a deterministic Clock or use platform TestClock layer if available
Guidance
- Keep tests focused and fast; avoid network by mocking services
- Provide layers explicitly to match program requirements
- Keep tests close to real interfaces; do not reshape app code for tests
- Use
.Defaultlayers for quick wiring; add custom mock layers per test - Favor small smoke tests that run quickly and fail fast
Pitfalls
- Leaking real IO into tests → flakiness
- Over-mocking internals → brittle tests; mock at service boundary
Cross-links
- Layers & Services for DI patterns
- Time/Logging for deterministic time and observable output
Local Source Reference
CRITICAL: Search local Effect source before implementing
The full Effect source code is available at docs/effect-source/. Always search the actual implementation before writing Effect code.
Key Source Files
- Layer:
docs/effect-source/effect/src/Layer.ts - TestClock:
docs/effect-source/effect/src/TestClock.ts - TestContext:
docs/effect-source/effect/src/TestContext.ts
Example Searches
# Find Layer.succeed patterns for mocks
grep -F "Layer.succeed" docs/effect-source/effect/src/Layer.ts
# Study TestClock operations
grep -F "TestClock" docs/effect-source/effect/src/TestClock.ts
# Find test helpers
grep -F "TestContext" docs/effect-source/effect/src/TestContext.ts
# Look at Layer test examples
grep -F "Layer.succeed" docs/effect-source/effect/test/Layer.test.ts
Workflow
- Identify the testing API you need (e.g., Layer.succeed, TestClock)
- Search
docs/effect-source/effect/src/Layer.tsfor the implementation - Study the types and testing patterns
- Look at test files for usage examples
- Write your code based on real implementations
Real source code > documentation > assumptions
Real-world snippet: Build a comprehensive Test layer
export const TestLayer = (input?: TestLiveInput) =>
Effect.gen(function* () {
const tempDir = tempy.temporaryDirectory({ prefix: 'test' })
const cwd = (yield* setupFixtureFolder({ fixture: input?.fixture, tempDir })) ?? tempDir
const NodeOsTest = Layer.succeed(NodeOs, new NodeOs({ homedir: cwd, arch: 'arm64', platform: 'darwin' }))
const NodeProcessTest = Layer.succeed(NodeProcess, new NodeProcess({ cwd, platform: 'darwin', arch: 'arm64' }))
const ToolkitsRepoTest = Layer.succeed(ComposioToolkitsRepository, new ComposioToolkitsRepository({
getToolkits: () => Effect.succeed([]),
getToolsAsEnums: () => Effect.succeed([])
}))
const layers = Layer.mergeAll(
Console.setConsole(yield* MockConsole.effect),
CliConfig.layer(ComposioCliConfig),
NodeProcessTest,
Layer.provideMerge(ComposioUserContextLive, Layer.merge(BunFileSystem.layer, NodeOsTest)),
ToolkitsRepoTest,
EnvLangDetector.Default,
JsPackageManagerDetector.Default,
BunFileSystem.layer,
BunContext.layer,
MockTerminal.layer,
BunPath.layer
)
return layers
}).pipe(
Logger.withMinimumLogLevel(LogLevel.Debug),
Effect.scoped,
Layer.unwrapEffect,
Layer.provide(Layer.setConfigProvider(input?.baseConfigProvider ?? ConfigProvider.fromMap(new Map([]))))
)
References
- Agent Skills overview: https://www.anthropic.com/news/skills
- Skills guide: https://docs.claude.com/en/docs/claude-code/skills