Before we move forward, I wanted to mention that the complete code for this tutorial is available on Github. You can use it to follow the article more clearly, and you are more than welcome to comment / fork / etc...
The Worker code is quite simple. It implements an API accepting query string parameters, performing simple math (addition, subtraction, multiplication and division) and finally returning an outcome in JSON format.
Our objective is to improve and automate our test coverage, both from a functional standpoint and an end-to-end perspective.
My favourite is Jest: it's a lightweight and expressive framework which allows me to write concise and readable tests. It is also straightforward to plug into the build pipeline.
If you use npm, here is how you install it:
npm install --save-dev jest
Then, we can modify our package.json to include the following configuration:
With this, I defined the test script which will run jest and the test suites that have been added to my project. We will look at these in more detail later. The --coverage flag will tell Jest to check how much of our code is covered by a test.
With the collectCoverageFrom option, we tell Jest which files we want to measure coverage on. In my project, index.js is the main Worker script and the src folder contains what I factored out, to make testing a bit easier.
Let's now have a look at the tests. For example, I have a maths.test.js (link) which defines the tests for my maths.js (link) object. Here is an excerpt:
The above tests are ensuring that the basic business logic is correct. Once we have completed them, we can run npm run tests to verify that the outcome is the desired one. Here is some sample output from another project of mine:
In the summary, we can see if the tests were successful, and if not it will highlight which assertions have not been met. It will also give us an idea of how much code is being covered with our testing scripts.
Building & Testing pipeline
Once we have added our tests, we can start plugging our project into a CI tool. For open-source projects, we can use Travis. You can follow the full setup documentation here: to begin with, sign up and provide the appropriate authorizations for the repository of interest.
Once this has been done, you can add a .travis.yml configuration file to the root of the repository. Here is my example (link)
The configuration instructs Travis on the steps to take to prepare the build, before running the tests, and what to do if the outcome is successful. For a complete explanation, I recommend again the official documentation.
Testing the worker end to end
Great, we have seen how to add functional test for our code, and how to automate the build and test process for our Cloudflare Worker. Something is missing still: we are not yet testing our worker code end to end.
Cloudflare provides Wrangler as a CLI tool to manage and interact with Workers for development, testing and deployment. Not too long ago, wrangler dev was released, facilitating local testing. The developer can fire up wrangler dev and send test requests to localhost, while Wrangler takes care of deploying the test code on the nearest Cloudflare data centre and sending your local requests there, for a high fidelity test environment.
What if we could automate this with Jest, and add some integration tests to our Jest test suites? In the next section, we will see an approach that I am experimenting with, still with some quirks!
🚨 Important: this setup is still experimental. As the wrangler cli itself explains in its output log:
wrangler dev is currently unstable and there are likely to be breaking changes! For this reason, we cannot yet recommend using wrangler dev for integration testing.
Keep this in mind while experimenting!
 Write Jest test suite for integrated test
First of all, in addition to our functional tests, we will add a test suite firing HTTP calls to our Worker and validate each outcome. To implement this, I used the node-fetch package and wrote my test suite (link):
The tests make HTTP calls to the local endpoint available at 127.0.0.1:8787. This is where wrangler dev will expose the test environment. We can then verify directly the responses produced by our Worker and make assertions on their contents.
 Add wrangler dev to the 'test' script and coordinate
The next step is to ensure that wrangler dev is up and running before we start our tests. The idea is to use the Travis configuration to prepare and coordinate for this.
The first part is achieved in our .travis.yml file (as seen above)
In particular, in the before_install section, we tell Travis to install Wrangler so it's available for later use.
Let's now go back to the test script line that I have in my package.json (link)
"test": "concurrently --success first --kill-others \"wrangler dev \" \"wait-on -d 3000 -t 30000 http-get://localhost:8787 && jest --coverage\""
A few things are happening:
I am using concurrently, a Node tool which allows running multiple commands in parallel. In our case, we want to run wrangler dev and also our jest testing command so that we can execute our tests at the appropriate time.
As you can imagine, running things in parallel immediately calls for coordination😅. For that, I am using another utility called wait-on which allows me to "align the stars" before running my tests.
Looking more closely at the wait-on parameters, I am defining a delay -d of 3 seconds before starting my readiness check. The check fires an HTTP GET call to localhost:8787 and expects an HTTP 200 response back. It will continue to perform this check for at most 30 seconds, before giving up.
We use concurrently to spawn wrangler dev and wait-on
wrangler dev will attempt to deploy a test worker and also expose an HTTP endpoint locally on port 8787, ready to accept incoming test requests.
In the meantime, wait-on will wait 3 seconds and then will start making HTTP GET local requests on port 8787, expecting an HTTP 200 code back.
Once wrangler has started up, the check will succeed and wait-on will terminate, at which point we will launch jest --coverage
jest --coverage runs the functional and integrated tests for our Worker
✅If the tests are positive, jest will exit with a success code. Because we told concurrently to wait for the first success code and then also terminate successfully, the overall result will be positive.
❌ If the tests are negative, jest will exit with a failure code, which will ultimately cause the test command to also fail.
As a further step, we could also use Travis and Wrangler to deploy our code in case of success, and notify in case of failure. We will keep this for a future iteration.
From my perspective, this method works 100% of the time when I try it locally. The coordination kicks in and we run our tests only when wrangler dev has done its things and is ready to accept test requests:
If I force some of the tests to fail, I also obtain the expected outcome. Below, I am absolutely adamant that 6 * 5 = 300 and Jest faithfully obliges to my wishes 😀
This approach also works fine in Travis, meaning I can fully automate the testing of my serverless Cloudflare Worker.
What do you think? Have you tried to achieve this in another way? Let me know in the comments!