Integration Testing with SuperTest

The same way you are used to testing your front end code you need to have to the ability to test your software’s server side implementation. For this post, we are going to use NodeJS as the choosen language.

Background

We are going to create a simple API that exposes two endpoints.

GET
/api/filmsPOST
/api/films

The GET endpoint will get a collection of movies, while the POST endpoint will save a specific movie to the database.

Before we start coding how this solution would look, let’s write out tests first.

Write tests first, then code

Lets write the use case for our GET method first. You will use a module called SuperTest that provides a high level abstraction for testing HTTP.

var request = require('supertest');
var app = require('../app.js).getApp;it('should response with a json object of films', function(done){
    request(app)
    .get('/api/films')
    .set('Accept', 'application/json')
    .expect('Content-Type', /json/)
    .expect(200, done);
    });
});

Very similar to other testing frameworks inside the it function we have our assertion. We make an HTTP GET call against the app and we expect for it to return with a json payload and 200 for it’s status code.

Now let’s add our tests for our POST endpoint.

it('should save a movie', function(done){
    request(app)
    .post('/api/films')
    .send({ title: 'Pulp Fiction', year: '1945', rated: 'R', released: '1999',runtime: '90', genre: 'Drama', director: 'Tarantino', writer: 'Vazquez', actors: "John Travolta", plot: 'wow', language: 'english', country: 'USA', awards: 'All', poster: 'some url', metascore: "45", imdbRating: "90", imdbVotes: "67", imdbID: "tt0110912", response: "true" })
    .expect(200)
    .end(function(err, res) {
     if (err) {
        return done(err);
    }
    done();
    });
});

Let me explain the code above. We make a POST call and send a json object that is our film and expect 200 from our response header.

Like you can see from our tests, Supertest is very helpul because it provides a very user-friendly interface.

Let’s make our tests pass

Based on our tests, we need an endpoint /api/films to return a json object that represents our films. Since we are query a database, I am usingMongoDB to store the movies and Mongoose to create a schema for my films. Both the database schema are out of the scope for this blog, however I will make sure to reference the post once I write it.

On the code below, we hit an endpoint and return all the values that are on the database, if we encounter an error we return a 404.

app.get('/api/films', function(req, res) {
    return FilmModel.find(function(err, films) {
        if (!err) {
            log.info('GET films');
                return res.send(films);
        } else {
        return res.status(404).send('Not available');
        log.info(err);
        }
    })
});

One tests green! One more to go.

We also know that we want to have the ability to store films by exposing a POST /api/post endpoint.

In the code below, we take the json object passed to the endpoint and create a new model based on the object. We then save the model to our database and return a success.

app.post('/api/films', function(req, res) {
    var film    film = new FilmModel({
        title: req.body.title,
        year: req.body.year,
        rated: req.body.rated,
        released: req.body.released,
        runtime: req.body.runtime,
        genre: req.body.genre,
        director: req.body.director,
        writer: req.body.writer,
        actors: req.body.actors,
        plot: req.body.plot,
        language: req.body.language,
        country: req.body.country,
        awards: req.body.awards,
        poster: req.body.poster,
        metascore: req.body.metascore,
        imdbRating: req.body.imdbRating,
        imdbVotes: req.body.imdbVotes,
        imdbID: req.body.imdbID,
        response: req.body.response
    });    film.save(function(err) {
        if (!err) {
        log.info('POST films');
        return res.status(200).send(film);
        } else {
        log.info(err);
        return res.status(404).send('Not available');
    }});

Great! Now you know how to add integration tests to your Node API using SuperTest and Express. I really hope you learned a lot and drop a comment if you would to chat.