Skip to content

Commit

Permalink
refactor: remove process.exit() from the pages code (#747)
Browse files Browse the repository at this point in the history
This enables simpler testing, as we do not have to spawn new child processes
to avoid the `process.exit()` from killing the jest process.

As part of the refactor, some of the `Error` classes have been moved to a
shared `errors.ts` file.
  • Loading branch information
petebacondarwin authored Apr 2, 2022
1 parent 3e25dcb commit db6b830
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 75 deletions.
11 changes: 11 additions & 0 deletions .changeset/polite-lemons-shop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"wrangler": patch
---

refactor: remove `process.exit()` from the pages code

This enables simpler testing, as we do not have to spawn new child processes
to avoid the `process.exit()` from killing the jest process.

As part of the refactor, some of the `Error` classes have been moved to a
shared `errors.ts` file.
8 changes: 7 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"pgrep",
"PKCE",
"Positionals",
"scandir",
"selfsigned",
"textfile",
"tsbuildinfo",
Expand All @@ -28,7 +29,12 @@
"websockets",
"xxhash"
],
"cSpell.ignoreWords": ["TESTTEXTBLOBNAME", "TESTWASMNAME", "yxxx"],
"cSpell.ignoreWords": [
"TESTTEXTBLOBNAME",
"TESTWASMNAME",
"extensionless",
"yxxx"
],
"eslint.runtime": "node",
"files.trimTrailingWhitespace": true
}
8 changes: 4 additions & 4 deletions packages/wrangler/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -845,14 +845,14 @@ describe("wrangler", () => {
it("should throw an error if the deprecated command is used with positional arguments", async () => {
await expect(runWrangler("preview GET")).rejects
.toThrowErrorMatchingInlineSnapshot(`
"DEPRECATION WARNING:
"DEPRECATION:
The \`wrangler preview\` command has been deprecated.
Try using \`wrangler dev\` to to try out a worker during development.
"
`);
await expect(runWrangler(`preview GET "SomeBody"`)).rejects
.toThrowErrorMatchingInlineSnapshot(`
"DEPRECATION WARNING:
"DEPRECATION:
The \`wrangler preview\` command has been deprecated.
Try using \`wrangler dev\` to to try out a worker during development.
"
Expand Down Expand Up @@ -970,15 +970,15 @@ describe("wrangler", () => {
it("should print a deprecation message for 'generate'", async () => {
await runWrangler("generate").catch((err) => {
expect(err.message).toMatchInlineSnapshot(`
"DEPRECATION WARNING:
"DEPRECATION:
\`wrangler generate\` has been deprecated, please refer to https://github.com/cloudflare/wrangler2/blob/main/docs/deprecations.md#generate for alternatives"
`);
});
});
it("should print a deprecation message for 'build'", async () => {
await runWrangler("build").catch((err) => {
expect(err.message).toMatchInlineSnapshot(`
"DEPRECATION WARNING:
"DEPRECATION:
\`wrangler build\` has been deprecated, please refer to https://github.com/cloudflare/wrangler2/blob/main/docs/deprecations.md#build for alternatives"
`);
});
Expand Down
66 changes: 21 additions & 45 deletions packages/wrangler/src/__tests__/pages.test.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,9 @@
import { execaSync } from "execa";
import { getPackageManager } from "../package-manager";
import { mockConsoleMethods } from "./helpers/mock-console";
import { runInTempDir } from "./helpers/run-in-tmp";
import { runWrangler } from "./helpers/run-wrangler";
import type { PackageManager } from "../package-manager";

describe("subcommand implicit help ran on imcomplete command execution", () => {
let mockPackageManager: PackageManager;
describe("subcommand implicit help ran on incomplete command execution", () => {
runInTempDir();

beforeEach(() => {
mockPackageManager = {
cwd: process.cwd(),
// @ts-expect-error we're making a fake package manager here
type: "mockpm",
addDevDeps: jest.fn(),
install: jest.fn(),
};
(getPackageManager as jest.Mock).mockResolvedValue(mockPackageManager);
});

const std = mockConsoleMethods();
function endEventLoop() {
return new Promise((resolve) => setImmediate(resolve));
Expand All @@ -46,36 +30,28 @@ describe("subcommand implicit help ran on imcomplete command execution", () => {
🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"
`);
});
});

describe("beta message for subcommands", () => {
const betaMsg =
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose";
const isWindows = process.platform === "win32";
it("should display for pages:dev", async () => {
let err: Error | undefined;
try {
execaSync("npx", ["wrangler", "pages", "dev"], {
shell: isWindows,
env: { BROWSER: "none", ...process.env },
}).stderr;
} catch (e: unknown) {
err = e as Error;
}
expect(err?.message.includes(betaMsg)).toBe(true);
});
describe("beta message for subcommands", () => {
it("should display for pages:dev", async () => {
await expect(
runWrangler("pages dev")
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Must specify a directory of static assets to serve or a command to run."`
);

expect(std.out).toMatchInlineSnapshot(
`"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"`
);
});

// Note that `wrangler pages functions` does nothing...

it("should display for pages:functions", async () => {
let err: Error | undefined;
try {
execaSync("npx", ["wrangler", "pages", "functions", "build"], {
shell: isWindows,
env: { BROWSER: "none", ...process.env },
});
} catch (e: unknown) {
err = e as Error;
}
it("should display for pages:functions:build", async () => {
await expect(runWrangler("pages functions build")).rejects.toThrowError();

expect(err?.message.includes(betaMsg)).toBe(true);
expect(std.out).toMatchInlineSnapshot(
`"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"`
);
});
});
});
8 changes: 4 additions & 4 deletions packages/wrangler/src/__tests__/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe("wrangler route", () => {
it("shows a deprecation notice when `wrangler route` is run", async () => {
await expect(runWrangler("route")).rejects
.toThrowErrorMatchingInlineSnapshot(`
"DEPRECATION WARNING:
"DEPRECATION:
\`wrangler route\` has been deprecated.
Please use wrangler.toml and/or \`wrangler publish --routes\` to modify routes"
`);
Expand All @@ -18,7 +18,7 @@ describe("wrangler route", () => {
it("shows a deprecation notice when `wrangler route delete` is run", async () => {
await expect(runWrangler("route delete")).rejects
.toThrowErrorMatchingInlineSnapshot(`
"DEPRECATION WARNING:
"DEPRECATION:
\`wrangler route delete\` has been deprecated.
Remove the unwanted route(s) from wrangler.toml and run \`wrangler publish\` to remove your worker from those routes."
`);
Expand All @@ -27,7 +27,7 @@ describe("wrangler route", () => {
it("shows a deprecation notice when `wrangler route delete <id>` is run", async () => {
await expect(runWrangler("route delete some-zone-id")).rejects
.toThrowErrorMatchingInlineSnapshot(`
"DEPRECATION WARNING:
"DEPRECATION:
\`wrangler route delete\` has been deprecated.
Remove the unwanted route(s) from wrangler.toml and run \`wrangler publish\` to remove your worker from those routes."
`);
Expand All @@ -36,7 +36,7 @@ describe("wrangler route", () => {
it("shows a deprecation notice when `wrangler route list` is run", async () => {
await expect(runWrangler("route list")).rejects
.toThrowErrorMatchingInlineSnapshot(`
"DEPRECATION WARNING:
"DEPRECATION:
\`wrangler route list\` has been deprecated.
Refer to wrangler.toml for a list of routes the worker will be deployed to upon publishing.
Refer to the Cloudflare Dashboard to see the routes this worker is currently running on."
Expand Down
6 changes: 4 additions & 2 deletions packages/wrangler/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import process from "process";
import { hideBin } from "yargs/helpers";
import { FatalError } from "./errors";
import { reportError, initReporting } from "./reporting";
import { main } from ".";

Expand All @@ -11,9 +12,10 @@ process.on("uncaughtExceptionMonitor", async (err, origin) => {
await reportError(err, origin);
});

main(hideBin(process.argv)).catch(() => {
main(hideBin(process.argv)).catch((e) => {
// The logging of any error that was thrown from `main()` is handled in the `yargs.fail()` handler.
// Here we just want to ensure that the process exits with a non-zero code.
// We don't want to do this inside the `main()` function, since that would kill the process when running our tests.
process.exit(1);
const exitCode = (e instanceof FatalError && e.code) || 1;
process.exit(exitCode);
});
11 changes: 11 additions & 0 deletions packages/wrangler/src/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export class DeprecationError extends Error {
constructor(message: string) {
super(`DEPRECATION:\n${message}`);
}
}

export class FatalError extends Error {
constructor(message?: string, readonly code?: number) {
super(message);
}
}
6 changes: 1 addition & 5 deletions packages/wrangler/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { createWorkerUploadForm } from "./create-worker-upload-form";
import Dev from "./dev/dev";
import { confirm, prompt } from "./dialogs";
import { getEntry } from "./entry";
import { DeprecationError } from "./errors";
import {
getNamespaceId,
listNamespaces,
Expand Down Expand Up @@ -211,11 +212,6 @@ function demandOneOfOption(...options: string[]) {
}

class CommandLineArgsError extends Error {}
class DeprecationError extends Error {
constructor(message: string) {
super(`DEPRECATION WARNING:\n${message}`);
}
}

export async function main(argv: string[]): Promise<void> {
const wrangler = makeCLI(argv)
Expand Down
36 changes: 22 additions & 14 deletions packages/wrangler/src/pages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { getType } from "mime";
import { buildWorker } from "../pages/functions/buildWorker";
import { generateConfigFromFileTree } from "../pages/functions/filepath-routing";
import { writeRoutesModule } from "../pages/functions/routes";
import { FatalError } from "./errors";
import openInBrowser from "./open-in-browser";
import { toUrlPath } from "./paths";
import type { Config } from "../pages/functions/routes";
Expand All @@ -25,17 +26,20 @@ import type { BuilderCallback } from "yargs";
export const pagesBetaWarning =
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose";

const EXIT_CALLBACKS: (() => void)[] = [];
const EXIT = (message?: string, code?: number) => {
if (message) console.log(message);
if (code) process.exitCode = code;
EXIT_CALLBACKS.forEach((callback) => callback());
const CLEANUP_CALLBACKS: (() => void)[] = [];
const CLEANUP = () => {
CLEANUP_CALLBACKS.forEach((callback) => callback());
RUNNING_BUILDERS.forEach((builder) => builder.stop?.());
process.exit(code);
};

process.on("SIGINT", () => EXIT());
process.on("SIGTERM", () => EXIT());
process.on("SIGINT", () => {
CLEANUP();
process.exit();
});
process.on("SIGTERM", () => {
CLEANUP();
process.exit();
});

function isWindows() {
return process.platform === "win32";
Expand Down Expand Up @@ -108,11 +112,13 @@ async function spawnProxyProcess({
port?: number;
command: (string | number)[];
}): Promise<void | number> {
if (command.length === 0)
return EXIT(
if (command.length === 0) {
CLEANUP();
throw new FatalError(
"Must specify a directory of static assets to serve or a command to run.",
1
);
}

console.log(`Running ${command.join(" ")}...`);
const proxy = spawn(
Expand All @@ -126,7 +132,7 @@ async function spawnProxyProcess({
},
}
);
EXIT_CALLBACKS.push(() => {
CLEANUP_CALLBACKS.push(() => {
proxy.kill();
});

Expand Down Expand Up @@ -157,7 +163,8 @@ async function spawnProxyProcess({
.filter((port) => port !== undefined)[0];

if (port === undefined) {
return EXIT(
CLEANUP();
throw new FatalError(
"Could not automatically determine proxy port. Please specify the proxy port with --proxy.",
1
);
Expand Down Expand Up @@ -970,13 +977,14 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
});
}

EXIT_CALLBACKS.push(() => {
CLEANUP_CALLBACKS.push(() => {
server.close();
miniflare.dispose().catch((err) => miniflare.log.error(err));
});
} catch (e) {
miniflare.log.error(e as Error);
EXIT("Could not start Miniflare.", 1);
CLEANUP();
throw new FatalError("Could not start Miniflare.", 1);
}
}
)
Expand Down

0 comments on commit db6b830

Please sign in to comment.