Skip to main content

Function: createTestingClient()

createTestingClient<T>(doBindingName, doInstanceNameOrId, config?): T extends (...args) => I ? RpcAccessible<I> : T & RpcClientProxy

Defined in: packages/testing/src/create-testing-client.ts:52

Creates a testing-optimized RPC client for Cloudflare Durable Objects.

Environment Requirement: This function can only be used within Cloudflare Workers test environment (vitest with @cloudflare/vitest-pool-workers). It imports from cloudflare:test which is only available in that environment.

This is a convenience wrapper around createRpcClient that automatically:

  • Imports SELF from cloudflare:test
  • Uses HTTP transport by default (fast, simple, no connection overhead)
  • Automatically switches to WebSocket when downstream messaging is configured
  • Provides RPC access to DO instance internals

Type Parameters

T

T

The DO class constructor (e.g., typeof MyDO) or pre-wrapped with RpcAccessible.

Parameters

doBindingName

string

The DO binding name from wrangler.jsonc (e.g., 'MY_DO')

doInstanceNameOrId

string

The DO instance name or ID

config?

Optional configuration for downstream messaging and connection handling

clientId?

string

Optional client ID for downstream messaging If not provided but onDownstream is set, a random ID will be generated

onClose?

(code, reason) => void | Promise<void>

Handler for WebSocket connection close events

Remarks

Automatically switches transport to 'websocket'.

onDownstream?

(payload) => void | Promise<void>

Handler for downstream messages from the DO

Testing Guidance: For most tests, prefer calling methods and using vi.waitFor() to check state directly. Only use onDownstream when specifically testing downstream messaging features or complex cross-DO communication patterns where the callback path itself needs validation.

Remarks

If provided without clientId, a random clientId will be auto-generated and the WebSocket connection will be tagged with it for routing downstream messages. Automatically switches transport to 'websocket'.

Example

// ❌ Don't do this for simple tests
const messages: any[] = [];
await using client = createTestingClient('MY_DO', 'test', {
onDownstream: (msg) => messages.push(msg)
});
await vi.waitFor(() => expect(messages.length).toBe(1));

// ✅ Do this instead - clearer and more direct
await using client = createTestingClient('MY_DO', 'test');
await vi.waitFor(async () => {
const state = await client.getState();
expect(state.count).toBe(1);
});

// ✅ Use onDownstream for cross-DO communication validation
await using client = createTestingClient('USER_DO', 'user-1', {
onDownstream: (notification) => {
expect(notification.type).toBe('message_received');
}
});

transport?

"websocket" | "http"

Transport type to use. Defaults to 'http'.

  • 'http': Fast, simple, no connection overhead (default)
  • 'websocket': Persistent connection, required for downstream messaging

Remarks

Automatically switches to 'websocket' when onDownstream or onClose is provided.

Returns

T extends (...args) => I ? RpcAccessible<I> : T & RpcClientProxy

A proxy client that supports both RPC calls and lifecycle management

Remarks

Internally calls createRpcClient with testing-specific defaults. For production use or when you need full configuration control (custom transports, WebSocket connections, custom headers, etc.), use createRpcClient directly.

Both functions return the same underlying RpcClient instance and support 'using' for automatic cleanup. The only difference is the level of configuration abstraction.

For test timeouts, use your test framework's timeout features (e.g., Vitest's test.timeout).

Example

using client = createTestingClient<typeof MyDO>('MY_DO', 'instance-name');
await client.ctx.storage.put('key', 'value');

// For TypeScript, it also supports interfaces or pre-wrapping using `RpcAccessible`
type MyDOType = RpcAccessible<InstanceType<typeof MyDO>>;
using client = createTestingClient<MyDOType>('MY_DO', 'instance-name');

// With downstream messaging
using client = createTestingClient<typeof MyDO>('MY_DO', 'instance-name', {
onDownstream: (payload) => console.log('Received:', payload),
onClose: (code, reason) => console.log('Connection closed')
});

Throws

Will fail to import if used outside vitest-pool-workers environment