Testing is hard and this is why you should do it: learn how to test a simple Koa 2 API with Mocha, Chai, and Chai HTTP. Code included! Building something with Javascript is relatively easy. Take a look and you’ll see an uninterrupted stream of articles and tutorials. here But… how many of them covers Test Driven Development with Javascript? Few. Mine included. Testing is hard and more often than not I find myself writing code without even having a test case. Intrigued by Koa 2, I’ve started to play with it lately to build an API. And I liked it, especially when you start to see all those green marks after typing . So, what follows is an introduction to building a RESTful API with Koa 2, Mocha and Chai, by following the TDD principles. npm test Koa 2, Mocha, and Chai in action The concept is simple: we’ll build a simple API for displaying and storing a collection of blog articles, code and tests included! What you will learn How to start building a RESTful APIs with Koa 2 The basics of Test Driven Development with Mocha, Chai, and Chai HTTP Disclaimer The following guide provides some basic examples. It does not cover every possible use case but will give you a good starting point either way. Also, keep in mind that the code in this tutorial is not suitable for production. Use it at your own risk. Its purpose is to show you the basics. Don’t copy/paste the examples without having a solid understanding about what the code is supposed to do. Requirements In order to follow along with this tutorial you should have a basic understanding of Javascript, Node.js, and ES6. The latest version of Node.js is available from the . official website If you use Linux, you should absolutely check out . Nodesource Also, make sure to have at least Node v7.6.0 or higher. In the following examples I’ll make large use of the pattern. async/await Scaffolding the project To start the project, create an empty directory named : koa-tdd-api mkdir koa-tdd-api then move inside the newly created directory: cd koa-tdd-api and initialize by running: package.json npm init We won’t publish any module to NPM so you can safely accept the default choices and just move on. We also need to create some directory structure. In your terminal type: mkdir -p server/{routes,db,controllers} test and hit enter. Setting up Knex and the database That’s a boring task but someone has to do it: setting up the database and all the likes. Our tools of choice will be: Sqlite3: it’s enough to get started for a testing/development environment and it offers almost instant feedback : it’s a SQL query builder for Javascript. To keep things simple I won’t use any ORM in this tutorial but you should take a look at right after finishing this project. Knex Sequelize Before doing anything else install the with: Sqlite3 adapter npm i sqlite3@3.1.8 --save-dev The reason why I picked version 3.1.8 is because of . I hope it will fixed soon. this issue Right after that add Knex with: npm i knex Knex comes included with a command line tool for managing both migrations and seeding. The Knex CLI can also be used to initialize the Knex configuration file. Run in your terminal: node_modules/knex/bin/cli.js init and you should see the following output: Created ./knexfile.js This file will hold the database credentials for every environment. You can also specify where your migrations and seeds should be generated. Open up and update the configuration by replacing the defaults with the following: knexfile.js <a href="https://medium.com/media/d95fb78b66e997043717c906f94e0d5f/href">https://medium.com/media/d95fb78b66e997043717c906f94e0d5f/href</a> Of course you’re free to load in other environments such as “dev” or “prod”, anyway for the scope of this tutorial I’ll stick just with a “test” environment. At this point you can safely generate your first migration with: node_modules/knex/bin/cli.js migrate:make articles --env test A new migration will be created inside . Open up the newly created file and update the defaults with the following code: server/db/migrations/ <a href="https://medium.com/media/2a592fde391d40273774b656c994896c/href">https://medium.com/media/2a592fde391d40273774b656c994896c/href</a> The above code defines a new table named . Every article will be composed of a title, a body and some tags. articles Save and close the file, then commit the migration with: node_modules/knex/bin/cli.js migrate:latest --env test A new file, will appear inside your project directory. It’s the test database. Eager to see what’s inside? You can browse it with even if it’ll be most likely empty right now. Time to load some data! test.sqlite3 sqlitebrowser Seeding the database for testing Right now the database is empty. We need some kind of data which will be used by the testing suite during its execution. Knex makes easy to create fake data by making use of seeds. NOTE: Seeding is not meant to be used during testing. That’s a job for fixtures and factories. Seeding is mostly used for populating an application with some data needed to allow the software to be usable as soon it starts. Knex does not have a fixtures feature, therefore we’ll use seeding either way Generate the seed file by running: node_modules/knex/bin/cli.js seed:make articles --env test and a new seed will appear inside . Open up the file and add some fake articles inside the call: server/db/seeds/articles.js insert() <a href="https://medium.com/media/af4ad2192f7a30a01a0c65834cab4959/href">https://medium.com/media/af4ad2192f7a30a01a0c65834cab4959/href</a> Now that everything is set let’s start with the serious stuff: setting up the testing suite. Test Driven Development: make it fail, one test at a time In brief, Test Driven Development is a programming style based on the repetition of a set of steps: Starting with a list of requirements, analyze the requested feature and write a simple test case Make sure the test at first: this is the . The test will fail because the feature hasn’t been implemented yet fails red phase Write just enough code, in its simplest form, to make sure the test pass: green phase Refactor the code to remove any duplicate. This is the phase refactoring can be easily implemented within Javascript. We will make use of three renowned libraries: Test Driven Development : it’s a Javascript testing framework with a lot of features. With Mocha you can organize and automate your tests easily Mocha : it’s an assertion library for Javascript. An assertion library is nothing more than a tool for verifying that your code produces the intended result. If you’re new to testing I highly recommend reading the before getting started Chai documentation : it’s a plugin for Chai. It makes easy to test APIs and web servers Chai HTTP As usual, install the dependencies with: npm i mocha chai chai-http --save-dev and you’re ready to go. Testing Koa 2 with Mocha, Chai and Chai HTTP Update the script section inside . The command should point to : package.json test mocha "scripts": { "test": "mocha" } Following the TDD principles, let’s start with a simple test case. In this first test we want to make sure that our server will respond to every against the endpoint. HTTP requests /api/v1/articles Create a new file named inside the directory: articles.routes.test.js test <a href="https://medium.com/media/2b55b651f542c687427c9dcd2884da40/href">https://medium.com/media/2b55b651f542c687427c9dcd2884da40/href</a> The first two sections of the file serve for the purpose of configuring Knex and requiring the assertion libraries: Chai and its Chai Http plugin. Next there are two calls to Knex: the first call rollbacks, commits the migration and populates the test database before each test. The second call to Knex instead makes sure that the test database gets cleaned at the end of every test case. Right after that comes the first test, starting with the block. Both and are Mocha functions. describe describe it The block helps you organizing a group of similar tests, against a specific endpoint for example. describe The block on the other hand is the actual test being declared. it By looking at the above code it should be clear also how Chai makes possible to spawn the server and subsequently making a get request: //.. chai .request(server) .get(`${PATH}`) // .. So what’s the test all about? Speaking of HTTP servers, you may want to check whether a given route responds correctly or not by: Checking if no errors exists: // ... should.not.exist(err); //... Checking if the server responds with the expected status code: res.status.should.eql(200); Checking if the server sends back valid JSON: // ... res.type.should.eql("application/json"); //... Checking if the JSON response contains the expected output: In the example below I’m asserting that the response body contains an array named , which should have a length equal to 2: data // ... res.body.data.length.should.eql(2); //... and I also want to make sure that the first element of the array contains the keys “title”, “id”, “body”, and “tags”: data // ... res.body.data[0].should.include.keys("id", "title", "body", "tags"); //... and so on. It’s worth noting that Chai supports three different assertions styles: the Should style, the Expect style and the Assert style. Picking one over another it’s a matter of personal preferences. Personally I feel the Should style more natural. With the first test case in place, it’s time to make it fail. To do so, create a new file named inside the directory and put a simple console.log() call inside it: index.js server/ <a href="https://medium.com/media/ea405f52dd7b6c58cb1565ab4f5b739c/href">https://medium.com/media/ea405f52dd7b6c58cb1565ab4f5b739c/href</a> Ready? Run the test suite with: npm test and watch the test fail: TypeError: app.address is not a function To make the test pass we should move to the green phase, or rather: write just enough code to make the test pass. Setting up the Koa server Why Koa? is a web framework for Node.js. Koa How many frameworks for Node.js exist as of today? I’ve lost the count: picking one over another is a tough choice. Lately I’ve been enjoying Koa amongst the others for two simple reasons: I’ve been using Node 8 since its release and that means I’m able to use the pattern inside Koa 2. My code feels more natural and I’m able to handle errors correctly. async/await Koa is much lighter than Express. It includes only the bare minimum by default. That means less and less code to debug memory consumption and there is a lot more. I suggest reading the documentation to discover what Koa has to offer. One of its features is the for instance. context object You will see a lot of references to the object in the upcoming examples. ctx, or context, is an object containing both the Node.js request and response objects. It is specific to Koa and provides a lot of useful methods. ctx Wiring up the server In its basic form an API would be composed of three key components, glued together. A : it’s the component responsible for listening on a given network port, forwarding all the request to the appropriate route server A set of , ie the components responsible for handling the incoming requests. This route for example: routes router.get("/api/v1/articles", articlesController.index); will handle all the requests for by asking the function to retrieve the appropriate data from the database. You should pay attention to not put too many business logic inside your routes. GET /api/v1/articles articlesController.index For example you may be tempted to write: // BAD router.get("/api/v1/articles", async ctx => { try { const articles = await knex("articles").select(); ctx.body = { data: articles }; } catch (error) { console.error(error); } }); The above code will work fine but it’s not immediately understandable as: // GOD router.get("/api/v1/articles", articlesController.index); Finally we have the : to put it simply, the controller is responsible for intepreting the request, fetching the requested data and sending an appropriate output back to the user. controller Besides some slightly variations between every web framework, those listed above are some of the main building blocks of the MVC pattern. The key difference here is that with Rails, Laravel, Phoenix and co. you get some sort of organization for free. With Javascript and Node.js you won’t have any guidance about the project structure, unless you go with or something similar. Trails With this basic theory in place let’s start by creating the server. Our goal is still to make the previous test green. Install Koa with: npm i koa open up again, remove the existing code and replace it with the following: server/index.js <a href="https://medium.com/media/cc1aac206978f48faf1307fa931155bf/href">https://medium.com/media/cc1aac206978f48faf1307fa931155bf/href</a> save and close the file, then move on to setting up the routes. Setting up the Routes and the Controller, ie making the test pass Koa does not include a router by default. Routing functionalities are provided inside the package: koa-router npm i koa-router Setting GET /api/v1/articles The first route we’ll going to create is the endpoint for . GET /api/v1/articles Create a new file named inside the directory: articles.routes.js server/routes <a href="https://medium.com/media/6fd801b47a71fb6e287af0331177a3ef/href">https://medium.com/media/6fd801b47a71fb6e287af0331177a3ef/href</a> Did you noticed how I’m requiring the inside the article route? Unlike a full MVC framework, Koa does not enforce a strict structure for your project. How the application gets organized is completely up to you so we’d better follow some conventions. articlesController A named should exists and a corresponding action named should be defined inside the controller as well. The action can be a basic Javascript function: it should fetch the resources from the database and return something meaningful to the user. controller articlesController index Start by creating the controller alongside the action inside : server/controllers/articlesController.js <a href="https://medium.com/media/90e2c7514fce2d9c7887794178f936b4/href">https://medium.com/media/90e2c7514fce2d9c7887794178f936b4/href</a> Pay attention to the above async arrow function which takes as a parameter and: ctx makes a query to the underlying Sqlite3 database by using Knex appends the data property to the response body Save and close the file: at this point we have a basic API with a single route, waiting to be tested. Run the test suite again with: npm test and watch your first test pass: Testing GET /api/v1/articles Setting up GET /api/v1/articles/:id Let’s move on by writing another failing test for the next endpoint: . This route is expected to return a single resource from the database. GET /api/v1/articles/:id Update by adding the code below: test/articles.routes.test.js <a href="https://medium.com/media/6b928b2e6035c844300338178dbfff52/href">https://medium.com/media/6b928b2e6035c844300338178dbfff52/href</a> In the above code we’re basically testing the following behaviours: the route should return a single resource the route should return an error when the requested article does not exists We’re also expecting the correct status codes to be returned from the API. Run the test suite with: npm test and watch it fail. To make the test pass you should update the routes, again. Open up and add: server/routes/articles.routes.js <a href="https://medium.com/media/692d277151519ba1437b09f140b47123/href">https://medium.com/media/692d277151519ba1437b09f140b47123/href</a> update the controller as well by adding the action inside : show server/controllers/articlesController.js <a href="https://medium.com/media/94e869cf81afd321edf5c773ed0691a3/href">https://medium.com/media/94e869cf81afd321edf5c773ed0691a3/href</a> Again, look at the above async arrow function which takes as a parameter and: ctx makes a query to the underlying Sqlite3 database by using Knex, selecting only the requested id passed via the request parameter throws an error if the requested resource does not exists appends the data property to the response body when the requested resource is present Run the test suite again with: npm test and watch the test pass: Testing GET /api/v1/articles/:id Setting up POST /api/v1/articles/ Our last test will check the behaviour of the endpoint. The route is expected to create a new resource inside the database by starting from the request body. POST /api/v1/articles/ Koa doesn’t know how to handle the body by itself, thus we must install : koa-bodyparser npm i koa-bodyparser update as well in order to use the new middleware: server/index.js <a href="https://medium.com/media/1915db5ecafdb7187fe75715c6669ebd/href">https://medium.com/media/1915db5ecafdb7187fe75715c6669ebd/href</a> Update the tests as well by adding the code below inside : test/articles.routes.test.js <a href="https://medium.com/media/a99173695029feb13bc15b6f5abe90a1/href">https://medium.com/media/a99173695029feb13bc15b6f5abe90a1/href</a> In the above code we’re testing if: the route returns the newly created resource identifier, alongside a Location header the route returns an error when the newly added resource already exists inside the database We’re also expecting the appropriate status code to be returned from the API: : This status code should be returned whenever a new resource has been created. See 201 Created 201 : This status code should be returned whenever a new resource couldn’t be created because the same one is already present inside the database. See 409 Conflict 409 Run the test suite when you’re ready: npm test and watch it fail. Guess what? To make the test pass you must add the corresponding route. Open up and add: server/routes/articles.routes.js <a href="https://medium.com/media/0921874688848f1797d1d932f4a2051a/href">https://medium.com/media/0921874688848f1797d1d932f4a2051a/href</a> update the controller as well by adding the action inside : create server/controllers/articlesController.js <a href="https://medium.com/media/e8024140966c2465538bb8b04b4613cc/href">https://medium.com/media/e8024140966c2465538bb8b04b4613cc/href</a> The above code has another async arrow function which takes as a parameter and: ctx adds the new resource inside the database adds a Location header to the response appends the data property to the response body throws an error if the requested resource already exists Now run the test suite again: npm test and watch all the tests pass: Testing POST /api/v1/articles The pattern should be clear now: write a failing test, add just enough code to make it pass, then refactor. By doing so you will not only be more confident and satisfied with your code, but more importantly, you’ll ship only the necessary logic for making your app work, nothing more, nothing less. The route next to the corresponding controller’s action would be a nice addition to this simple API: that’s left as an exercise for you. delete The code The code for is available on Github: koa-tdd-api koa-tdd-api A more complex example with basic authentication is available at faq-app-api Where to go from here Have you spotted any error in my code? Any suggestion? I would love to ear your input in the comments below! and this is why you should practice it: it must become an habit. Testing is hard It will require time and discipline to incorporate TDD into your workflow, especially if you’re new to Web Development. In fact I encourage you to begin with as soon as possible: the benefits will be invaluable. TDD If you’re absolutely new to TDD I suggest starting with . Why learning TDD is hard, and what to do about it After you get a grasp of how TDD works, start immediately by creating tests: as a rule of thumb, next time you’re about to write some code stop it and write a first. Make it fail and only then you can start adding the appropriate code to make the test pass. test case Once you’re confortable with the basics, go learn about Unit and Integration Testing too! Thanks for reading! See you next time! Originally published on valentinog.com/blog on September 3, 2017 Web Developer & IT Consultant, with over 10 year of experience, I’m here to help you developing your next idea. Got something to do? Let’s get in touch