Hi!
I'm currently using "supertest" to test some express routes in my Node.js application. (I'm also using sinon and chai.)
I was wondering if the is a way to mock the response so that I don't have to rely on a real HTTP connection to my routes and to any other external services that they might call.
Something like this:
`
const request = require('supertest');
const server = require('./server');
const expectedJson = { 'message': 'Hi!' };
request(server)
.post('/some/route')
.expect(200)
.**magicFunctionThatSetsTheResponseBody(expectedJson)**
.end(function(err, res){
expect(res.body).to.equal(expectedJson);
if (err) {
return done(err);
}
done();
});
`
_The idea behind this, is to verify if nothing has changed within the functionality (controller, etc) that is called within that given route._
@mayacr86 if you are using sinon then you should be able to mock the response on the server-side.
I think that falls outside the scope of supertest. supertest would make the request to a "server", other libs are able to mock the server to provide a test response.
Thanks for the quick response @mikelax !
Here's the "issue"...
I have use sinon.stub to mock Node's http module on other unit test, and that works... But when I try to do the same and combine it with "supertest", I keep getting the same error over and over... Here is a snippet of the code:
const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');
const http = require('http');
const PassThrough = require('stream').PassThrough;
const request = require('supertest');
const server = require('../../../server');
describe('My Service Spec', function () {
// Stub for the http module.
// I have use this set of setting to mock the request and it does work :)
let stubHttpRequest;
beforeEach(function () {
stubHttpRequest = sinon.stub(http, 'request');
});
afterEach(function () {
http.request.restore();
});
describe('testing supertest!', function () {
it('responds to /permission/list', function (done) {
const expected = { // Mock data for the response.
status: {
code: 200,
message: 'OK'
},
data: {
User: {
name: 'Irene'
}
}
};
// Generating request and response streams.
// I have use these settings to test other pieces functionality and it does work.
let response = new test.PassThrough();
response.write(JSON.stringify(expected));
response.end();
stubHttpRequest.callsArgWith(1, response).returns(new test.PassThrough());
request(server)
.post('/permission/list')
.end(function(err, res){ // **HERE IS THE CODE LINE WHERE IT FAILS!!**
console.log('err', err);
console.log('res.body', res.body);
console.log('res.headers', res.headers);
if (err) return done(err);
done();
});
});
});
});
Here's the error detail:
TypeError: argument at index 1 is not a function: undefined
at callCallback (server/node_modules/sinon/lib/sinon/behavior.js:111:27)
at Object.invoke (server/node_modules/sinon/lib/sinon/behavior.js:142:17)
at Object.functionStub (server/node_modules/sinon/lib/sinon/stub.js:93:61)
at Function.invoke (server/node_modules/sinon/lib/sinon/spy.js:172:59)
at Object.proxy [as request] (eval at createProxy (server/node_modules/sinon/lib/sinon/spy.js:77:86), <anonymous>:1:37)
at Test.Request.request (server/node_modules/superagent/lib/node/index.js:623:28)
at Test.Request.end (server/node_modules/superagent/lib/node/index.js:743:18)
at Test.end (server/node_modules/supertest/lib/test.js:121:7)
@mayacr86 have you tried yielding the stubbed request [I have used the Unauthorized code below as an example]
stubHttpRequest.yields({statusCode:401});
I am using the get method to a route that calls a method that sets some JSON data in the response object and using sinon's assert.
var request = require('supertest');
var sinon = require('sinon');
var spy=sinon.spy();
describe('simple test of about route with params',function(){
var server;
beforeEach(function () {
server = require('../server').server;
});
it ('matches the response JSON when the about page is called',function(done){
var getSpy=sinon.spy(server,'get');
const expectedJson = {"data":{"username":"hellojv"}};
聽 request(server)
聽聽聽聽 .get('/about/jv')
聽聽聽聽 .expect(200)
聽聽聽聽 .end(function (err, response) {
聽sinon.assert.match(response.body, expectedJson);
done();
});
});
});
The sinon spy is passed the 'server' that encapsulates the server.js and which contains the express route and is invoked by 'supertest'. In the server.js, a call to a method populates the response object. Please check out the full example here
Most helpful comment
@mayacr86 if you are using sinon then you should be able to mock the response on the server-side.
I think that falls outside the scope of supertest. supertest would make the request to a "server", other libs are able to mock the server to provide a test response.