Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does one unit test routes with Express?

I'm in the process of learning Node.js and have been playing around with Express. Really like the framework;however, I'm having trouble figuring out how to write a unit/integration test for a route.

Being able to unit test simple modules is easy and have been doing it with Mocha; however, my unit tests with Express fail since the response object I'm passing in doesn't retain the values.

Route-Function Under Test (routes/index.js):

exports.index = function(req, res){   res.render('index', { title: 'Express' }) }; 

Unit Test Module:

var should = require("should")     , routes = require("../routes");  var request = {}; var response = {     viewName: ""     , data : {}     , render: function(view, viewData) {         viewName = view;         data = viewData;     } };  describe("Routing", function(){     describe("Default Route", function(){         it("should provide the a title and the index view name", function(){         routes.index(request, response);         response.viewName.should.equal("index");         });      }); }); 

When I run this, it fails for "Error: global leaks detected: viewName, data".

  1. Where am I going wrong so that I can get this working?

  2. Is there a better way for me to unit test my code at this level?

Update 1. Corrected code snippet since I initially forgot "it()".

like image 398
JamesEggers Avatar asked Mar 01 '12 14:03

JamesEggers


People also ask

How do routes work in Express?

A route is a section of Express code that associates an HTTP verb ( GET , POST , PUT , DELETE , etc.), a URL path/pattern, and a function that is called to handle that pattern.

How do I test a route in jest?

If you are using react router dom, then there are two ways to test the routes using jest. One way is to create an object containing the pathname of route as key and component name for that route as value, and then do an assertion based on that object.


2 Answers

As others have recommended in comments, it looks like the canonical way to test Express controllers is through supertest.

An example test might look like this:

describe('GET /users', function(){   it('respond with json', function(done){     request(app)       .get('/users')       .set('Accept', 'application/json')       .expect(200)       .end(function(err, res){         if (err) return done(err);         done()       });   }) }); 

Upside: you can test your entire stack in one go.

Downside: it feels and acts a bit like integration testing.

like image 99
Rich Apodaca Avatar answered Oct 11 '22 12:10

Rich Apodaca


I've come to the conclusion that the only way to really unit test express applications is to maintain a lot of separation between the request handlers and your core logic.

Thus, your application logic should be in separate modules that can be required and unit tested, and have minimal dependence on the Express Request and Response classes as such.

Then in the request handlers you need to call appropriate methods of your core logic classes.

I'll put an example up once I've finished restructuring my current app!

I guess something like this? (Feel free to fork the gist or comment, I'm still exploring this).

Edit

Here's a tiny example, inline. See the gist for a more detailed example.

/// usercontroller.js var UserController = {    _database: null,    setDatabase: function(db) { this._database = db; },     findUserByEmail: function(email, callback) {        this._database.collection('usercollection').findOne({ email: email }, callback);    } };  module.exports = UserController;  /// routes.js  /* GET user by email */ router.get('/:email', function(req, res) {     var UserController = require('./usercontroller');     UserController.setDB(databaseHandleFromSomewhere);     UserController.findUserByEmail(req.params.email, function(err, result) {         if (err) throw err;         res.json(result);     }); }); 
like image 43
Luke H Avatar answered Oct 11 '22 12:10

Luke H