If you were not aware, Cloudflare Workers lets you run Javascript in all 165+ of our Data Centers. We’re delighted to see some of the creative applications of Workers. As the use cases grow in complexity, the need to smoke test your code also grows.
More specifically, if your Worker includes a number of functions, it’s important to ensure each function does what it’s intended to do in addition to ensuring the output of the entire Worker returns as expected.
In this post, we’re going to demonstrate how to unit test Cloudflare Workers, and their individual functions, with Cloudworker, created by the Dollar Shave Club engineering team.
Dollar Shave Club is a Cloudflare customer, and they created Cloudworker, a mock for the Workers runtime, for testing purposes. We’re really grateful to them for this. They were kind enough to post on our blog about it.
This post will demonstrate how to abstract away Cloudworker, and test Workers with the same syntax you write them in.
Example Script
Before we get into configuring Cloudworker, let’s introduce the simple script we are going to test against in our example. As you can see this script contains two functions, both of which contribute to the response to the client.
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function addition(a, b) {
return a + b
}
async function handleRequest(request) {
const added = await addition(1,3)
return new Response(`The Sum is ${added}!`)
}
This script will be active for the route worker.example.com
.
Directory Set Up
After I’ve created a new npm ( npm init
) project in a new directory, I placed my worker.js
file inside, containing the above, and created the folder test
which contains worker-test.js
. The structure is laid out below.
.
----- worker.js
----- test
. worker-test.js
----- node_modules
----- package.json
----- package-lock.json.
Next I need to install Cloudworker ( npm install @dollarshaveclub/cloudworker --save-dev
) and the Mocha testing framework ( npm install mocha --save-dev
) if you do not have it installed globally. Make sure that package.json
reflects a value of mocha
for tests
, like:
"scripts": {
"test": "mocha"
}
Now we can finally write some tests! Luckily, mocha
has async/await
support which is going to make this very simple. The idea is straightforward: Cloudworker allows you to place a Worker in development in front of an HTTP request and inspect the response.
Writing Tests!
Before any test logic, we’ll place two lines at the top of the test file ( worker-test.js
). The first line assigns all property values from Cloudworker and our Worker script to the global context before every async function()
is run in mocha. The second line requires assert
, which is commonly used to compare an expected output to a mocked output.
before(async function () {
Object.assign(global, new (require('@dollarshaveclub/cloudworker'))(require('fs').readFileSync('worker.js', ‘utf8’)).context);
});
// You will replace worker.js with the relative path to your worker
const assert = require('assert')
Now, testing looks a lot more like a Worker itself as we access to all the underlying functions used by Cloudworker AND the Worker script.
describe('Worker Test', function() {
it('returns a body that says The Sum is 4', async function () {
let url = new URL('https://worker.example.com')
let req = new Request(url)
let res = await handleRequest(req)
let body = await res.text()
assert.equal(body, 'The Sum is 4!')
})
it('does addition properly', async function() {
let res = await addition(1, 1)
assert.equal(res, 2)
})
})
We can test individual functions with our Worker this way, as shown above with the addition()
function call. This is really powerful and allows for more confidence when deploying complex workers as you can test each component that makes up the script. We hope this was useful and welcome any feedback.