test(server): use Layer.mock for partial Account service stub (#26472)
This commit is contained in:
@@ -142,3 +142,19 @@ Use `provideTmpdirInstance(...)` or `tmpdirScoped()` plus `provideInstance(...)`
|
|||||||
- Yield services directly with `yield* MyService.Service` or `yield* MyTool`.
|
- Yield services directly with `yield* MyService.Service` or `yield* MyTool`.
|
||||||
- Avoid custom `ManagedRuntime`, `attach(...)`, or ad hoc `run(...)` wrappers when `testEffect(...)` already provides the runtime.
|
- Avoid custom `ManagedRuntime`, `attach(...)`, or ad hoc `run(...)` wrappers when `testEffect(...)` already provides the runtime.
|
||||||
- When a test needs instance-local state, prefer `it.instance(...)` over manual `Instance.provide(...)` inside Promise-style tests.
|
- When a test needs instance-local state, prefer `it.instance(...)` over manual `Instance.provide(...)` inside Promise-style tests.
|
||||||
|
|
||||||
|
### Partial Service Stubs
|
||||||
|
|
||||||
|
When a test only needs to override one or two methods of a service, prefer `Layer.mock` over a hand-rolled `Layer.succeed(Service, Service.of({ ... }))`. `Layer.mock` lets you supply just the methods that matter — anything else throws an `UnimplementedError` defect if the test accidentally calls it, which is exactly the signal you want.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Effect, Layer } from "effect"
|
||||||
|
import { Account } from "@/account/account"
|
||||||
|
|
||||||
|
const failingAccountLayer = Layer.mock(Account.Service, {
|
||||||
|
orgsByAccount: () =>
|
||||||
|
Effect.fail(new Account.AccountServiceError({ message: "simulated upstream failure" })),
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
This is much shorter than stubbing every method with `Effect.void` / `Effect.succeed(...)` placeholders, and it keeps the test focused on the behaviour under test.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { afterEach, describe, expect, mock, test } from "bun:test"
|
import { afterEach, describe, expect, mock, test } from "bun:test"
|
||||||
import { Effect, Layer, Option } from "effect"
|
import { Effect, Layer } from "effect"
|
||||||
|
|
||||||
// Account.orgsByAccount() can fail with AccountServiceError when the
|
// Account.orgsByAccount() can fail with AccountServiceError when the
|
||||||
// upstream Anthropic Console API is unreachable. The HTTP API used to
|
// upstream Anthropic Console API is unreachable. The HTTP API used to
|
||||||
@@ -17,22 +17,10 @@ import { Effect, Layer, Option } from "effect"
|
|||||||
|
|
||||||
const ORIG = await import("../../src/account/account")
|
const ORIG = await import("../../src/account/account")
|
||||||
|
|
||||||
const failingAccountLayer = Layer.succeed(
|
const failingAccountLayer = Layer.mock(ORIG.Service, {
|
||||||
ORIG.Service,
|
orgsByAccount: () =>
|
||||||
ORIG.Service.of({
|
Effect.fail(new ORIG.AccountServiceError({ message: "simulated upstream failure" })),
|
||||||
active: () => Effect.succeed(Option.none()),
|
})
|
||||||
activeOrg: () => Effect.succeed(Option.none()),
|
|
||||||
list: () => Effect.succeed([]),
|
|
||||||
orgsByAccount: () => Effect.fail(new ORIG.AccountServiceError({ message: "simulated upstream failure" })),
|
|
||||||
remove: () => Effect.void,
|
|
||||||
use: () => Effect.void,
|
|
||||||
orgs: () => Effect.succeed([]),
|
|
||||||
config: () => Effect.succeed(Option.none()),
|
|
||||||
token: () => Effect.succeed(Option.none()),
|
|
||||||
login: () => Effect.fail(new ORIG.AccountServiceError({ message: "unused" })),
|
|
||||||
poll: () => Effect.fail(new ORIG.AccountServiceError({ message: "unused" })),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
const mocked = {
|
const mocked = {
|
||||||
...ORIG,
|
...ORIG,
|
||||||
|
|||||||
Reference in New Issue
Block a user