Testing with Mocha
Tags: mocha, javascript, testing
Published: 2020-08-30 20:26:05

Normally, after you get done writing your code, you have to test your code by thinking of every way someone might interact with your application, and then manually trying all those things to make sure it doesn't break. Well wouldn't it be great if something could run all those tests for you? That's what Mocha does.

Mocha is a testing framework for Node.js. Which means it can execute all those tests for you and let you know if your code holds up.
___
Let's assume you have a Node.js server already set up and you have it hooked up to a database. 

Great! Now let's test it to make sure it's working.

First things first let's install the dependencies we'll need for this. 
```
npm i -D mocha chai chai-http nock
```
Mocha is our testing framework. Chai is an assertion library. There are several different ones, but we'll be using Chai. Chai HTTP is used to make requests to our server. And Nock is used to load up a fake response so we can reliably test our api.

Before we do anything let's add a script to our package.json file.
```javascript
  "test": "mocha --exit"
```
This will run all the tests we have in our `/test` folder. We include exit because test responses hang sometimes, and we want the tests to stop running after all the tests pass. If you want to debug exactly why this is happening you can use [wtfnode][1]. But exit doesn't really hurt anything.

Ok, so let's make a set of tests to test our routes.

First let's take a look at how a test works with Mocha and Chai when you're using Behavior Driven Development, which is what I'll be using.
```javascript
describe('Name of the User Story', function() {
  beforeEach('Runs before each test', function() {
  });

  afterEach('Runs after each test', function() {
  });

  context('Start of a narrative', function() {
    it('should do something', function() {
      // Actual testing code
      expect(value).to.be(otherValue)
    });
  });
});
```
In the above example, describe is a way to display a description and group your tests together, and context is just an alias for describe. The two only exist as seperate entites to make your code easier to read.

In addition to beforeEach and afterEach, there are several hooks you can use to interact with your testing environment and get it ready for the test you are about to do. If you want to know more about them check out [mocha's documentation][2].

Finally there is the it block. This is where the actual test is run. Depending on your assertion library and the interface you choose, you can have several different things here. I like expect and it's what I'm going to use here. But [chai's documentation][3] talks about the other kinds.
___
Now that you're familiar with the Mocha pattern, let's look at an actual test.
```javascript
const chai = require('chai');
const chaiHttp = require('chai-http');
const app = require('../server');

chai.use(chaiHttp);
const { expect } = chai;

describe('Books can be found and added', function() {
  let request;

  beforeEach('Setup Request', function() {
    request = chai.request(app);
  });

  context('GET /books', function() {
    it("should return an array", function(done) {
      request.get("/books").end((err, res) => {
        if (err) done(err);
        expect(res.body.books).to.be.an("array");
        expect(res.body.books[0]).to.have.property("name");
        done();
      });
    });
  });
});
```
At the top we import the packages we need and our app, so that we can make requests to it. Then we tell Chai to use `chaiHttp` so that we can make requests. We also grab our interface from Chai.

In our beforeEach we set up our request object. Calling `chai.request(app)` starts the app listening for a request.

Then in our test we do a GET request to `/books` and we expect the result to be an array and the first entry in that array to have a name property.

Part of the beauty of using expect is that the tests are very readable by humans.

Notice our use of done here. Done is an optional parameter you can pass into either a hook or a test if you expect it to be asynchronous. That way the test won't move on until it is `done()`.
___
Let's also go over nock, which we will use to send a fake response back from a given url. We're going to use it to spoof an api call so that we can control our testing environment.

So go ahead and require nock, and some fake data, as json.
```javascript
const nock = require("nock");
const fakeData = require("./fakeData.json");
```
Now let's set up our test for our api call.
```javascript
describe("We want to be able to get data back from the api", function () {
  let request;

  beforeEach("Setup Request", function() {
    request = chai.request(app);
    });
  });

  context("GET /api/books", function() {
    it("should get a response from the api", function(done) {
      nock("http://fakeapi.com")
        .get("/books")
        .reply(200, fakeData);
      request.get("/api/books").end((err, res) => {
        if (err) done(err);
        expect(res).to.have.status(200);
        expect(res.body).to.be.an("array");
        done();
      });
    });
  });
});
```
This example is pretty similar to the previous one, except we are adding nock in. Nock is going to spoof the first call it sees to the given url and reply with, in our case, `fakeData`. This is to guarantee that when our app makes its call to `http://fakeapi.com/books` it gets back exactly what we want. We aren't testing that the api is working, instead we're only testing the way we are talking to it.

Now all you have to do is run `npm test` to see if your tests are passing!
___
These may not seem like especially robust tests, but they are only the beginning. Only you know what your code needs to test, so you're going to have custom build any tests you need. Have fun! I hope this has been enough information to start doing just that.

[1]:https://www.npmjs.com/package/wtfnode
[2]:https://mochajs.org/#hooks
[3]:https://www.chaijs.com/