branch:
e2e.test.ts
14195 bytesRaw
import { describe, it, expect } from "vitest";
import { env } from "cloudflare:workers";
import { createWorker } from "../index";
import { parseWranglerConfig, hasNodejsCompat } from "../config";
import { detectEntryPoint } from "../utils";
import type { CreateWorkerOptions, Files } from "../types";
let testId = 0;
/**
* Build a worker with createWorker, load it into the Worker Loader,
* call fetch(), and return the Response.
*/
async function buildAndFetch(
options: CreateWorkerOptions,
request: Request = new Request("http://worker/")
): Promise<Response> {
const result = await createWorker(options);
const id = "test-worker-" + testId++;
const worker = env.LOADER.get(id, () => ({
mainModule: result.mainModule,
modules: result.modules,
compatibilityDate: result.wranglerConfig?.compatibilityDate ?? "2026-01-01",
compatibilityFlags: result.wranglerConfig?.compatibilityFlags
}));
return worker.getEntrypoint().fetch(request);
}
describe("createWorker e2e (build + load + fetch)", () => {
it("bundles and runs a simple worker", async () => {
const response = await buildAndFetch({
files: {
"src/index.ts": [
"export default {",
" fetch() {",
' return new Response("hello");',
" }",
"};"
].join("\n")
}
});
expect(response.status).toBe(200);
expect(await response.text()).toBe("hello");
});
it("bundles multiple files with relative imports", async () => {
const response = await buildAndFetch({
files: {
"src/index.ts": [
'import { greet } from "./utils";',
"export default {",
" fetch() {",
' return new Response(greet("world"));',
" }",
"};"
].join("\n"),
"src/utils.ts": [
"export function greet(name: string): string {",
' return "Hello, " + name + "!";',
"}"
].join("\n")
}
});
expect(await response.text()).toBe("Hello, world!");
});
it("respects explicit entryPoint option", async () => {
const response = await buildAndFetch({
files: {
"worker.ts": [
"export default {",
" fetch() {",
' return new Response("custom entry");',
" }",
"};"
].join("\n")
},
entryPoint: "worker.ts"
});
expect(await response.text()).toBe("custom entry");
});
it("runs a worker that uses cloudflare:workers", async () => {
const response = await buildAndFetch({
files: {
"src/index.ts": [
'import { WorkerEntrypoint } from "cloudflare:workers";',
"export default class extends WorkerEntrypoint {",
" fetch() {",
' return new Response("entrypoint works");',
" }",
"}"
].join("\n")
}
});
expect(await response.text()).toBe("entrypoint works");
});
it("runs a worker that reads the request", async () => {
const response = await buildAndFetch(
{
files: {
"src/index.ts": [
"export default {",
" async fetch(request) {",
" const url = new URL(request.url);",
' return new Response("path: " + url.pathname);',
" }",
"};"
].join("\n")
}
},
new Request("http://worker/hello/world")
);
expect(await response.text()).toBe("path: /hello/world");
});
it("runs a worker that returns JSON", async () => {
const response = await buildAndFetch({
files: {
"src/index.ts": [
"export default {",
" fetch() {",
' return Response.json({ status: "ok", count: 42 });',
" }",
"};"
].join("\n")
}
});
expect(response.headers.get("content-type")).toContain("application/json");
const data = await response.json();
expect(data).toEqual({ status: "ok", count: 42 });
});
it("runs a minified worker", async () => {
const response = await buildAndFetch({
files: {
"src/index.ts": [
"export default {",
" fetch() {",
' const message = "minified";',
" return new Response(message);",
" }",
"};"
].join("\n")
},
minify: true
});
expect(await response.text()).toBe("minified");
});
it(
"installs npm dependencies and runs the worker",
{ timeout: 30_000 },
async () => {
const response = await buildAndFetch({
files: {
"src/index.ts": [
'import { escape } from "he";',
"export default {",
" fetch() {",
' return new Response(escape("<h1>hello</h1>"));',
" }",
"};"
].join("\n"),
"package.json": JSON.stringify({
dependencies: { he: "^1.2.0" }
})
}
});
expect(response.status).toBe(200);
const text = await response.text();
// he.escape should HTML-encode the angle brackets
expect(text).toContain("<");
expect(text).toContain(">");
expect(text).not.toContain("<h1>");
}
);
it("runs a worker with wrangler.toml nodejs_compat", async () => {
const response = await buildAndFetch({
files: {
"src/index.ts": [
'import { Buffer } from "node:buffer";',
"export default {",
" fetch() {",
' const buf = Buffer.from("hello");',
' return new Response(buf.toString("base64"));',
" }",
"};"
].join("\n"),
"wrangler.toml": [
'main = "src/index.ts"',
'compatibility_date = "2026-01-28"',
'compatibility_flags = ["nodejs_compat"]'
].join("\n")
}
});
expect(await response.text()).toBe("aGVsbG8=");
});
});
describe("createWorker transform-only mode (build + load + fetch)", () => {
it("transforms and runs a multi-file worker without bundling", async () => {
const result = await createWorker({
files: {
"src/index.ts": [
'import { greet } from "./utils";',
"export default {",
" fetch() {",
' return new Response(greet("world"));',
" }",
"};"
].join("\n"),
"src/utils.ts": [
"export function greet(name: string): string {",
' return "Hello, " + name + "!";',
"}"
].join("\n")
},
bundle: false
});
expect(result.mainModule).toBe("src/index.js");
expect(result.modules["src/index.js"]).toBeDefined();
expect(result.modules["src/utils.js"]).toBeDefined();
const id = "test-transform-" + testId++;
const worker = env.LOADER.get(id, () => ({
mainModule: result.mainModule,
modules: result.modules,
compatibilityDate: "2026-01-01"
}));
const response = await worker
.getEntrypoint()
.fetch(new Request("http://worker/"));
expect(await response.text()).toBe("Hello, world!");
});
});
describe("createWorker error cases", () => {
it("throws when entry point is not found", async () => {
await expect(
createWorker({
files: { "src/other.ts": "export const x = 1;" },
entryPoint: "src/index.ts"
})
).rejects.toThrow('Entry point "src/index.ts" not found');
});
it("throws when no entry point can be detected", async () => {
await expect(
createWorker({
files: { "lib/other.ts": "export const x = 1;" }
})
).rejects.toThrow("Could not determine entry point");
});
});
describe("createWorker output validation", () => {
it("treats cloudflare: modules as external in bundle", async () => {
const result = await createWorker({
files: {
"src/index.ts": [
'import { WorkerEntrypoint } from "cloudflare:workers";',
"export default class extends WorkerEntrypoint {",
' fetch() { return new Response("ok"); }',
"}"
].join("\n")
}
});
const bundle = result.modules["bundle.js"] as string;
expect(bundle).toContain("cloudflare:workers");
});
it("treats user-specified externals as external", async () => {
const result = await createWorker({
files: {
"src/index.ts": [
'import pg from "pg";',
"export default {",
" fetch() { return new Response(pg.name); }",
"};"
].join("\n")
},
externals: ["pg"]
});
const bundle = result.modules["bundle.js"] as string;
expect(bundle).toContain("pg");
});
it("parses wrangler.toml and returns config", async () => {
const result = await createWorker({
files: {
"src/index.ts":
'export default { fetch() { return new Response("ok"); } };',
"wrangler.toml": [
'main = "src/index.ts"',
'compatibility_date = "2026-01-01"',
'compatibility_flags = ["nodejs_compat"]'
].join("\n")
}
});
expect(result.wranglerConfig).toBeDefined();
expect(result.wranglerConfig?.compatibilityDate).toBe("2026-01-01");
expect(result.wranglerConfig?.compatibilityFlags).toContain(
"nodejs_compat"
);
});
it("supports sourcemap option", async () => {
const result = await createWorker({
files: {
"src/index.ts":
'export default { fetch() { return new Response("ok"); } };'
},
sourcemap: true
});
const bundle = result.modules["bundle.js"] as string;
expect(bundle).toContain("sourceMappingURL");
});
it("supports minify option", async () => {
const files = {
"src/index.ts": [
"export default {",
" fetch() {",
' const longVariableName = "hello";',
" return new Response(longVariableName);",
" }",
"};"
].join("\n")
};
const unminified = await createWorker({ files, minify: false });
const minified = await createWorker({ files, minify: true });
const unminifiedSize = (unminified.modules["bundle.js"] as string).length;
const minifiedSize = (minified.modules["bundle.js"] as string).length;
expect(minifiedSize).toBeLessThan(unminifiedSize);
});
});
describe("detectEntryPoint", () => {
it("detects from wrangler config main", () => {
const files: Files = { "src/worker.ts": "export default {}" };
const config = { main: "src/worker.ts" };
expect(detectEntryPoint(files, config)).toBe("src/worker.ts");
});
it("strips ./ from wrangler config main", () => {
const files: Files = { "src/worker.ts": "export default {}" };
const config = { main: "./src/worker.ts" };
expect(detectEntryPoint(files, config)).toBe("src/worker.ts");
});
it("detects from package.json main field", () => {
const files: Files = {
"package.json": JSON.stringify({ main: "./lib/index.js" }),
"lib/index.js": "export default {}"
};
expect(detectEntryPoint(files, undefined)).toBe("lib/index.js");
});
it("detects from package.json exports field", () => {
const files: Files = {
"package.json": JSON.stringify({
exports: { ".": { import: "./src/entry.ts" } }
}),
"src/entry.ts": "export default {}"
};
expect(detectEntryPoint(files, undefined)).toBe("src/entry.ts");
});
it("falls back to src/index.ts default", () => {
const files: Files = { "src/index.ts": "export default {}" };
expect(detectEntryPoint(files, undefined)).toBe("src/index.ts");
});
it("falls back to index.ts default", () => {
const files: Files = { "index.ts": "export default {}" };
expect(detectEntryPoint(files, undefined)).toBe("index.ts");
});
it("returns undefined when no entry found", () => {
const files: Files = { "lib/other.ts": "export const x = 1;" };
expect(detectEntryPoint(files, undefined)).toBeUndefined();
});
});
describe("parseWranglerConfig", () => {
it("parses wrangler.toml", () => {
const files: Files = {
"wrangler.toml": [
'main = "src/index.ts"',
'compatibility_date = "2026-01-01"',
'compatibility_flags = ["nodejs_compat"]'
].join("\n")
};
const config = parseWranglerConfig(files);
expect(config).toBeDefined();
expect(config?.main).toBe("src/index.ts");
expect(config?.compatibilityDate).toBe("2026-01-01");
expect(config?.compatibilityFlags).toEqual(["nodejs_compat"]);
});
it("parses wrangler.json", () => {
const files: Files = {
"wrangler.json": JSON.stringify({
main: "src/index.ts",
compatibility_date: "2026-01-01"
})
};
const config = parseWranglerConfig(files);
expect(config?.main).toBe("src/index.ts");
expect(config?.compatibilityDate).toBe("2026-01-01");
});
it("parses wrangler.jsonc with comments", () => {
const files: Files = {
"wrangler.jsonc": [
"{",
" // Entry point",
' "main": "src/index.ts",',
" /* Compat settings */",
' "compatibility_date": "2026-01-01"',
"}"
].join("\n")
};
const config = parseWranglerConfig(files);
expect(config?.main).toBe("src/index.ts");
expect(config?.compatibilityDate).toBe("2026-01-01");
});
it("returns undefined when no config file exists", () => {
const files: Files = { "src/index.ts": "export default {}" };
expect(parseWranglerConfig(files)).toBeUndefined();
});
it("returns empty object for invalid toml", () => {
const files: Files = { "wrangler.toml": "not valid toml {{{" };
const config = parseWranglerConfig(files);
expect(config).toEqual({});
});
});
describe("hasNodejsCompat", () => {
it("returns true when nodejs_compat is present", () => {
expect(hasNodejsCompat({ compatibilityFlags: ["nodejs_compat"] })).toBe(
true
);
});
it("returns false when flag is absent", () => {
expect(hasNodejsCompat({ compatibilityFlags: [] })).toBe(false);
});
it("returns false for undefined config", () => {
expect(hasNodejsCompat(undefined)).toBe(false);
});
});