Skip to content
result-rpc
Esc
navigateopen⌘Jpreview

Testing and SSR

Parity-mode test clients, the fetch-handler-as-fetch harness, and validated hydration.

import { createTestClient } from "result-rpc/testing"
import { appRouter } from "./router"

const client = createTestClient(appRouter, {
  context: testContext,
  mode: "parity",
})

const result = await client.doc.byId({ id: "missing" })

expect(result).toEqual({
  ok: false,
  error: {
    _tag: "doc/not-found",
    data: { docId: "missing" },
  },
})

Parity mode runs the same codecs and undeclared-error checks as the remote protocol. A separate test transport covers malformed envelopes, 5xx responses, timeouts, offline behavior, and batch failures.

And when a test should cross the real wire — protocol, serializer, HTTP statuses and all — the fetch handler is the fetch, no server process required. The examples run their full React trees this way:

const handler = createFetchHandler({ router, createContext: () => context })

const client = createClient({
  router,
  transport: fetchTransport({
    url: "https://example.test/rpc",
    fetch: (input, init) => handler(new Request(input, init)),
  }),
})

// full round-trip: devalue envelope, HTTP status, rich values intact
const events = await collect(client.doc.events({ id: "doc_1" }))
expect(events[0]).toEqual(ok({ docId: "doc_1", kind: "renamed", at: new Date("2026-01-01") }))

Note the Date inside the assertion — it crossed the wire as a Date.

Was this page helpful?