Skip to content

Commit dc33dff

Browse files
authored
feat(TestWorkers): Ability to Unit Test Workers (#23)
* feat(TestWorker): Add the ability to unit test a worker * doc(TestWorker): Adding documentation on unit testing workers
1 parent fe1f199 commit dc33dff

File tree

8 files changed

+95
-2
lines changed

8 files changed

+95
-2
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# cloudflare-worker-local
2-
WIP: Run a Cloudflare Worker Locally
2+
Run (or test) a Cloudflare Worker Locally
33

44
## Running
55

@@ -19,6 +19,10 @@ $ npm install -g nodemon
1919
$ nodemon --watch /path/to/worker.js --signal SIGHUP --exec 'cloudflare-worker-local /path/to/worker.js localhost:3000 4000'
2020
```
2121

22+
## Unit Testing a Cloudflare Worker
23+
24+
`cloudflare-worker-local` can be used to unit test a cloudflare worker. Please see [This Example](examples/unit-test-a-worker)
25+
2226
## Things that are supported (and in scope)
2327

2428
* Anything in Node.js scope by default (Object, Array)

app/__tests__/test-app_spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const { createTestApp } = require("../test-app");
2+
const express = require("express");
3+
const supertest = require("supertest");
4+
5+
describe("server", () => {
6+
it("returns the response from the worker", async () => {
7+
const upstreamApp = express();
8+
upstreamApp.get("/some-route", (req, res) => res.end("hello"));
9+
const app = createTestApp('addEventListener("fetch", (e) => e.respondWith(fetch(e.request)))', upstreamApp);
10+
11+
await supertest(app)
12+
.get("/some-route")
13+
.expect(200, "hello");
14+
});
15+
});

app/server.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ function createApp(workerContent, opts) {
4343
workerContent = contents;
4444
workersByOrigin = {};
4545
};
46+
app.updateOpts = newOpts => {
47+
opts = Object.assign({}, opts, newOpts);
48+
workersByOrigin = {};
49+
};
4650

4751
return app;
4852
}

app/test-app.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const { createApp } = require("./server");
2+
const http = require("http");
3+
4+
function createTestApp(workerContent, upstreamApp, opts = {}) {
5+
const app = createApp(workerContent, opts);
6+
const server = http.createServer(app);
7+
const upstreamServer = http.createServer(upstreamApp);
8+
9+
server.listen = function() {
10+
upstreamServer.listen(0);
11+
app.updateOpts({ upstreamHost: `127.0.0.1:${upstreamServer.address().port}` });
12+
return http.Server.prototype.listen.apply(this, arguments);
13+
};
14+
15+
server.close = function() {
16+
upstreamServer.close();
17+
return http.Server.prototype.close.apply(this, arguments);
18+
};
19+
20+
return server;
21+
}
22+
23+
module.exports = { createTestApp };
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const { createTestApp } = require("cloudflare-worker-local");
2+
const supertest = require("supertest");
3+
const express = require("express");
4+
const fs = require("fs");
5+
6+
const workerContent = fs.readFileSync(`${__dirname}/../worker.js`);
7+
8+
describe("My New Worker", () => {
9+
it("Adds a header on 200 responses", async () => {
10+
const upstreamApp = express();
11+
upstreamApp.get("/route", (req, res) => res.end("Success"));
12+
await supertest(createTestApp(workerContent, upstreamApp))
13+
.get("/route")
14+
.expect("Foo", "Bar")
15+
.expect(200, "Success");
16+
});
17+
18+
it("Adds a different header on 404", async () => {
19+
// all routes are 404
20+
const upstreamApp = express();
21+
22+
await supertest(createTestApp(workerContent, upstreamApp))
23+
.get("/route")
24+
.expect("Foo", "Not Bar")
25+
.expect(404);
26+
});
27+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
addEventListener("fetch", e => {
2+
e.respondWith(fetchAndAddHeader(e.request));
3+
});
4+
5+
async function fetchAndAddHeader(request) {
6+
const response = await fetch(request);
7+
8+
if (response.status === 200) {
9+
response.headers.set("Foo", "Bar");
10+
} else {
11+
response.headers.set("Foo", "Not Bar");
12+
}
13+
14+
return response;
15+
}

index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
const { createApp } = require("./app/server");
22
const { Worker } = require("./app/worker");
3+
const { createTestApp } = require("./app/test-app");
34

45
module.exports = {
56
Worker,
6-
createApp
7+
createApp,
8+
createTestApp
79
};

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,8 @@
3737
},
3838
"bin": {
3939
"cloudflare-worker-local": "./cli.js"
40+
},
41+
"jest": {
42+
"testPathIgnorePatterns": ["/node_modules/", "/examples"]
4043
}
4144
}

0 commit comments

Comments
 (0)