Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Failing test displays "Error: timeout of 2000ms exceeded" when using Sinon-Chai

I have the following route (express) for which I'm writing an integration test.

Here's the code:

var q = require("q"),
    request = require("request");

/*
    Example of service wrapper that makes HTTP request.
*/
function getProducts() {

    var deferred = q.defer();

    request.get({uri : "http://localhost/some-service" }, function (e, r, body) {
        deferred.resolve(JSON.parse(body));
    });

    return deferred.promise;
}

/*
    The route
*/
exports.getProducts = function (request, response) {
    getProducts()
        .then(function (data) {
            response.write(JSON.stringify(data));
            response.end();
        });
};

I want to test that all the components work together but with a fake HTTP response, so I am creating a stub for the request/http interactions.

I am using Chai, Sinon and Sinon-Chai and Mocha as the test runner.

Here's the test code:

var chai = require("chai"),
    should = chai.should(),
    sinon = require("sinon"),
    sinonChai = require("sinon-chai"),
    route = require("../routes"),
    request = require("request");

chai.use(sinonChai);

describe("product service", function () {
    before(function(done){
        sinon
        .stub(request, "get")
        // change the text of product name to cause test failure.
        .yields(null, null, JSON.stringify({ products: [{ name : "product name" }] }));
        done();
    });

    after(function(done){
        request.get.restore();
        done();
    });

    it("should call product route and return expected resonse", function (done) {

        var writeSpy = {},
            response = {
            write : function () { 
                writeSpy.should.have.been.calledWith("{\"products\":[{\"name\":\"product name\"}]}");
                done();
            }
        };

        writeSpy = sinon.spy(response, "write");

        route.getProducts(null, response);
    });
}); 

If the argument written to the response (response.write) matches the test passes ok. The issue is that when the test fails the failure message is:

"Error: timeout of 2000ms exceeded"

I've referenced this answer, however it doesn't resolve the problem.

How can I get this code to display the correct test name and the reason for failure?

NB A secondary question may be, could the way the response object is being asserted be improved upon?

like image 562
Bradley Braithwaite Avatar asked Jan 24 '14 14:01

Bradley Braithwaite


1 Answers

The problem looks like an exception is getting swallowed somewhere. The first thing that comes to my mind is adding done at the end of your promise chain:

exports.getProducts = function (request, response) {
    getProducts()
        .then(function (data) {
            response.write(JSON.stringify(data));
            response.end();
        })
        .done(); /// <<< Add this!
};

It is typically the case when working with promises that you want to end your chain by calling a method like this. Some implementations call it done, some call it end.

How can I get this code to display the correct test name and the reason for failure?

If Mocha never sees the exception, there is nothing it can do to give you a nice error message. One way to diagnose a possible swallowed exception is to add a try... catch block around the offending code and dump something to the console.

like image 86
Louis Avatar answered Sep 28 '22 14:09

Louis