sidgate
sidgate

Reputation: 15244

Chai http - double callback issue

I have a normal unit test for my REST api using chai-http. It fails with following error

warn: double callback!
error: { SyntaxError: Unexpected token { in JSON at position 58
    at Object.parse (native)
    at IncomingMessage.<anonymous> (E:\projects\node_modules\chai-http\node_modules\superagent\lib\node\parsers\json.js:8:35)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:80:11)
    at process._tickCallback (internal/process/next_tick.js:104:9)
  rawResponse: '{"books":[],"count":0,"page":1,"pages":0,"pageSize":10}{"books":[],"count":0,"page":1,"pages":0,"pageSize":10}',
  statusCode: 200,
  response: undefined }

As you can see, the rawResponse is duplicated due to which the test is failing. I debugged the code, and the controller code is called exactly once, with proper output. But can't understand why this error occurs.

Following is the test code

// some code to mock mongoose with mockgoose
....
....

let server = require('../../../server');
let should = chai.should();
chai.use(chaiHttp);


describe.only('Books', () => {
  describe('/GET book', () => {
      it('it should GET all the books', (done) => {
        chai.request(server)
            .get('/api/books')
            .end((err, res) => {
                console.log(res);
                res.should.have.status(200);

              done();
            }).catch(function(err){
                console.error(err);
                done(err);
            });
      });
  });
});

Upvotes: 2

Views: 3801

Answers (1)

robertklep
robertklep

Reputation: 203514

You're mixing two types of async handling: using .end/.catch instead of either .then/.catch or .end

Because there's an error, both .end() (with the first argument, err, set) and .catch() are getting called, resulting in the done callback being called twice.

Here's a solution using .then/.catch, combined with Mocha's built-in promise support (not using done):

it('it should GET all the books', () => {
  return chai.request(server)
      .get("/api/books")
      .then(res => {
        console.log(res);
        res.should.have.status(200);
      })
      .catch(err => {
        console.error(err);
        throw err; // Re-throw the error if the test should fail when an error happens
      });
});

And using .end:

it('it should GET all the books', done => {

  chai.request(server)
      .get("/api/books")
      .end((err, res) => {
        if (err) return done(err);
        console.log(res);
        res.should.have.status(200);
        done();
      });

});

Upvotes: 9

Related Questions