Workerd Testing Strategies and the .wd-test Format: A Complete Technical Guide

Workerd employs a three-tier testing strategy that pairs JavaScript test files with Cap'n Proto .wd-test configuration files to define runtime environments, while C++ unit tests handle low-level components, all orchestrated through Bazel with multiple compatibility variants.

The Cloudflare workerd runtime uses a sophisticated, multi-layered testing architecture to validate JavaScript APIs, runtime behavior, and internal C++ components. Understanding these workerd testing strategies and the .wd-test format is essential for contributing to the codebase or extending the runtime with new features.

Workerd Testing Architecture Overview

Workerd organizes its test suite around three orthogonal concepts that cover different layers of the stack:

  • JavaScript/TypeScript test files — Pure JavaScript test logic using node:assert without external test frameworks. These live in src/workerd/api/tests/*.js (or *.ts for Node.js compatibility tests) and export test objects or fetch handlers.
  • Cap'n Proto .wd-test files — Runtime configuration files that define Workerd.Config schemas to start a worker for the paired test file. These reside in the same directory with matching basenames (e.g., feature-test.js pairs with feature-test.wd-test).
  • C++ unit tests — Low-level component tests using the kj_test framework, located in src/workerd/*/tests/*.c++.

Each .js test is automatically paired with a .wd-test file that describes a complete Workerd.Config. The test harness loads this configuration, starts a temporary workerd instance, and executes the exported test functions.

Understanding the .wd-test File Format

A .wd-test file is a Cap'n Proto source that imports the global schema and creates a Workerd.Config constant. The schema definition resides in src/workerd/server/workerd.capnp.

Cap'n Proto Schema and Structure

The minimal structure imports the workerd schema and defines a constant configuration:

using Workerd = import "/workerd/workerd.capnp";

const unitTests :Workerd.Config = (
  services = [
    ( name = "worker-test",
      worker = (
        modules = [
          (name = "worker", esModule = embed "worker-test.js"),
          (name = "inline-module", esModule = "export default 42")
        ],
        compatibilityFlags = [
          "nodejs_compat",
          "allow_eval_during_startup"
        ]
      )
    )
  ]
);

The embed keyword inlines the source file content, while literal strings allow inline JavaScript definitions.

Key Configuration Sections

The .wd-test format supports several critical configuration sections that map 1-to-1 to the Cap'n Proto schema:

  • services — Defines named services. Most tests declare a single worker service with a descriptive name.
  • worker.modules — Specifies the modules available inside the worker. Use embed "<file>" to reference external files or provide strings for inline code.
  • worker.compatibilityFlags — Enables specific runtime behaviors via flags defined in src/workerd/io/compatibility-date.capnp (e.g., "nodejs_compat", "allow_fetch").
  • worker.autogates — Optional list of experimental features controlled by autogates defined in src/workerd/util/autogate.h and src/workerd/util/autogate.c++.
  • worker.bindings — Connects the worker to mock services such as KV namespaces, Durable Objects, or Queues.

The test harness compiles the file on-the-fly using wd_cc_embed, feeds the resulting binary config to the workerd binary, and then invokes the test code.

Writing and Running .wd-test Configurations

Creating a new test requires pairing a JavaScript test file with its configuration and verifying it against multiple compatibility variants.

Creating a New Test File Pair

Follow this sequence to add a validated test to the suite:

  1. Create the JavaScript test file at src/workerd/api/tests/<feature>-test.js:
import assert from "node:assert";

export const test = {
  async test(ctrl) {
    const res = await fetch("https://example.com/");
    assert.strictEqual(res.status, 200);
  },
};
  1. Create the matching .wd-test file with the same basename:
using Workerd = import "/workerd/workerd.capnp";

const unitTests :Workerd.Config = (
  services = [
    ( name = "my-feature-test",
      worker = (
        modules = [ (name = "worker", esModule = embed "<feature>-test.js") ],
        compatibilityFlags = [ "nodejs_compat" ],
        bindings = [
          (name = "KV", kvNamespace = "my-kv"),
        ]
      )
    ),
  ]
);

  1. Add mock bindings if required. Mock services reside in src/workerd/api/tests/*-mock.js and are referenced by name in the bindings list.

Test Variants and Compatibility Modes

Every test target can be exercised with three Bazel variants to ensure backward and forward compatibility:

  • name@ — Default variant using the oldest compatibility date (2000-01-01).
  • name@all-compat-flags — Newest compatibility date (2999-12-31) with all compatibility flags enabled.
  • name@all-autogates — Same as above plus all autogates enabled for experimental feature testing.

Run a specific variant using the just command:

just test //src/workerd/api/tests:worker-test@all-compat-flags

Debugging with VS Code

The repository includes a dedicated launch configuration for debugging .wd-test files. The "workerd wd-test case (dbg)" configuration, documented in [docs/vscode.md](https://github.com/cloudflare/workerd/blob/main/docs/vscode.md), prompts for a .wd-test file (defaulting to src/workerd/api/node/path-test.wd-test) and launches workerd with --inspect.

Set breakpoints directly in the embedded JavaScript modules or the test file itself. This integration allows stepping through code execution as the test harness runs the configuration against the runtime.

Summary

  • Workerd testing strategies rely on three layers: JavaScript test files for API logic, .wd-test Cap'n Proto files for runtime configuration, and C++ kj_test unit tests for internal components.
  • The .wd-test format uses Cap'n Proto syntax to define Workerd.Config with modules, compatibility flags, autogates, and service bindings.
  • Test files must share the same basename (e.g., feature-test.js and feature-test.wd-test) to be automatically paired by the harness.
  • Run tests with just test and specify compatibility variants (@, @all-compat-flags, @all-autogates) to validate behavior across runtime versions.
  • Reference schemas are located in src/workerd/server/workerd.capnp, src/workerd/io/compatibility-date.capnp, and src/workerd/util/autogate.h.

Frequently Asked Questions

What is the relationship between .wd-test files and JavaScript test files?

Each JavaScript test file in src/workerd/api/tests/ must have a corresponding .wd-test file with an identical basename. The .wd-test file defines the Workerd.Config that the test harness uses to start a workerd instance, specifying which JavaScript modules to load, which compatibility flags to enable, and which mock services to bind. The harness then executes the exported test functions or fetch handlers from the JavaScript file within that configured environment.

How do I enable experimental features in a .wd-test configuration?

Experimental features are controlled through autogates in the worker.autogates section of your .wd-test file. Add the specific autogate identifier (e.g., "experimental_fetch") to the list to enable cutting-edge functionality. The available autogates are defined in the C++ headers src/workerd/util/autogate.h and src/workerd/util/autogate.c++. You can also run the @all-autogates test variant to enable every experimental gate simultaneously.

Where are the mock services like KV and Durable Objects defined for testing?

Mock services are defined in separate JavaScript files following the *-mock.js naming convention in src/workerd/api/tests/. These mocks simulate Cloudflare platform APIs like KV, D1, Durable Objects, and Queues. You reference them in your .wd-test file's worker.bindings section (e.g., (name = "KV", kvNamespace = "kv-test")), and the test harness wires them to your worker during initialization.

How do I run a specific compatibility variant of a workerd test?

Append the variant suffix to the Bazel target name when invoking just test. The three supported variants are @ (oldest compatibility date), @all-compat-flags (newest date with all flags), and @all-autogates (newest date with all flags and autogates). For example, to test with all compatibility flags enabled, run: just test //src/workerd/api/tests:worker-test@all-compat-flags. This ensures your code behaves correctly across the full compatibility matrix.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →