first commit
This commit is contained in:
75
docs/api-stack/api/api-worker-rpc/src/testing/conformance.md
Normal file
75
docs/api-stack/api/api-worker-rpc/src/testing/conformance.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# `conformance`
|
||||
|
||||
## Purpose
|
||||
|
||||
Builds a paired client/server harness over an in-process `MessageChannel`
|
||||
for conformance tests. The harness is intended for use by every Stage-3
|
||||
worker-proxy package (`api-db-worker-proxy`, `api-events-worker-proxy`,
|
||||
`api-secrets-worker-proxy`, `api-jobs-worker-proxy`,
|
||||
`api-logger-worker-proxy`, and any successor) so each proxy can verify
|
||||
its capability semantics over a real `MessagePort` round-trip without
|
||||
re-implementing setup boilerplate.
|
||||
|
||||
The harness exposes the live `client`, `server`, and `ports` handles
|
||||
plus a `dispose()` that tears them all down in the correct order
|
||||
(client first, then server, then port). Tests typically wrap it in a
|
||||
`finally`-style block or per-test setup/teardown.
|
||||
|
||||
## Features
|
||||
|
||||
- Single-call paired construction: pass a handlers factory, get a
|
||||
fully wired client/server/ports triple back.
|
||||
- Idempotent `dispose()` — safe to call inside a test cleanup hook
|
||||
even if the test already closed parts of the harness.
|
||||
- Exposes the underlying `RawWorkerRpcClient` so streaming tests can
|
||||
attach a `StreamDispatcher` via the client's `onStreamFrame`
|
||||
option.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { runWorkerRpcConformance } from "@suaveplan/api-worker-rpc/testing";
|
||||
|
||||
const h = runWorkerRpcConformance(() => ({
|
||||
ping: () => "pong",
|
||||
}));
|
||||
await expect(h.client.call("ping", [])).resolves.toBe("pong");
|
||||
h.dispose();
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { StreamDispatcher, streamRequest } from "@suaveplan/api-worker-rpc/streaming";
|
||||
import { runWorkerRpcConformance } from "@suaveplan/api-worker-rpc/testing";
|
||||
|
||||
const h = runWorkerRpcConformance(() => ({
|
||||
rows: async function* () {
|
||||
for (let i = 0; i < 5; i++) yield i;
|
||||
},
|
||||
}));
|
||||
|
||||
const dispatcher = new StreamDispatcher();
|
||||
// Re-wire onStreamFrame on the underlying client — note: in practice you'd
|
||||
// construct the client with this option from the start. The harness ships
|
||||
// without it so test authors can choose whether streaming is exercised.
|
||||
|
||||
h.dispose();
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `interface ConformanceHarness { client, server, ports, dispose }`.
|
||||
- `runWorkerRpcConformance(factory: () => WorkerRpcHandlers): ConformanceHarness`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The default harness does NOT install a `StreamDispatcher` — streaming
|
||||
tests construct their own client with the dispatcher's `dispatch`
|
||||
method wired into `onStreamFrame`, then use the harness's ports
|
||||
directly. This keeps the non-streaming path one-line.
|
||||
- The `client` field is a `RawWorkerRpcClient`, not the typed proxy —
|
||||
conformance tests address methods by string and inspect raw frames
|
||||
rather than relying on TypeScript inference.
|
||||
- `dispose()` tolerates partial-prior-closure so per-test `afterEach`
|
||||
can call it unconditionally.
|
||||
Reference in New Issue
Block a user