Files
skills/docs/api-stack/api/api-worker-host/src/testing/testing.md
2026-05-29 08:20:56 +01:00

2.9 KiB

Worker host conformance harness

(no submodules)

Purpose

runWorkerHostConformance spins up an in-process worker-shaped peer using paired MessageChannel ports. It exists so this package's own test suite — and the lifecycle-driver tests inside api-host — can exercise the full bootstrap → lifecycle → capability-proxy chain without spawning a real node:worker_threads Worker. Two paired ports are wired up (one for control, one for capability), the bootstrap is run on the worker-side ports, a stub capability server is mounted on the main-side of the capability port, and a main-side RPC client is wired to the control port — giving callers everything they need to drive lifecycle commands and observe capability call dispatch deterministically.

Features

  • Optional overrides for manifest, capabilityHandles, plugin hooks and the main-side capabilityHandlers.
  • Reasonable defaults ({ name: "test-plugin", version: "0.1.0", tier: "isolated", capabilities: [] }) so trivial tests need zero setup.
  • Returns the live WorkerHost, the main-side WorkerRpcClient, the stub capability server, both port pairs and a single dispose() that tears everything down in reverse order.
  • No real Worker thread spawned — pure structured-clone routing via MessageChannel.

Usage: Basic

import {
    runWorkerHostConformance,
} from "@suaveplan/api-worker-host/testing";

const h = runWorkerHostConformance({
    hooks: { install: () => {} },
});
const ack = await h.mainClient.call("lifecycle.dispatch", [
    { command: "install" },
]);
h.dispose();

Usage: Advanced

Provide capability handles + main-side handlers to round-trip a capability call:

import {
    runWorkerHostConformance,
} from "@suaveplan/api-worker-host/testing";

const h = runWorkerHostConformance({
    capabilityHandles: { db: { methods: ["query"] } },
    capabilityHandlers: {
        "db.query": (params) => ({ rows: [params[0]] }),
    },
});
const query = h.host.capabilities.db?.query;
const result = await query?.("SELECT 1");
h.dispose();

API Reference

  • runWorkerHostConformance(opts?): WorkerHostConformanceHarness
  • WorkerHostConformanceOptions:
    • manifest?: ManifestEnvelope
    • capabilityHandles?: CapabilityHandles
    • hooks?: PluginLifecycleHooks
    • capabilityHandlers?: WorkerRpcHandlers
  • WorkerHostConformanceHarness:
    • host: WorkerHost
    • mainClient: WorkerRpcClient
    • capabilityServer: WorkerRpcServer
    • controlPorts / capabilityPorts: InProcessPortPair
    • dispose(): void

Implementation Notes

dispose() closes the main-side client first so it stops sending, then the worker host (which closes its own server + capability client), then the main-side capability server, then both port pairs. Closing in reverse-construction order avoids port already closed log noise in vitest while still flushing the inflight RPC budget.