1import { sortServerModules, type OutputFile } from "../../core/index.ts";
2import { describe, expect, it } from "vitest";
3import {
4 listEdgeFunctions,
5 DEFAULT_COMPATIBILITY_DATE,
6 hasDoQueueClass,
7 makeRunnerConfig,
8 toRuntimeModules,
9 WORKER_ENTRY_MODULE,
10} from "../Nextjs.ts";
11
12const file = (name: string, content: string | Uint8Array): OutputFile => ({
13 name,
14 content,
15 hash: "test",
16});
17
18describe("makeRunnerConfig", () => {
19 it("applies defaults", () => {
20 const config = makeRunnerConfig("/app");
21 expect(config).toEqual({
22 appDir: "/app",
23 configPath: undefined,
24 cache: "static-assets",
25 compatibilityDate: DEFAULT_COMPATIBILITY_DATE,
26 skipNextBuild: false,
27 minify: false,
28 debug: false,
29 buildCommand: undefined,
30 });
31 });
32
33 it("honors options", () => {
34 const config = makeRunnerConfig("/app", {
35 vite: { compatibilityDate: "2026-01-01" },
36 nextjs: {
37 configPath: "custom.config.ts",
38 cache: "kv",
39 buildCommand: "npx next build --debug",
40 skipNextBuild: true,
41 minify: true,
42 debug: true,
43 },
44 });
45 expect(config).toEqual({
46 appDir: "/app",
47 configPath: "custom.config.ts",
48 cache: "kv",
49 compatibilityDate: "2026-01-01",
50 skipNextBuild: true,
51 minify: true,
52 debug: true,
53 buildCommand: "npx next build --debug",
54 });
55 });
56});
57
58describe("toRuntimeModules", () => {
59 it("maps extensions to cloudflare-runtime module types", () => {
60 const modules = toRuntimeModules([
61 file("worker/worker.js", "entry"),
62 file("worker/chunks/a.mjs", "chunk"),
63 file("worker/legacy.cjs", "cjs"),
64 file("worker/data.json", `{"a":1}`),
65 file("worker/wasm.wasm", new Uint8Array([0, 97, 115, 109])),
66 file("worker/blob.bin", new Uint8Array([1, 2, 3])),
67 file("worker/readme.txt", "text"),
68 ]);
69 expect(modules.map((module) => [module.name, module.type])).toEqual([
70 ["worker/worker.js", "ESModule"],
71 ["worker/chunks/a.mjs", "ESModule"],
72 ["worker/legacy.cjs", "CommonJsModule"],
73 ["worker/data.json", "Json"],
74 ["worker/wasm.wasm", "Wasm"],
75 ["worker/blob.bin", "Data"],
76 ["worker/readme.txt", "Text"],
77 ]);
78 });
79
80 it("drops sourcemaps", () => {
81 expect(toRuntimeModules([file("worker/worker.js.map", "{}")])).toEqual([]);
82 });
83
84 it("normalizes buffered text content to strings and text to bytes", () => {
85 const [text] = toRuntimeModules([
86 file("worker/worker.js", Buffer.from("hello")),
87 ]);
88 expect(text).toEqual({
89 name: "worker/worker.js",
90 type: "ESModule",
91 content: "hello",
92 });
93 const [bytes] = toRuntimeModules([file("worker/blob.bin", "abc")]);
94 expect(bytes?.type).toBe("Data");
95 expect(bytes?.content).toBeInstanceOf(Uint8Array);
96 });
97});
98
99describe("hasDoQueueClass", () => {
100 it("detects the DO queue class in string and buffered entries", () => {
101 expect(
102 hasDoQueueClass(file("worker/worker.js", "export { DOQueueHandler }")),
103 ).toBe(true);
104 expect(
105 hasDoQueueClass(
106 file("worker/worker.js", Buffer.from("class DOQueueHandler")),
107 ),
108 ).toBe(true);
109 expect(hasDoQueueClass(file("worker/worker.js", "export default {}"))).toBe(
110 false,
111 );
112 expect(hasDoQueueClass(undefined)).toBe(false);
113 });
114});
115
116describe("server module ordering", () => {
117 it("sorts the worker entry first", () => {
118 const sorted = sortServerModules(
119 [
120 file("worker/chunks/a.js", "a"),
121 file(WORKER_ENTRY_MODULE, "entry"),
122 file("worker/chunks/b.js", "b"),
123 ],
124 WORKER_ENTRY_MODULE,
125 );
126 expect(sorted[0]?.name).toBe(WORKER_ENTRY_MODULE);
127 expect(WORKER_ENTRY_MODULE).toBe("worker/worker.js");
128 });
129});
130
131describe("listEdgeFunctions", () => {
132 it("returns edge function paths from the middleware manifest", () => {
133 expect(
134 listEdgeFunctions({
135 middleware: { "/": { files: [] } },
136 functions: {
137 "/api/edge/route": { files: [] },
138 "/edge-page": { files: [] },
139 },
140 }),
141 ).toEqual(["/api/edge/route", "/edge-page"]);
142 });
143
144 it("treats middleware-only manifests (and junk) as edge-free", () => {
145 expect(listEdgeFunctions({ middleware: { "/": { files: [] } } })).toEqual(
146 [],
147 );
148 expect(listEdgeFunctions({})).toEqual([]);
149 expect(listEdgeFunctions(undefined)).toEqual([]);
150 expect(listEdgeFunctions("nope")).toEqual([]);
151 });
152});