INTEGRITY Cloudflare Docs

API

Wrangler offers APIs to programmatically interact with your Cloudflare Workers.

createTestHarness

createTestHarness() starts one or more Workers for integration tests from any Node.js test runner. It runs production build output from Wrangler configuration files, Vite-generated configuration files, or inline Wrangler configuration objects. The API wraps Miniflare and provides methods for dispatching requests and scheduled events.

For setup guidance and examples, refer to Integration test harness.

Syntax

import { createTestHarness } from "wrangler";

const server = createTestHarness(options);
import { createTestHarness } from "wrangler";

const server = createTestHarness(options);

Parameters

Each WorkerInput can load a Worker from a Wrangler configuration file:

const server = createTestHarness({
	workers: [
		{ configPath: "./wrangler.web.jsonc" },
		{ configPath: "./wrangler.api.jsonc" },
	],
});
const server = createTestHarness({
	workers: [
		{ configPath: "./wrangler.web.jsonc" },
		{ configPath: "./wrangler.api.jsonc" },
	],
});

Configuration file inputs support these fields:

Each WorkerInput can also use config to provide an inline Wrangler configuration object:

const server = createTestHarness({
	workers: [
		{
			config: {
				name: "api-worker",
				main: "src/api.ts",
				compatibility_date: "YYYY-MM-DD",
			},
		},
	],
});
const server = createTestHarness({
	workers: [
		{
			config: {
				name: "api-worker",
				main: "src/api.ts",
				compatibility_date: "YYYY-MM-DD",
			},
		},
	],
});

Return type

createTestHarness() returns a TestHarness object with these methods:

getWorker(name?) returns a WorkerHandle object with these methods:

Usage

This example uses the Node.js built-in test runner:

import assert from "node:assert/strict";
import { after, afterEach, before, describe, test } from "node:test";
import { createTestHarness } from "wrangler";

const server = createTestHarness({
	workers: [
		{ configPath: "./wrangler.web.jsonc" },
		{ configPath: "./wrangler.api.jsonc" },
	],
});

const apiWorker = server.getWorker("api-worker");

describe("Worker", () => {
	before(async () => {
		await server.listen();
	});

	afterEach(async () => {
		await server.reset();
	});

	after(async () => {
		await server.close();
	});

	test("dispatches through configured routes", async () => {
		const response = await server.fetch("http://example.com/users/123");
		assert.equal(response.status, 200);
	});

	test("calls a specific Worker directly", async () => {
		const response = await apiWorker.fetch(
			"http://api.example.com/v1/users/123",
		);
		assert.equal(response.status, 200);
	});

	test("triggers a scheduled handler", async () => {
		const result = await apiWorker.scheduled({
			cron: "0 0 * * *",
			scheduledTime: new Date(),
		});
		assert.equal(result.outcome, "ok");
	});
});
import assert from "node:assert/strict";
import { after, afterEach, before, describe, test } from "node:test";
import { createTestHarness } from "wrangler";

const server = createTestHarness({
	workers: [
		{ configPath: "./wrangler.web.jsonc" },
		{ configPath: "./wrangler.api.jsonc" },
	],
});

const apiWorker = server.getWorker("api-worker");

describe("Worker", () => {
	before(async () => {
		await server.listen();
	});

	afterEach(async () => {
		await server.reset();
	});

	after(async () => {
		await server.close();
	});

	test("dispatches through configured routes", async () => {
		const response = await server.fetch("http://example.com/users/123");
		assert.equal(response.status, 200);
	});

	test("calls a specific Worker directly", async () => {
		const response = await apiWorker.fetch(
			"http://api.example.com/v1/users/123",
		);
		assert.equal(response.status, 200);
	});

	test("triggers a scheduled handler", async () => {
		const result = await apiWorker.scheduled({
			cron: "0 0 * * *",
			scheduledTime: new Date(),
		});
		assert.equal(result.outcome, "ok");
	});
});

experimental_generateTypes

Generate TypeScript type definitions from your Worker configuration. This API uses the same core logic as the wrangler types CLI command, so outputs stay aligned between the CLI and programmatic API.

Unlike the CLI command, experimental_generateTypes does not write to disk automatically. Instead, it returns the generated type content as structured strings for you to handle as needed.

Syntax

import { experimental_generateTypes } from "wrangler";

const result = await experimental_generateTypes(options);

Parameters

Return Type

experimental_generateTypes() returns a Promise resolving to an object containing the following fields:

Usage

You can use experimental_generateTypes to generate types programmatically and write them to disk yourself, or pass them to other tools:

import { experimental_generateTypes } from "wrangler";
import * as fs from "node:fs";

const result = await experimental_generateTypes({
	config: "wrangler.json",
	includeRuntime: true,
	includeEnv: true,
});

// Write the combined content to the path specified in options
fs.writeFileSync(result.path, result.content, "utf-8");

To generate only env types without runtime types:

const result = await experimental_generateTypes({
	includeRuntime: false,
});

To generate types for a specific environment with a custom interface name:

const result = await experimental_generateTypes({
	env: "staging",
	envInterface: "StagingEnv",
	path: "./types/staging.d.ts",
});

unstable_startWorker

This API exposes the internals of Wrangler's dev server, and allows you to customise how it runs. For example, you could use unstable_startWorker() to run integration tests against your Worker. This example uses node:test, but should apply to any testing framework:

import assert from "node:assert";
import test, { after, before, describe } from "node:test";
import { unstable_startWorker } from "wrangler";

describe("worker", () => {
	let worker;

	before(async () => {
		worker = await unstable_startWorker({ config: "wrangler.json" });
	});

	test("hello world", async () => {
		assert.strictEqual(
			await (await worker.fetch("http://example.com")).text(),
			"Hello world",
		);
	});

	after(async () => {
		await worker.dispose();
	});
});

unstable_dev

Start an HTTP server for testing your Worker.

Once called, unstable_dev will return a fetch() function for invoking your Worker without needing to know the address or port, as well as a stop() function to shut down the HTTP server.

By default, unstable_dev will perform integration tests against a local server. If you wish to perform an e2e test against a preview Worker, pass local: false in the options object when calling the unstable_dev() function. Note that e2e tests can be significantly slower than integration tests.

Constructor

const worker = await unstable_dev(script, options);

Parameters

Return Type

unstable_dev() returns an object containing the following methods:

Usage

When initiating each test suite, use a beforeAll() function to start unstable_dev(). The beforeAll() function is used to minimize overhead: starting the dev server takes a few hundred milliseconds, starting and stopping for each individual test adds up quickly, slowing your tests down.

In each test case, call await worker.fetch(), and check that the response is what you expect.

To wrap up a test suite, call await worker.stop() in an afterAll function.

Single Worker example

const { unstable_dev } = require("wrangler");

describe("Worker", () => {
	let worker;

	beforeAll(async () => {
		worker = await unstable_dev("src/index.js", {
			experimental: { disableExperimentalWarning: true },
		});
	});

	afterAll(async () => {
		await worker.stop();
	});

	it("should return Hello World", async () => {
		const resp = await worker.fetch();
		const text = await resp.text();
		expect(text).toMatchInlineSnapshot(`"Hello World!"`);
	});
});
import { unstable_dev } from "wrangler";
import type { UnstableDevWorker } from "wrangler";

describe("Worker", () => {
	let worker: UnstableDevWorker;

	beforeAll(async () => {
		worker = await unstable_dev("src/index.ts", {
			experimental: { disableExperimentalWarning: true },
		});
	});

	afterAll(async () => {
		await worker.stop();
	});

	it("should return Hello World", async () => {
		const resp = await worker.fetch();
		const text = await resp.text();
		expect(text).toMatchInlineSnapshot(`"Hello World!"`);
	});
});

Multi-Worker example

You can test Workers that call other Workers. In the below example, we refer to the Worker that calls other Workers as the parent Worker, and the Worker being called as a child Worker.

If you shut down the child Worker prematurely, the parent Worker will not know the child Worker exists and your tests will fail.

import { unstable_dev } from "wrangler";

describe("multi-worker testing", () => {
	let childWorker;
	let parentWorker;

	beforeAll(async () => {
		childWorker = await unstable_dev("src/child-worker.js", {
			config: "src/child-wrangler.toml",
			experimental: { disableExperimentalWarning: true },
		});
		parentWorker = await unstable_dev("src/parent-worker.js", {
			config: "src/parent-wrangler.toml",
			experimental: { disableExperimentalWarning: true },
		});
	});

	afterAll(async () => {
		await childWorker.stop();
		await parentWorker.stop();
	});

	it("childWorker should return Hello World itself", async () => {
		const resp = await childWorker.fetch();
		const text = await resp.text();
		expect(text).toMatchInlineSnapshot(`"Hello World!"`);
	});

	it("parentWorker should return Hello World by invoking the child worker", async () => {
		const resp = await parentWorker.fetch();
		const parsedResp = await resp.text();
		expect(parsedResp).toEqual("Parent worker sees: Hello World!");
	});
});
import { unstable_dev } from "wrangler";
import type { UnstableDevWorker } from "wrangler";

describe("multi-worker testing", () => {
	let childWorker: UnstableDevWorker;
	let parentWorker: UnstableDevWorker;

	beforeAll(async () => {
		childWorker = await unstable_dev("src/child-worker.js", {
			config: "src/child-wrangler.toml",
			experimental: { disableExperimentalWarning: true },
		});
		parentWorker = await unstable_dev("src/parent-worker.js", {
			config: "src/parent-wrangler.toml",
			experimental: { disableExperimentalWarning: true },
		});
	});

	afterAll(async () => {
		await childWorker.stop();
		await parentWorker.stop();
	});

	it("childWorker should return Hello World itself", async () => {
		const resp = await childWorker.fetch();
		const text = await resp.text();
		expect(text).toMatchInlineSnapshot(`"Hello World!"`);
	});

	it("parentWorker should return Hello World by invoking the child worker", async () => {
		const resp = await parentWorker.fetch();
		const parsedResp = await resp.text();
		expect(parsedResp).toEqual("Parent worker sees: Hello World!");
	});
});

getPlatformProxy

The getPlatformProxy function provides a way to obtain an object containing proxies (to local workerd bindings) and emulations of Cloudflare Workers specific values, allowing the emulation of such in a Node.js process.

One general use case for getting a platform proxy is for emulating bindings in applications targeting Workers, but running outside the Workers runtime (for example, framework local development servers running in Node.js), or for testing purposes (for example, ensuring code properly interacts with a type of binding).

Syntax

const platform = await getPlatformProxy(options);

Parameters

Return Type

getPlatformProxy() returns a Promise resolving to an object containing the following fields.

Usage

The getPlatformProxy function uses bindings found in the Wrangler configuration file. For example, if you have an environment variable configuration set up in the Wrangler configuration file:

{
	"vars": {
		"MY_VARIABLE": "test"
	}
}
[vars]
MY_VARIABLE = "test"

You can access the bindings by importing getPlatformProxy like this:

import { getPlatformProxy } from "wrangler";

const { env } = await getPlatformProxy();

To access the value of the MY_VARIABLE binding add the following to your code:

console.log(`MY_VARIABLE = ${env.MY_VARIABLE}`);

This will print the following output: MY_VARIABLE = test.

Supported bindings

All supported bindings found in your Wrangler configuration file are available to you via env.

The bindings supported by getPlatformProxy are: