Skip to content

Commit 385668d

Browse files
authored
Add generic handler tests using framework (#30)
1 parent a010a8a commit 385668d

File tree

9 files changed

+450
-32
lines changed

9 files changed

+450
-32
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"pb:version": "genversion --semi --double --es6 ./src/version.ts",
2020
"pb:landing": "yarn build:landing && node -e 'const page = JSON.stringify(require(\"fs\").readFileSync(\"./landing/dist/index.html\").toString()); console.log(\"export const landing = \" + page);' > ./src/landing.ts && npx prettier ./src/landing.ts --write",
2121
"build": "yarn run clean && tsc --project tsconfig.build.json",
22-
"test": "jest --passWithNoTests",
22+
"test": "node --expose-gc --max-old-space-size=4096 ./node_modules/.bin/jest --silent --logHeapUsage --maxWorkers=8",
2323
"clean": "rm -rf ./dist",
2424
"lint": "eslint .",
2525
"postversion": "yarn run build && yarn run build:copy",
@@ -71,6 +71,7 @@
7171
"genversion": "^3.1.1",
7272
"jest": "27.5.1",
7373
"next": "^12.3.0",
74+
"nock": "^13.2.9",
7475
"node-mocks-http": "^1.11.0",
7576
"nodemon": "^2.0.20",
7677
"np": "^7.6.1",

src/cloudflare.test.ts

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,89 @@
1+
import fetch, { Headers, Response } from "cross-fetch";
12
import * as CloudflareHandler from "./cloudflare";
23
import { testFramework } from "./test/helpers";
34

45
const originalProcess = process;
6+
const originalFetch = globalThis.fetch;
7+
const originalResponse = globalThis.Response;
8+
const originalHeaders = globalThis.Headers;
59

610
testFramework("Cloudflare", CloudflareHandler, {
711
lifecycleChanges: () => {
812
beforeEach(() => {
913
jest.resetModules();
10-
process = undefined as unknown as NodeJS.Process;
14+
15+
/**
16+
* Fake lack of any `process` global var; Cloudflare allows access to env
17+
* vars by passing them in to the request handler.
18+
*
19+
* Because of some test components (mainly `debug`) that use
20+
* `process.stderr`, we do need to provide some pieces of this, but we can
21+
* still remove any env vars.
22+
*/
23+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
24+
process.env = undefined as any;
25+
26+
/**
27+
* Fake a global `fetch` value, which is available as the Cloudflare
28+
* handler will use the global DOM `fetch`.
29+
*/
30+
globalThis.fetch = fetch;
31+
32+
/**
33+
* Fake a global `Response` class, which is used to create new responses
34+
* for the handler.
35+
*/
36+
globalThis.Response = Response;
37+
38+
/**
39+
* Fake a global `Headers` class, which is used to create new Headers
40+
* objects during response building.
41+
*/
42+
globalThis.Headers = Headers;
1143
});
1244

1345
afterEach(() => {
14-
process = originalProcess;
46+
/**
47+
* Reset all changes made to the global scope
48+
*/
49+
process.env = originalProcess.env;
50+
globalThis.fetch = originalFetch;
51+
globalThis.Response = originalResponse;
52+
globalThis.Headers = originalHeaders;
53+
});
54+
},
55+
transformReq: (req, res, env) => {
56+
const headers = new Headers();
57+
Object.entries(req.headers).forEach(([k, v]) => {
58+
headers.set(k, v as string);
1559
});
60+
61+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
62+
(req as any).headers = headers;
63+
64+
return [
65+
{
66+
request: req,
67+
env,
68+
},
69+
];
70+
},
71+
transformRes: async (res, ret: Response) => {
72+
const headers: Record<string, string> = {};
73+
74+
ret.headers.forEach((v, k) => {
75+
headers[k] = v;
76+
});
77+
78+
return {
79+
status: ret.status,
80+
body: await ret.text(),
81+
headers,
82+
};
1683
},
1784
envTests: () => {
1885
test("process should be undefined", () => {
19-
expect(process).toBeUndefined();
86+
expect(process.env).toBeUndefined();
2087
});
2188
},
2289
handlerTests: () => {

src/components/Inngest.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { envKeys } from "../helpers/consts";
22
import { devServerAvailable, devServerUrl } from "../helpers/devserver";
3-
import { devServerHost, isProd } from "../helpers/env";
3+
import { devServerHost, hasProcessEnv, isProd } from "../helpers/env";
44
import type {
55
PartialK,
66
SendEventPayload,
@@ -107,10 +107,7 @@ export class Inngest<Events extends Record<string, EventPayload>> {
107107
this.name = name;
108108

109109
this.eventKey =
110-
eventKey ||
111-
(typeof process === "undefined"
112-
? ""
113-
: process.env[envKeys.EventKey] || "");
110+
eventKey || (hasProcessEnv() ? process.env[envKeys.EventKey] || "" : "");
114111

115112
this.inngestBaseUrl = new URL(inngestBaseUrl);
116113
this.inngestApiUrl = new URL(`e/${this.eventKey}`, this.inngestBaseUrl);
@@ -271,7 +268,7 @@ export class Inngest<Events extends Record<string, EventPayload>> {
271268
// If the dev server host env var has been set we always want to use
272269
// the dev server - even if it's down. Otherwise, optimistically use
273270
// it for non-prod services.
274-
if (host !== undefined || await devServerAvailable(host, fetch)) {
271+
if (host !== undefined || (await devServerAvailable(host, fetch))) {
275272
url = devServerUrl(host, `e/${this.eventKey}`).href;
276273
}
277274
}

src/express.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ describe("InngestCommHandler", () => {
4545
{ event: "test/event.name" },
4646
{ step: new InngestStep(() => undefined) }
4747
);
48-
const ch = new InngestCommHandler("test-1", [fn], {});
48+
const ch = new InngestCommHandler("test-1", [fn], { landingPage: true });
4949
const handler = ch.createHandler() as RequestHandler;
5050
// Matches a real-world request using an express app
5151
const req: Request = httpMocks.createRequest({

src/helpers/env.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,25 @@ export const devServerHost = (): string | undefined => {
2020
// processed using webpack's DefinePlugin, which is dumb and does a straight
2121
// text replacement instead of actually understanding the AST, despite webpack
2222
// being fully capable of understanding the AST.
23-
const values =
24-
typeof process === "undefined"
25-
? []
26-
: [
27-
process.env.INNGEST_DEVSERVER_URL,
28-
process.env.REACT_APP_INNGEST_DEVSERVER_URL,
29-
process.env.NEXT_PUBLIC_INNGEST_DEVSERVER_URL,
30-
];
23+
const values = hasProcessEnv()
24+
? [
25+
process.env.INNGEST_DEVSERVER_URL,
26+
process.env.REACT_APP_INNGEST_DEVSERVER_URL,
27+
process.env.NEXT_PUBLIC_INNGEST_DEVSERVER_URL,
28+
]
29+
: [];
3130

3231
return values.find((a) => !!a);
3332
};
3433

3534
export const isProd = (): boolean => {
36-
const values =
37-
typeof process === "undefined"
38-
? []
39-
: [process.env.NODE_ENV, process.env.VERCEL_ENV, process.env.CONTEXT];
35+
const values = hasProcessEnv()
36+
? [process.env.NODE_ENV, process.env.VERCEL_ENV, process.env.CONTEXT]
37+
: [];
4038

4139
return values.includes("production");
4240
};
41+
42+
export const hasProcessEnv = (): boolean => {
43+
return typeof process !== "undefined" && "env" in process;
44+
};

src/remix.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,30 @@
1+
import { Headers } from "cross-fetch";
12
import * as RemixHandler from "./remix";
23
import { testFramework } from "./test/helpers";
34

4-
testFramework("Remix", RemixHandler);
5+
testFramework("Remix", RemixHandler, {
6+
transformReq: (req) => {
7+
const headers = new Headers();
8+
Object.entries(req.headers).forEach(([k, v]) => {
9+
headers.set(k, v as string);
10+
});
11+
12+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
13+
(req as any).headers = headers;
14+
15+
return [{ request: req }];
16+
},
17+
transformRes: async (res, ret: Response) => {
18+
const headers: Record<string, string> = {};
19+
20+
ret.headers.forEach((v, k) => {
21+
headers[k] = v;
22+
});
23+
24+
return {
25+
status: ret.status,
26+
body: await ret.text(),
27+
headers,
28+
};
29+
},
30+
});

src/remix.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class RemixCommHandler extends InngestCommHandler {
6666

6767
return new Response(JSON.stringify(introspection), {
6868
status: 200,
69+
headers,
6970
});
7071
}
7172

0 commit comments

Comments
 (0)