Skip to content

Commit 7f3e514

Browse files
authored
test(server): use Layer.mock for partial Account service stub (#26472)
1 parent cbdb2d9 commit 7f3e514

2 files changed

Lines changed: 21 additions & 17 deletions

File tree

packages/opencode/test/AGENTS.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,19 @@ Use `provideTmpdirInstance(...)` or `tmpdirScoped()` plus `provideInstance(...)`
142142
- Yield services directly with `yield* MyService.Service` or `yield* MyTool`.
143143
- Avoid custom `ManagedRuntime`, `attach(...)`, or ad hoc `run(...)` wrappers when `testEffect(...)` already provides the runtime.
144144
- When a test needs instance-local state, prefer `it.instance(...)` over manual `Instance.provide(...)` inside Promise-style tests.
145+
146+
### Partial Service Stubs
147+
148+
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.
149+
150+
```typescript
151+
import { Effect, Layer } from "effect"
152+
import { Account } from "@/account/account"
153+
154+
const failingAccountLayer = Layer.mock(Account.Service, {
155+
orgsByAccount: () =>
156+
Effect.fail(new Account.AccountServiceError({ message: "simulated upstream failure" })),
157+
})
158+
```
159+
160+
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.

packages/opencode/test/server/httpapi-account-error-mapping.test.ts

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { afterEach, describe, expect, mock, test } from "bun:test"
2-
import { Effect, Layer, Option } from "effect"
2+
import { Effect, Layer } from "effect"
33

44
// Account.orgsByAccount() can fail with AccountServiceError when the
55
// upstream Anthropic Console API is unreachable. The HTTP API used to
@@ -17,22 +17,10 @@ import { Effect, Layer, Option } from "effect"
1717

1818
const ORIG = await import("../../src/account/account")
1919

20-
const failingAccountLayer = Layer.succeed(
21-
ORIG.Service,
22-
ORIG.Service.of({
23-
active: () => Effect.succeed(Option.none()),
24-
activeOrg: () => Effect.succeed(Option.none()),
25-
list: () => Effect.succeed([]),
26-
orgsByAccount: () => Effect.fail(new ORIG.AccountServiceError({ message: "simulated upstream failure" })),
27-
remove: () => Effect.void,
28-
use: () => Effect.void,
29-
orgs: () => Effect.succeed([]),
30-
config: () => Effect.succeed(Option.none()),
31-
token: () => Effect.succeed(Option.none()),
32-
login: () => Effect.fail(new ORIG.AccountServiceError({ message: "unused" })),
33-
poll: () => Effect.fail(new ORIG.AccountServiceError({ message: "unused" })),
34-
}),
35-
)
20+
const failingAccountLayer = Layer.mock(ORIG.Service, {
21+
orgsByAccount: () =>
22+
Effect.fail(new ORIG.AccountServiceError({ message: "simulated upstream failure" })),
23+
})
3624

3725
const mocked = {
3826
...ORIG,

0 commit comments

Comments
 (0)