← Cloudflare Workers / workers / testing / test-harness
Работа с Workers
Используйте тестовый стенд, чтобы отправлять запросы через настроенные маршруты или напрямую обращаться к конкретному Worker. Также можно отправлять события, например запланированные события.
Тестирование маршрутизации между Workers
Если тестовый набор запускает несколько Workers, добавьте каждый Worker в workers массив. Первый Worker является основным Worker. server.fetch() отправляет относительные URL-адреса на основной Worker, а абсолютные URL-адреса сопоставляет с настроенными маршрутами. Если ни один маршрут не совпадает, запрос возвращается к основному Worker:
const server = createTestHarness({
workers: [
/** Includes `"routes": ["example.com/*"]` */
{ configPath: "./workers/web/wrangler.jsonc" },
/** Includes `"routes": ["api.example.com/v1/*"]` */
{ configPath: "./workers/api/wrangler.jsonc" },
],
});
const primaryResponse = await server.fetch("/");
const apiResponse = await server.fetch("http://api.example.com/v1/users/123");
const webResponse = await server.fetch("http://example.com/users/123");const server = createTestHarness({
workers: [
/** Includes `"routes": ["example.com/*"]` */
{ configPath: "./workers/web/wrangler.jsonc" },
/** Includes `"routes": ["api.example.com/v1/*"]` */
{ configPath: "./workers/api/wrangler.jsonc" },
],
});
const primaryResponse = await server.fetch("/");
const apiResponse = await server.fetch("http://api.example.com/v1/users/123");
const webResponse = await server.fetch("http://example.com/users/123");Работа с определённым Worker
Диспетчеризация маршрутов проверяет границу приложения, но некоторые тесты могут быть нацелены на конкретный Worker или на вызов других обработчиков событий. Используйте server.getWorker(name) чтобы обойти сопоставление маршрутов и получить handle для этого Worker.
Затем этот Worker handle можно использовать для отправки запросов напрямую или для диспетчеризации других событий, например scheduled():
const apiWorker = server.getWorker("api-worker");
const response = await apiWorker.fetch("http://api.example.com/v1/users/123");
await apiWorker.scheduled({
cron: "0 0 * * *",
scheduledTime: new Date(),
});const apiWorker = server.getWorker("api-worker");
const response = await apiWorker.fetch("http://api.example.com/v1/users/123");
await apiWorker.scheduled({
cron: "0 0 * * *",
scheduledTime: new Date(),
});Проверка поведения по логам
Тестовое окружение перехватывает логи из среды выполнения Workers. Чтобы убедиться, что Worker записал определённое сообщение в лог, используйте server.getLogs() чтобы получить записи журнала.
Захваченные логи сбрасываются при вызове server.reset(). Также можно вызвать server.clearLogs() чтобы выделить логи до и после определенного действия:
test("logs scheduled job results", async ({ expect }) => {
const apiWorker = server.getWorker("api-worker");
await apiWorker.scheduled({
cron: "0 0 * * *",
scheduledTime: new Date("2026-05-29T00:00:00.000Z"),
});
expect(server.getLogs()).toEqual([
expect.objectContaining({
level: "info",
message: "Generated daily report for 2026-05-29",
}),
]);
server.clearLogs();
await apiWorker.scheduled({
cron: "0 0 * * *",
scheduledTime: new Date("2026-05-30T00:00:00.000Z"),
});
expect(server.getLogs()).toEqual([
expect.objectContaining({
level: "info",
message: "Generated daily report for 2026-05-30",
}),
]);
});test("logs scheduled job results", async ({ expect }) => {
const apiWorker = server.getWorker("api-worker");
await apiWorker.scheduled({
cron: "0 0 * * *",
scheduledTime: new Date("2026-05-29T00:00:00.000Z"),
});
expect(server.getLogs()).toEqual([
expect.objectContaining({
level: "info",
message: "Generated daily report for 2026-05-29",
}),
]);
server.clearLogs();
await apiWorker.scheduled({
cron: "0 0 * * *",
scheduledTime: new Date("2026-05-30T00:00:00.000Z"),
});
expect(server.getLogs()).toEqual([
expect.objectContaining({
level: "info",
message: "Generated daily report for 2026-05-30",
}),
]);
});Просмотр и управление выполнением Workflow
Если ваш Worker запускает Workflow, вы можете использовать worker.introspectWorkflow(bindingName) чтобы управлять новыми экземплярами и просматривать их состояние.
const worker = server.getWorker("api-worker");
await using workflow = await worker.introspectWorkflow("MY_WORKFLOW");
await workflow.modifyAll(async (modifier) => {
await modifier.disableSleeps([{ name: "wait-for-approval" }]);
});
await worker.fetch("/start-workflow");
const [instance] = await workflow.get();
await instance.waitForStatus("complete");
expect(await instance.getOutput()).toEqual({ approved: true });const worker = server.getWorker<ApiEnv>("api-worker");
await using workflow = await worker.introspectWorkflow("MY_WORKFLOW");
await workflow.modifyAll(async (modifier) => {
await modifier.disableSleeps([{ name: "wait-for-approval" }]);
});
await worker.fetch("/start-workflow");
const [instance] = await workflow.get();
await instance.waitForStatus("complete");
expect(await instance.getOutput()).toEqual({ approved: true });Если тесту уже известен ID экземпляра, вы также можете исследовать этот экземпляр напрямую с помощью worker.introspectWorkflowInstance(bindingName, instanceId).
const instance = await worker.introspectWorkflowInstance(
"MY_WORKFLOW",
"instance-id",
);
await instance.modify(async (modifier) => {
await modifier.mockStepResult({ name: "load-user" }, { id: "123" });
});
await instance.waitForStatus("complete");const instance = await worker.introspectWorkflowInstance(
"MY_WORKFLOW",
"instance-id",
);
await instance.modify(async (modifier) => {
await modifier.mockStepResult({ name: "load-user" }, { id: "123" });
});
await instance.waitForStatus("complete");