Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 29 additions & 31 deletions fixtures/additional-modules/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import childProcess from "node:child_process";
import { existsSync } from "node:fs";
import { existsSync, mkdtempSync } from "node:fs";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { removeDir } from "@fixture/shared/src/fs-helpers";
import { afterAll, assert, beforeAll, describe, test, vi } from "vitest";
import { unstable_startWorker } from "wrangler";
import { createServer, type WorkerServer } from "wrangler";
import { wranglerEntryPath } from "../../shared/src/run-wrangler-long-lived";

async function getTmpDir() {
return fs.mkdtemp(path.join(os.tmpdir(), "wrangler-modules-"));
}

type WranglerDev = Awaited<ReturnType<typeof unstable_startWorker>>;
function get(worker: WranglerDev, pathname: string) {
const url = `http://example.com${pathname}`;
// Disable Miniflare's pretty error page, so we can parse errors as JSON
return worker.fetch(url, { headers: { "MF-Disable-Pretty-Error": "true" } });
}

describe("find_additional_modules dev", () => {
let tmpDir: string;
let worker: WranglerDev;
const tmpDir = mkdtempSync(path.join(os.tmpdir(), "wrangler-modules-"));
const server = createServer({
root: tmpDir,
workers: [{ configPath: "wrangler.jsonc" }],
watch: true,
});

function get(server: WorkerServer, pathname: string) {
const url = `http://example.com${pathname}`;
// Disable Miniflare's pretty error page, so we can parse errors as JSON
return server.fetch(url, {
headers: { "MF-Disable-Pretty-Error": "true" },
});
}

beforeAll(async () => {
// Copy over files to a temporary directory as we'll be modifying them
tmpDir = await getTmpDir();
await fs.cp(
path.resolve(__dirname, "..", "src"),
path.join(tmpDir, "src"),
Expand All @@ -36,37 +36,35 @@ describe("find_additional_modules dev", () => {
path.join(tmpDir, "wrangler.jsonc")
);

worker = await unstable_startWorker({
config: path.join(tmpDir, "wrangler.jsonc"),
});
await server.listen();
});
afterAll(async () => {
await worker.dispose();
await server.close();
removeDir(tmpDir, { fireAndForget: true });
});

test("supports bundled modules", async ({ expect }) => {
const res = await get(worker, "/dep");
const res = await get(server, "/dep");
expect(await res.text()).toBe("bundled");
});
test("supports text modules", async ({ expect }) => {
const res = await get(worker, "/text");
const res = await get(server, "/text");
expect(await res.text()).toBe("test\n");
});
test("supports SQL modules", async ({ expect }) => {
const res = await get(worker, "/sql");
const res = await get(server, "/sql");
expect(await res.text()).toBe("SELECT * FROM users;\n");
});
test("supports dynamic imports", async ({ expect }) => {
const res = await get(worker, "/dynamic");
const res = await get(server, "/dynamic");
expect(await res.text()).toBe("dynamic");
});
test("supports commonjs lazy imports", async ({ expect }) => {
const res = await get(worker, "/common");
const res = await get(server, "/common");
expect(await res.text()).toBe("common");
});
test("supports variable dynamic imports", async ({ expect }) => {
const res = await get(worker, "/lang/en");
const res = await get(server, "/lang/en");
expect(await res.text()).toBe("hello");
});

Expand All @@ -79,15 +77,15 @@ describe("find_additional_modules dev", () => {
'export default "new dynamic";'
);
await vi.waitFor(async () => {
const res = await get(worker, "/dynamic");
const res = await get(server, "/dynamic");
assert.strictEqual(await res.text(), "new dynamic");
});

// Delete dynamically imported file
await fs.rm(path.join(srcDir, "lang", "en.js"));

await vi.waitFor(async () => {
await expect(get(worker, "/lang/en")).rejects.toThrowError(
await expect(get(server, "/lang/en")).rejects.toThrowError(
'No such module "lang/en.js".'
);
});
Expand All @@ -99,7 +97,7 @@ describe("find_additional_modules dev", () => {
'export default { hello: "hey" };'
);
await vi.waitFor(async () => {
const res = await get(worker, "/lang/en/us");
const res = await get(server, "/lang/en/us");
assert.strictEqual(await res.text(), "hey");
});

Expand All @@ -109,7 +107,7 @@ describe("find_additional_modules dev", () => {
'export default { hello: "bye" };'
);
await vi.waitFor(async () => {
const res = await get(worker, "/lang/en/us");
const res = await get(server, "/lang/en/us");
assert.strictEqual(await res.text(), "bye");
});
});
Expand All @@ -126,7 +124,7 @@ function build(cwd: string, outDir: string) {
describe("find_additional_modules deploy", () => {
let tmpDir: string;
beforeAll(async () => {
tmpDir = await getTmpDir();
tmpDir = mkdtempSync(path.join(os.tmpdir(), "wrangler-modules-"));
});
afterAll(async () => await removeDir(tmpDir, { fireAndForget: true }));

Expand Down
27 changes: 27 additions & 0 deletions fixtures/create-server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@fixture/create-server",
"private": true,
"description": "Integration tests with createServer API",
"type": "module",
"scripts": {
"check:type": "tsc",
"build": "vite build",
"test:ci": "vitest run",
"type:tests": "tsc -p ./tests/tsconfig.json"
},
"devDependencies": {
"@cloudflare/vite-plugin": "workspace:*",
"@cloudflare/workers-tsconfig": "workspace:*",
"@cloudflare/workers-types": "catalog:default",
"@fixture/shared": "workspace:*",
"@types/node": "catalog:default",
"msw": "catalog:default",
"typescript": "catalog:default",
"vite": "catalog:default",
"vitest": "catalog:default",
"wrangler": "workspace:*"
},
"volta": {
"extends": "../../package.json"
}
}
18 changes: 18 additions & 0 deletions fixtures/create-server/src/auxiliary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
let lastTriggeredCron: string | null = null;

export default {
async fetch(request, env) {
const url = new URL(request.url);

if (url.pathname === "/scheduled") {
return new Response(lastTriggeredCron ?? "no cron triggered", {
headers: { "Content-Type": "text/plain" },
});
}

return fetch("http://example.com/auxiliary");
},
async scheduled(event) {
lastTriggeredCron = event.cron;
},
} satisfies ExportedHandler<{ NAME: string }>;
18 changes: 18 additions & 0 deletions fixtures/create-server/src/primary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
let lastTriggeredCron: string | null = null;

export default {
async fetch(request, env) {
const url = new URL(request.url);

if (url.pathname === "/scheduled") {
return new Response(lastTriggeredCron ?? "no cron triggered", {
headers: { "Content-Type": "text/plain" },
});
}

return fetch("http://example.com/primary");
},
async scheduled(event) {
lastTriggeredCron = event.cron;
},
} satisfies ExportedHandler<{ NAME: string }>;
9 changes: 9 additions & 0 deletions fixtures/create-server/tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "@cloudflare/workers-tsconfig/tsconfig.json",
"compilerOptions": {
"module": "esnext",
"types": ["node"]
},
"include": ["**/*.ts"],
"exclude": []
}
70 changes: 70 additions & 0 deletions fixtures/create-server/tests/vite-project.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";
import { afterAll, beforeAll, describe, it } from "vitest";
import { createServer } from "wrangler";

const mockServer = setupServer(
http.get("http://example.com/:worker", ({ params }) => {
return HttpResponse.text(`mock:${params.worker}`);
})
);
const workerServer = createServer({
workers: [
{ configPath: "./dist/primary_worker/wrangler.json" },
{ configPath: "./dist/auxiliary_worker/wrangler.json" },
],
});
const primaryWorker = workerServer.getWorker();
const auxiliaryWorker = workerServer.getWorker("auxiliary-worker");

describe("createServer: vite project setup", () => {
beforeAll(async () => {
mockServer.listen({ onUnhandledRequest: "error" });
await workerServer.listen();
});

afterAll(async () => {
mockServer.close();
await workerServer.close();
});

it("could fetch workers with mocking support", async ({ expect }) => {
const primaryResponse = await primaryWorker.fetch("http://example.com");
await expect(primaryResponse.text()).resolves.toBe("mock:primary");
const auxiliaryResponse = await auxiliaryWorker.fetch("http://example.com");
await expect(auxiliaryResponse.text()).resolves.toBe("mock:auxiliary");
});

it("support triggering scheduled events with custom scheduledTime", async ({
expect,
}) => {
const primaryScheduled = await primaryWorker.fetch(
"http://example.com/scheduled"
);
await expect(primaryScheduled.text()).resolves.toBe("no cron triggered");

await expect(
primaryWorker.scheduled({
cron: "* * * * *",
scheduledTime: new Date(1_700_000_100_000),
})
).resolves.toEqual({ outcome: "ok", noRetry: false });

const primaryResponse = await primaryWorker.fetch(
"http://example.com/scheduled"
);
await expect(primaryResponse.text()).resolves.toBe("* * * * *");

await expect(
auxiliaryWorker.scheduled({
cron: "*/5 * * * *",
scheduledTime: new Date(1_700_000_101_000),
})
).resolves.toEqual({ outcome: "ok", noRetry: false });

const auxiliaryResponse = await auxiliaryWorker.fetch(
"http://example.com/scheduled"
);
await expect(auxiliaryResponse.text()).resolves.toBe("*/5 * * * *");
});
});
70 changes: 70 additions & 0 deletions fixtures/create-server/tests/wrangler-project.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";
import { afterAll, beforeAll, describe, it } from "vitest";
import { createServer } from "wrangler";

const mockServer = setupServer(
http.get("http://example.com/:worker", ({ params }) => {
return HttpResponse.text(`mock:${params.worker}`);
})
);
const workerServer = createServer({
workers: [
{ configPath: "./wrangler.primary.jsonc" },
{ configPath: "./wrangler.auxiliary.jsonc" },
],
});
const primaryWorker = workerServer.getWorker();
const auxiliaryWorker = workerServer.getWorker("auxiliary-worker");

describe("createServer: wrangler project setup", () => {
beforeAll(async () => {
mockServer.listen({ onUnhandledRequest: "error" });
await workerServer.listen();
});

afterAll(async () => {
mockServer.close();
await workerServer.close();
});

it("could fetch workers with mocking support", async ({ expect }) => {
const primaryResponse = await primaryWorker.fetch("http://example.com");
await expect(primaryResponse.text()).resolves.toBe("mock:primary");
const auxiliaryResponse = await auxiliaryWorker.fetch("http://example.com");
await expect(auxiliaryResponse.text()).resolves.toBe("mock:auxiliary");
});

it("support triggering scheduled events with custom scheduledTime", async ({
expect,
}) => {
const primaryScheduled = await primaryWorker.fetch(
"http://example.com/scheduled"
);
await expect(primaryScheduled.text()).resolves.toBe("no cron triggered");

await expect(
primaryWorker.scheduled({
cron: "* * * * *",
scheduledTime: new Date(1_700_000_100_000),
})
).resolves.toEqual({ outcome: "ok", noRetry: false });

const primaryResponse = await primaryWorker.fetch(
"http://example.com/scheduled"
);
await expect(primaryResponse.text()).resolves.toBe("* * * * *");

await expect(
auxiliaryWorker.scheduled({
cron: "*/5 * * * *",
scheduledTime: new Date(1_700_000_101_000),
})
).resolves.toEqual({ outcome: "ok", noRetry: false });

const auxiliaryResponse = await auxiliaryWorker.fetch(
"http://example.com/scheduled"
);
await expect(auxiliaryResponse.text()).resolves.toBe("*/5 * * * *");
});
});
17 changes: 17 additions & 0 deletions fixtures/create-server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"isolatedModules": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "bundler",
"resolveJsonModule": true,
"target": "esnext",
"strict": true,
"noEmit": true,
"types": ["@cloudflare/workers-types", "node"],
"lib": ["esnext"],
"skipLibCheck": true
},
"include": ["**/*.ts"],
"exclude": ["tests"]
}
9 changes: 9 additions & 0 deletions fixtures/create-server/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "http://turbo.build/schema.json",
"extends": ["//"],
"tasks": {
"build": {
"outputs": ["dist/**"]
}
}
}
13 changes: 13 additions & 0 deletions fixtures/create-server/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { cloudflare } from "@cloudflare/vite-plugin";
import { defineConfig } from "vite";

export default defineConfig({
plugins: [
cloudflare({
configPath: "./wrangler.primary.jsonc",
auxiliaryWorkers: [{ configPath: "./wrangler.auxiliary.jsonc" }],
inspectorPort: false,
persistState: false,
}),
],
});
Loading
Loading