Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test Express.js routes with Jasmine 2.3 and SuperTest

I'm using Jasmine 2.3 installed via NPM and executed with Grunt.

'use strict';

module.exports = function(grunt) {
    grunt.initConfig({
        package: grunt.file.readJSON('package.json'),
        exec: {
            jasmine: 'node_modules/.bin/jasmine'
        }
    });
    require('load-grunt-tasks')(grunt);
    require('time-grunt')(grunt);
    grunt.registerTask('default', 'exec:jasmine');
};

I exported an Express.js application object and using it in my specs along with SuperTest.

'use strict';

var supertest = require('supertest')
var application = require('../../../../../server');

describe('GET /api/users', function() {
    it('should respond with json', function(done) {
        supertest(application)
            .get('/api/users')
            .set('Accept', 'application/json')
            .expect('Content-Type', /json/)
            .expect(200, done);
    });
});

When I run the spec I get no errors even though a 200 status code was expected and 404 was the result. Is the problem in Jasmine or SuperTest, or maybe I should be using SuperAgent.

I have no routes setup just a 404 error handler setup on the Express application object.

application.use(function(request, response, next) {
    response
        .status(404)
        .send({
            message: 'not found'
        });
});
like image 452
Zorin Greene Avatar asked May 13 '15 18:05

Zorin Greene


3 Answers

In order to avoid writing the logic in every .end() function. I suggest to use the following snippet before all your jasmine specs (or you can put it in a helper file helpers/tell-jasmine.js if you like):

function tellJasmine(done) {
    return function (err) {
        if (err) {
            done.fail(err);
        } else {
            done();
        }
    };
}


Now you can write .end(tellJasmine(done)) at the end of your supertest:

describe('GET /api/users', function () {
    it('should respond with json', function (done) {
        supertest(application)
            .get('/api/users')
            .set('Accept', 'application/json')
            .expect('Content-Type', /json/)
            .expect(200)
            .end(tellJasmine(done));
    });
});

Credit for this code goes to nesQuick.

like image 147
nashwaan Avatar answered Nov 11 '22 18:11

nashwaan


Firstly, Good question! I've learned some things researching this. Apparently Jasmine + Supertest don't play very well together. The reason for this appears to be Supertest calling done(err), but Jasmine will only fail when done.fail() or fail() is called. You can see some github issues here, and here.

Use this code to see proof:

describe('GET /api/users', function() {
    it('should respond with json', function(done) {
        supertest(application)
            .get('/api/users')
            .set('Accept', 'application/json')
            .expect('Content-Type', /json/)
            .expect(200, function(res){
              console.log(res); 
              //res is actually an error because supertest called done(error)!
              done.fail() //Now jasmine will actually fail
            });
    });
});

Given this, it appears the easiest solution is to use an alternate library that play nicely together. I've personally used mocha instead of jasmine, and had good success. The choice is yours!

If you really wanted to, you could use jasmine and write your own validators seen in the supertest documentation here.

I hope this helps!

like image 11
Brennan Avatar answered Nov 11 '22 20:11

Brennan


The reason for test failure is because of Supertest calling done(err) whereas Jasmine fails on done.fail() or fail(). Despite this, there is a way to make Jasmine and Supertest work together.

Check this out:

describe('GET /api/users', function() {
  it('should respond with json', function(done) {

    supertest(application)
      .get('/api/users')
      .set('Accept', 'application/json')
      .expect('Content-Type', /json/)
      .expect(200)
      .end(function(err, res) {

        if (err) {

          done.fail(err);

        } else {

          done();
        }
      });
  });
});

The addition of

.end(function(err, res) {

  if (err) {

    done.fail(err);

  } else {

     done();
  }
});

in the end of all Supertests within a describe block should resolve issues between Supertest and Jasmine. This will also provide some sweet error descriptions within the console.

like image 3
datatype_void Avatar answered Nov 11 '22 19:11

datatype_void