← Cloudflare Workers / workers / wrangler
API
Wrangler предоставляет API для программного взаимодействия с вашими Cloudflare Workers.
createTestHarness- Запустите один или несколько Workers для интеграционных тестов в любом Node.js test runner.experimental_generateTypes- Генерируйте определения типов TypeScript на основе конфигурации Worker.unstable_startWorker- Запустите сервер для выполнения интеграционных тестов вашего Worker.unstable_dev- Запустите сервер для выполнения сквозных (e2e) или интеграционных тестов вашего Worker.getPlatformProxy- Получайте прокси и значения для эмуляции платформы Cloudflare Workers в процессе Node.js.
createTestHarness
createTestHarness() запускает один или несколько Workers для интеграционных тестов из любого средства запуска тестов Node.js. Он выполняет production-сборку на основе файлов конфигурации Wrangler, файлов конфигурации, созданных Vite, или встроенных объектов конфигурации Wrangler. API оборачивает Miniflare и предоставляет методы для отправки запросов и событий по расписанию.
Инструкции и примеры по настройке см. в Инфраструктура для интеграционных тестов.
Синтаксис
import { createTestHarness } from "wrangler";
const server = createTestHarness(options);import { createTestHarness } from "wrangler";
const server = createTestHarness(options);Параметры
-
optionsobjectнеобязательно-
Параметры тестового окружения. Если вы вызываете
createTestHarness()без параметров вызовитеserver.update(options)передserver.listen().-
rootstringнеобязательноБазовый каталог, используемый для разрешения относительных путей конфигурации Worker. По умолчанию:
process.cwd(). -
workersWorkerInput[]Workers для запуска в тестовом сервере. Первый Worker считается основным.
-
-
Каждый WorkerInput может загружать Worker из файла конфигурации Wrangler:
const server = createTestHarness({
workers: [
{ configPath: "./wrangler.web.jsonc" },
{ configPath: "./wrangler.api.jsonc" },
],
});const server = createTestHarness({
workers: [
{ configPath: "./wrangler.web.jsonc" },
{ configPath: "./wrangler.api.jsonc" },
],
});Входные данные файла конфигурации поддерживают следующие поля:
configPathstring | URL- Путь к файлу конфигурации Wrangler. Относительные пути разрешаются от
root.
- Путь к файлу конфигурации Wrangler. Относительные пути разрешаются от
envstringнеобязательно- Окружение Wrangler, которое нужно загрузить из файла конфигурации.
varsRecord<string, Json>необязательно- Переменные только для тестирования, которые переопределяют переменные из файла конфигурации Wrangler.
secretsRecord<string, string>необязательно- Секреты только для тестирования, которые переопределяют значения, загруженные из
.dev.varsи.envфайлы.
- Секреты только для тестирования, которые переопределяют значения, загруженные из
bindingOverridesRecord<string, string>необязательно- Переопределения привязок служб только для тестирования. Ключами служат имена привязок в окружении этого Worker. Значениями являются имена Worker в этом тестовом окружении.
Каждый WorkerInput также могут использовать config чтобы передать встроенный объект конфигурации Wrangler:
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",
},
},
],
});Возвращаемый тип
createTestHarness() возвращает TestHarness объект со следующими методами:
listen()Promise<{ url: URL }>- Запускает сервер и возвращает его текущий URL. Повторные вызовы возвращают ту же сессию, пока сервер не будет закрыт или сброшен.
fetch(input, init)Promise<Response>- Отправляет запрос fetch через сервер. Относительные URL разрешаются относительно текущего URL сервера. Абсолютные URL обрабатываются согласно настроенным маршрутам Worker, а если совпадений нет, используется основной Worker.
getWorker(name?)WorkerHandle- Возвращает дескриптор для отправки событий напрямую в Worker. Если имя не указано, возвращается основной Worker.
getLogs()WorkerdStructuredLog[]- Возвращает журналы выполнения Workers, собранные с момента начала текущего сеанса сервера, или
clearLogs()был вызван в последний раз.
- Возвращает журналы выполнения Workers, собранные с момента начала текущего сеанса сервера, или
clearLogs()void- Очищает захваченные журналы среды выполнения Workers.
debug()void- Выводит диагностическую временную шкалу этого тестового сервера, включая события сервера и перехваченные логи Workers runtime. Это полезно при сбое test runner или в cleanup hook.
update(optionsOrUpdater)Promise<void>- Обновляет конфигурацию сервера с помощью
TestHarnessOptionsобъект или функцию, которая получает текущие параметры и возвращает следующие параметры. Если сервер ещё не запущен, это настраивает параметры, используемыеlisten(). Если сервер запущен, это перезагружает работающие Worker. Изменение количества Worker на уже запущенном сервере не поддерживается.
- Обновляет конфигурацию сервера с помощью
reset()Promise<void>- Восстанавливает сервер до параметров, использованных при первом запуске текущей сессии. Хранилище пересоздаётся, а URL-адрес сервера может измениться после сброса.
close()Promise<void>- Останавливает сервер и освобождает все ресурсы среды выполнения.
getWorker(name?) возвращает WorkerHandle объект со следующими методами:
fetch(input, init)Promise<Response>- Отправляет событие fetch непосредственно этому Worker.
scheduled(options)Promise<{ outcome: "ok" | "canceled" | "exception"; noRetry: boolean }>- Отправляет событие scheduled непосредственно этому Worker.
getEnv()Promise<Env>- Возвращает полный объект окружения, настроенный для этого Worker, включая переменные, секреты и привязки.
getExport()Promise<Service<Module['default']>>- Возвращает экспорт Worker по умолчанию, включая методы RPC.
applyD1Migrations(bindingName)Promise<void>- Применяет локальные файлы миграций D1, которые ещё не выполнялись, к привязке D1 в этом Worker.
getDurableObjectStorage(classNameOrBindingName, options)Promise<DurableObjectStorageHandle>- Возвращает доступ к SQL-хранилищу для экземпляра Durable Object.
introspectWorkflow(bindingName)Promise<WorkflowIntrospector>- Создает интроспектор для экземпляров Workflow, созданных после вызова этого метода.
introspectWorkflowInstance(bindingName, instanceId)Promise<WorkflowInstanceIntrospector>- Создает интроспектор для конкретного экземпляра Workflow.
Использование
В этом примере используется встроенный тест-раннер Node.js:
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
Генерирует определения типов TypeScript на основе конфигурации вашего Worker. Этот API использует ту же базовую логику, что и wrangler types CLI-команду, поэтому вывод остается согласованным между CLI и программным API.
В отличие от команды CLI, experimental_generateTypes не записывает на диск автоматически. Вместо этого он возвращает сгенерированное содержимое типов в виде структурированных строк, чтобы вы могли обработать их по своему усмотрению.
Синтаксис
import { experimental_generateTypes } from "wrangler";
const result = await experimental_generateTypes(options);Параметры
-
optionsobjectнеобязательно-
Необязательный объект параметров, повторяющий структуру
wrangler typesфлаги CLI:-
configstring | string[]Путь к используемому файлу конфигурации Wrangler. Может быть массивом для разрешения нескольких конфигураций.
-
envstringИмя окружения Wrangler, для которого нужно сгенерировать типы.
-
envFilestring[]Пути к
.envфайлы для загрузки при определении локальных переменных и секретов. -
envInterfacestringИмя сгенерированного интерфейса окружения. Значение по умолчанию:
Env. -
includeEnvbooleanНужно ли включать в результат типы environment и bindings. По умолчанию:
true. -
includeRuntimebooleanНужно ли включать в результат runtime-типы. По умолчанию:
true. -
pathstringПуть к файлу деклараций для сгенерированных типов. По умолчанию используется
worker-configuration.d.ts. -
strictVarsbooleanНужно ли генерировать строгие литеральные и union-типы для переменных. По умолчанию:
true.
-
-
Возвращаемый тип
experimental_generateTypes() возвращает Promise, разрешающийся в объект со следующими полями:
-
contentstring- Единый форматированный вывод, включающий все сгенерированные разделы, в том числе заголовки, а также типы env и runtime.
-
envstring | null- Сгенерированные типы окружения и привязок, либо
nullкогда типы env исключены.
- Сгенерированные типы окружения и привязок, либо
-
pathstring- Путь к файлу деклараций, связанному с этим запуском генерации.
-
runtimestring | null- Сгенерированные типы среды выполнения, либо
nullкогда runtime типы исключены.
- Сгенерированные типы среды выполнения, либо
Использование
Вы можете использовать experimental_generateTypes чтобы сгенерировать типы программно и самостоятельно записать их на диск либо передать другим инструментам:
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");Чтобы сгенерировать только типы env, без типов runtime:
const result = await experimental_generateTypes({
includeRuntime: false,
});Чтобы сгенерировать типы для конкретного окружения с пользовательским именем интерфейса:
const result = await experimental_generateTypes({
env: "staging",
envInterface: "StagingEnv",
path: "./types/staging.d.ts",
});unstable_startWorker
Этот API открывает доступ к внутреннему устройству dev-сервера Wrangler и позволяет настраивать его работу. Например, вы можете использовать unstable_startWorker() для запуска интеграционных тестов для вашего Worker. В этом примере используется node:test, но должно подходить для любого тестового фреймворка:
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
Запустите HTTP-сервер для тестирования Worker.
После вызова unstable_dev вернёт fetch() функция для вызова вашего Worker без необходимости знать адрес или порт, а также stop() функцию для остановки HTTP-сервера.
По умолчанию unstable_dev выполнит интеграционные тесты на локальном сервере. Если вы хотите выполнить e2e-тест на предварительном Worker, передайте local: false в options объект при вызове unstable_dev() функция. Обратите внимание, что e2e-тесты могут выполняться значительно медленнее, чем интеграционные тесты.
Конструктор
const worker = await unstable_dev(script, options);Параметры
-
scriptstring- Строка с путём к скрипту вашего Worker относительно корневой директории вашего проекта Worker.
-
optionsobjectнеобязательно- Необязательный объект параметров, содержащий
wrangler devпараметры конфигурации. - Добавьте
experimentalобъект внутриoptionsдля доступа к экспериментальным функциям, таким какdisableExperimentalWarning.- Задайте
disableExperimentalWarningкtrueчтобы отключить предупреждение Wrangler об использованииunstable_API с этим префиксом.
- Задайте
- Необязательный объект параметров, содержащий
Возвращаемый тип
unstable_dev() возвращает объект со следующими методами:
-
fetch()Promise<Response> -
stop()Promise<void>- Останавливает сервер разработки.
Использование
При запуске каждого набора тестов используйте beforeAll() функцию для запуска unstable_dev(). beforeAll() функция используется для минимизации накладных расходов: запуск dev-сервера занимает несколько сотен миллисекунд, а запуск и остановка для каждого отдельного теста быстро накапливаются и замедляют выполнение тестов.
В каждом тестовом случае вызывайте await worker.fetch(), и проверьте, что ответ соответствует ожидаемому.
Чтобы завершить набор тестов, вызовите await worker.stop() в afterAll функцию.
Пример одного Worker
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!"`);
});
});Пример с несколькими Workers
Можно тестировать Workers, которые вызывают другие Workers. В примере ниже Worker, вызывающий другие Workers, называется родительским Worker, а вызываемый Worker называется дочерним Worker.
Если вы преждевременно завершите работу дочернего Worker, родительский Worker не будет знать о его существовании, и тесты завершатся с ошибкой.
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
getPlatformProxy функция предоставляет способ получить объект, содержащий прокси (к локальный workerd привязок) и эмуляции специфичных для Cloudflare Workers значений, что позволяет эмулировать их в процессе Node.js.
Один из распространенных случаев использования platform proxy: эмуляция привязок в приложениях, ориентированных на Workers, но выполняющихся вне среды выполнения Workers (например, локальные серверы разработки фреймворков, работающие в Node.js), либо для целей тестирования (например, чтобы убедиться, что код корректно взаимодействует с определенным типом привязки).
Синтаксис
const platform = await getPlatformProxy(options);Параметры
optionsobjectнеобязательно- Необязательный объект параметров с настройками для привязок:
-
environmentстрокаИспользуемое окружение.
-
configPathстрокаПуть к используемому файлу конфигурации.
Если путь не указан, по умолчанию поиск выполняется вверх по файловой системе от текущего каталога в поисках конфигурационный файл Wrangler для использования.
Примечание: это поле необязательно, но если путь указан, он должен указывать на существующий файл в файловой системе.
-
persistboolean |{ path: string }Указывает, нужно ли сохранять данные привязок и где именно. Если
trueилиundefined, по умолчанию использует то же расположение, что и Wrangler, поэтому данные можно передавать между ним и вызывающей стороной. Еслиfalse, данные не сохраняются в файловую систему и не считываются из неё.Примечание: Если вы используете
wrangler:--persist-toпараметр, обратите внимание, что он добавляет подкаталог с именемv3под капотом, в то время какgetPlatformProxy:persistнет. Например, если вы выполнитеwrangler dev --persist-to ./my-directory, чтобы повторно использовать то же расположение с помощьюgetPlatformProxy, вам нужно будет указать:persist: { path: "./my-directory/v3" }. -
remoteBindingsboolean необязательно (по умолчанию: `true`)Независимо от того, удаленные привязки следует включить.
-
- Необязательный объект параметров с настройками для привязок:
Возвращаемый тип
getPlatformProxy() возвращает Promise, разрешающийся в объект со следующими полями.
-
envRecord<string, unknown>- Объект, содержащий прокси к привязкам (bindings), которые можно использовать так же, как привязки production. Он соответствует структуре
envобъект, передаваемый в качестве второго аргумента воркерам в формате модулей. Они проксируют к реализациям привязок, выполняемым внутриworkerd. - Совет по TypeScript:
getPlatformProxy<Env>()представляет собой обобщённую (generic) функцию. Вы можете передать форму записи bindings в качестве аргумента типа, чтобы получить корректные типы безunknownзначения.
- Объект, содержащий прокси к привязкам (bindings), которые можно использовать так же, как привязки production. Он соответствует структуре
-
cfIncomingRequestCfProperties только для чтения- Мок для
Request:cfсвойство, содержащее данные, похожие на те, что вы увидели бы в продакшене.
- Мок для
-
ctxобъект- Мок-объект, содержащий реализации
waitUntilиpassThroughOnExceptionфункции, которые ничего не делают.
- Мок-объект, содержащий реализации
-
cachesобъект- Эмуляция Workers
cachesruntime API. - Пока что все операции с кешем не выполняют никаких действий. Более точная эмуляция появится позже.
- Эмуляция Workers
-
dispose()() =>Promise<void>- Завершает работу базового
workerdпроцесс. - Вызывайте этот метод после того, как платформенный прокси перестанет быть нужен программе. Если вы выполняете долгоживущий процесс (например, dev-сервер), который может использовать прокси неограниченное время, вызывать эту функцию не нужно.
- Завершает работу базового
Использование
getPlatformProxy функция использует привязки, найденные в конфигурационный файл Wrangler. Например, если у вас есть переменная окружения конфигурацию, заданную в файле конфигурации Wrangler:
{
"vars": {
"MY_VARIABLE": "test"
}
}[vars]
MY_VARIABLE = "test"Доступ к привязкам можно получить, импортировав getPlatformProxy следующим образом:
import { getPlatformProxy } from "wrangler";
const { env } = await getPlatformProxy();Чтобы получить значение MY_VARIABLE привязку добавьте в свой код следующее:
console.log(`MY_VARIABLE = ${env.MY_VARIABLE}`);Это выведет следующий результат: MY_VARIABLE = test.
Поддерживаемые привязки
Все поддерживаемые привязки, найденные в конфигурационный файл Wrangler доступны вам через env.
Привязки, поддерживаемые getPlatformProxy это:
-
-
Чтобы использовать привязку Durable Object с
getPlatformProxy, всегда указывайтеscript_name.Например, у вас может быть такая привязка в файле конфигурации Wrangler, который читает
getPlatformProxy.{ "durable_objects": { "bindings": [ { "name": "MyDurableObject", "class_name": "MyDurableObject", "script_name": "external-do-worker" } ] } }[[durable_objects.bindings]] name = "MyDurableObject" class_name = "MyDurableObject" script_name = "external-do-worker"Вам нужно будет объявить ваш Durable Object
"MyDurableObject"в другом Worker, называемомexternal-do-workerв этом примере../external-do-worker/src/index.tsexport class MyDurableObject extends DurableObject { // Your DO code goes here } export default { fetch() { // Doesn't have to do anything, but a DO cannot be the default export return new Response("Hello, world!"); }, };Этому Worker также нужен файл конфигурации Wrangler, который выглядит следующим образом:
{ "name": "external-do-worker", "main": "src/index.ts", "compatibility_date": "XXXX-XX-XX" }name = "external-do-worker" main = "src/index.ts" compatibility_date = "XXXX-XX-XX"Если вы не используете RPC с Durable Object, можно запустить отдельную сессию Wrangler dev параллельно с сервером разработки вашего фреймворка.
В противном случае можно собрать приложение и запустить оба Worker в одном сеансе Wrangler dev.
Если вы используете Pages, выполните:
npx wrangler pages dev -c path/to/pages/wrangler.jsonc -c path/to/external-do-worker/wrangler.jsoncЕсли вы используете Workers с Assets, выполните:
npx wrangler dev -c path/to/workers-assets/wrangler.jsonc -c path/to/external-do-worker/wrangler.jsonc
-