DEV Community

Cover image for Testing with Mocha
Daniel Troyano
Daniel Troyano

Posted on

Testing with Mocha

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.

  "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. 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.

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.

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 talks about the other kinds.


Now that you're familiar with the Mocha pattern, let's look at an actual test.

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.

const nock = require("nock");
const fakeData = require("./fakeData.json");

Now let's set up our test for our api call.

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.

Top comments (0)