Integrations (4)
Last updated Jul 27, 2026
You can use createTestHarness() with existing tools in the Node.js ecosystem. The examples on this page show common integration patterns that you can adapt to your test setup.
Mock Service Worker
If your Worker makes outbound fetch() requests, you can use Mock Service Worker (MSW) ↗︎ to intercept them and return predictable responses. MSW provides reusable request handlers that can be shared across tests.
For example, you can start MSW before the tests, reject unhandled requests, and reset handlers after each test:
import { afterAll, afterEach, beforeAll, test } from "vitest";
import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";
import { createTestHarness } from "wrangler";
const network = setupServer();
const server = createTestHarness({
workers: [{ configPath: "./wrangler.jsonc" }],
});
beforeAll(async () => {
network.listen({ onUnhandledRequest: "error" });
await server.listen();
});
afterEach(async () => {
network.resetHandlers();
await server.reset();
});
afterAll(async () => {
network.close();
await server.close();
});
test("loads a user profile", async ({ expect }) => {
network.use(
http.get("http://identity.example.com/profile/:id", ({ params }) => {
return HttpResponse.json({ id: params.id, name: "Ada" });
}),
);
const worker = server.getWorker();
const response = await worker.fetch("/users/123");
expect(await response.json()).toEqual({ id: "123", name: "Ada" });
});
import { afterAll, afterEach, beforeAll, test } from "vitest";
import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";
import { createTestHarness } from "wrangler";
const network = setupServer();
const server = createTestHarness({
workers: [{ configPath: "./wrangler.jsonc" }],
});
beforeAll(async () => {
network.listen({ onUnhandledRequest: "error" });
await server.listen();
});
afterEach(async () => {
network.resetHandlers();
await server.reset();
});
afterAll(async () => {
network.close();
await server.close();
});
test("loads a user profile", async ({ expect }) => {
network.use(
http.get("http://identity.example.com/profile/:id", ({ params }) => {
return HttpResponse.json({ id: params.id, name: "Ada" });
}),
);
const worker = server.getWorker();
const response = await worker.fetch("/users/123");
expect(await response.json()).toEqual({ id: "123", name: "Ada" });
});
Playwright
If you are building a web application and want to verify user flows in a real browser, use Playwright ↗︎ with the test harness. Playwright can navigate pages, interact with the user interface, and verify the behavior of your Workers project end to end.
A Playwright fixture can start a test server with createTestHarness() before browser tests. If you want to mock outbound fetch() requests, you can also use MSW to intercept them at the same time.
The following fixture sets the Playwright baseURL, exposes MSW and the test harness to tests, and resets storage state after each test.
tests/playwright.test.jsjs
import { test as base, expect } from "@playwright/test";
import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";
import { createTestHarness } from "wrangler";
const test = base.extend({
network: [
async ({}, use) => {
const network = setupServer();
network.listen({ onUnhandledRequest: "error" });
await use(network);
network.close();
},
{ scope: "worker" },
],
server: [
async ({}, use) => {
const server = createTestHarness({
workers: [
{ configPath: "./dist/web_worker/wrangler.json" },
{ configPath: "./dist/api_worker/wrangler.json" },
],
});
await server.listen();
await use(server);
await server.close();
},
{ scope: "worker" },
],
baseURL: async ({ server }, use) => {
const { url } = await server.listen();
await use(url.href);
},
reset: [
async ({ network, server }, use, testInfo) => {
await use();
if (testInfo.status !== testInfo.expectedStatus) {
server.debug();
}
network.resetHandlers();
await server.reset();
},
{ auto: true },
],
});
test("renders a user profile", async ({ page, network }) => {
network.use(
http.get("http://identity.example.com/profile/:id", ({ params }) => {
return HttpResponse.json({ id: params.id, name: "Ada" });
}),
);
await page.goto("/users/123");
await expect(page.getByText("Profile: Ada")).toBeVisible();
});
tests/playwright.test.tsts
import { test as base, expect } from "@playwright/test";
import { http, HttpResponse } from "msw";
import { setupServer, type SetupServerApi } from "msw/node";
import { createTestHarness, type TestHarness } from "wrangler";
type TestFixtures = {
reset: void;
};
type WorkerFixtures = {
network: SetupServerApi;
server: TestHarness;
};
const test = base.extend<TestFixtures, WorkerFixtures>({
network: [
async ({}, use) => {
const network = setupServer();
network.listen({ onUnhandledRequest: "error" });
await use(network);
network.close();
},
{ scope: "worker" },
],
server: [
async ({}, use) => {
const server = createTestHarness({
workers: [
{ configPath: "./dist/web_worker/wrangler.json" },
{ configPath: "./dist/api_worker/wrangler.json" },
],
});
await server.listen();
await use(server);
await server.close();
},
{ scope: "worker" },
],
baseURL: async ({ server }, use) => {
const { url } = await server.listen();
await use(url.href);
},
reset: [
async ({ network, server }, use, testInfo) => {
await use();
if (testInfo.status !== testInfo.expectedStatus) {
server.debug();
}
network.resetHandlers();
await server.reset();
},
{ auto: true },
],
});
test("renders a user profile", async ({ page, network }) => {
network.use(
http.get("http://identity.example.com/profile/:id", ({ params }) => {
return HttpResponse.json({ id: params.id, name: "Ada" });
}),
);
await page.goto("/users/123");
await expect(page.getByText("Profile: Ada")).toBeVisible();
});
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/workers/testing/test-harness/integrations/#page","headline":"Integrations","description":"Use createTestHarness with Mock Service Worker and Playwright.","url":"https://developers.cloudflare.com/workers/testing/test-harness/integrations/","inLanguage":"en","image":"https://developers.cloudflare.com/workers/testing/test-harness/integrations/og.png?v=d180095af1637ae1","dateModified":"2026-07-27","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
description: Test routes, dispatch events, control Workflows, and assert logged behavior with createTestHarness. title: Interact with Workers image: https://developers.cloudflare.com/workers/testing/test-harness/interact-with-workers/og.png?v=844c9e592ff561a9
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/workers/llms.txt
Use this file to discover all available pages before exploring further.
Docs