I'm trying to build a test set for my API, which was developed with nodejs/express, with mocha/chai. Basically, the index returns a simple string that I know it's working because I can see on my browser:
router.get('/', function(req, res, next) {
res.send('Hello World from Eclipse');
});
Then I followed this tutorial to build this test:
var supertest = require("supertest");
var should = require("should");
// This agent refers to PORT where program is runninng.
var server = supertest.agent("http://localhost:5000");
// UNIT test begin
describe("SAMPLE unit test",function(){
// #1 should return home page
it("should return home page",function(done){
// calling home page api
server
.get("/")
.expect("Content-type",/json/)
.expect(200) // THis is HTTP response
.end(function(err,res){
// HTTP status should be 200
res.status.should.equal(200);
// Error key should be false.
res.body.error.should.equal(false);
done();
});
});
});
I can see on the log of my server that the address is been called, however, the test always say that it cannot read property 'should' of undefined, on the line where I have 'res.status.should.equal(200);'. Probably because 'res' is undefined. In other words, no answer from the API.
Am I missing something here? I running mocha with no arguments...
Try something like this:
var expect = require('chai').expect;
var request = require('supertest');
var uri = 'your url';
describe('Profile',function(){
it('Should return a users profile',function(done){
request
.get(uri + '/api/1.0/profile')
.query({app_id:'12345'})
.end(function(err,res){
var body = res.body;
expect(body.first_name).to.equal('Bob');
expect(body.last_name).to.equal('Smith');
done()
});
});
});
Make sure you have the correct requires included.
You should check for errors in .end():
.end(function(err, res) {
if (err) return done(err);
...
});
The test case is expecting the content type to match /json/, which it doesn't, so it should be set (and res will be undefined because of that).
Related
I have embarked on the adventure of learning node and I have already had the first problems. I am testing with Mocha on the api that I am doing in node, and I have problems with authentication, which is why I am using passport and jwt. The problem comes when I do a test to check a 200 by passing a token to the spike through the body, test, and it returns 401
Here I put the file where I do the auth tests
const passport = require ('passport');
// chai is an external library that allows to validate the information of a variable through functions
const chai = require ('chai');
// chai plugin, which allows you to set up servers and make http calls on these servers
const chaiHttp = require ('chai-http');
// In order to do the endpoint tests, you have to call where the backend is located, which is the app.js file
//.app is to call the object that is the server.
const app = require ('../ app'). app;
// to tell chai that you want to use the http plugin it is indicated with the use functionality
chai.use (chaiHttp);
describe ('Auth Test Suite', () => {
it ('returns 401 when the user is not authorized', (done) => {
// here chai is told to use the server that is defined in the file
chai.request (app)
// Here it is saying to make the http call to the server using the indicated protocol
.get ('/ team')
// pick up a function that allows you to interact with the result of the call
.end ((err, res) => {
// check that the response is the same as the http status code
chai.assert.equal (res.status, 401);
// the test is finished
done ();
});
});
it ('returns 200 when jwt token is valid', (done) => {
// here chai is told to use the server that is defined in the file
chai.request (app)
// Here it is saying to make the http call to the server using the indicated protocol
.post ('/ login')
// pick up a function that allows you to interact with the result of the call
.end ((err, res) => {
// once in the post that collects the token, chai is launched again to make another
// request a get and check the token
chai.request (app)
.get ('/ team')
// a header is sent to perform the JWT check
.set ('Authorization', `jwt $ {res.body.token}`)
.end ((err, res) => {
// if the token is valid a 200 is received
chai.assert.equal (res.status, 200);
// the test is finished
done ();
});
});
});
});
Here the app.js
// the express library is imported with a require
const express = require ('express');
// the passport library is imported with a require
const passport = require ('passport');
// define the variable that will have the capabilities to use the express features
const app = express ();
// define the connection port that express will use
const port = 3000;
// the function that checks authentications is called
require ('./ auth') (passport);
// the listen object of the const app is called to start listening for connections, otherwise it would be executed
// and it would end up closing, then open keys to the callback function method so that it performs actions
// start the server.
app.listen (port, () => {
console.log ('Server started on port' + port);
})
// this function is a get request that can be launched from the constant that stores
// the functionalities of express. "req" => request and "res" => response
app.get ('/', (req, res) => {
// with the ".send" functionality, a response to the request is returned to the client
res.status (200) .send ('hello world');
});
app.post ('/ login', (req, res) => {
res.status (200) .json (
{token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0YjoxNTE2MjMXWF0IjoxNTE2MjMXWG2DMXM02MjMXH0IjoxNTE2MjMXWG2DMXM02MJMXH0IjoxNTE2MjMXMXWG2DMXMJ2MJMX2DXMXM02MjWG
)
});
app.get ('/ team',
// when using this route it will be verified whoever uses it has a JWT, it is a middleware
passport.authenticate ('jwt', {session: false}),
(req, res) => {
res.status (200) .send ('hello world');
});
app.post ('/ team / pokemons', (req, res) => {
res.status (200) .send ('hello world');
});
app.delete ('/ team / pokemons /: pokeid', (req, res) => {
res.status (200) .send ('hello world');
});
app.put ('/ team', (req, res) => {
res.status (200) .send ('hello world');
});
module.exports.app = app;
and finally the auth file in which I have passport and JWT
// imported library to use passport. Strategy is used to create an authentication strategy (I think so)
const jwtStrategy = require ('passport-jwt'). Strategy;
const extractJwt = require ('passport-jwt'). ExtractJwt;
// This function is exported to which passport is passed by parameter
module.exports = passport => {
// this would create a JSON object that would be the strategy to use
const opts = {
// this line specifies where the jwt will be taken from when making the request
jwtFromRequest: extractJwt.fromAuthHeaderWithScheme ("JWT"),
secretOrKey: 'secretPassword'
}
// Here passport is instructed to use the strategy created previously, and a function is entered inside it
// result, to do checks
passport.use (new jwtStrategy (opts, (decoded, done) => {
console.log ('decoded jwt', decoded);
return done (null, false);
}));
}
at the end of the test I get an error on line 59 of the test files (chai.assert.equal(res.status, 200);), specifically the second test that jwt tests but I don't understand where the error is. I attach a photo of the test results.
[test result][1][1]: https://i.stack.imgur.com/rVMTg.jpg
Finally, I feel my level of English, I am bad at the language and I have used the translator to ask this question
Consider this scenario:
When you visit my / page the server will respond with a JSON like the following
res.json({
message: 'Welcome home.'
});
to test this, I create a file home.test.js and test it like so:
const chai = require('chai');
const expect = chai.expect;
const chaiHttp = require('chai-http');
const server = require('../server')
chai.use(chaiHttp);
describe('GET /', () => {
it('should respond with homepage', (done) => {
chai
.request(server)
.get('/')
.end((err, res) => {
expect(res.status).to.equal(200);
expect(res.body.message).to.equal('Welcome home.');
done();
});
});
});
The simple test passes and everything is going as planned. Here is the problem. Later on, when I want to use ejs to render the view my code is going to change to this:
res.render('index', { message: 'Welcome home.' });
So now my previous test will not pass as res.body.message will now have the value undefined. How can I actually test this now that the response will be res.render() ?
I think you can affect the message to the request body before rendering the page. Your code will be something like this:
res.body.message="Welcome home".
res.render('index',{message:"welcome home"})
Hi i want to do unit testing on my express js code i want to mock data so after searching multiple websites and blogs i found this library but i am not clear how can i use this library for mocking or data.
My testing code is
var request = require('supertest');
var server = require('./app');
var chai = require('chai');
var chaiHttp = require('chai-http');
var server = require('./app');
var should = chai.should();
chai.use(chaiHttp);
describe('loading express', function () {
it('responds to /', function testSlash(done) {
request(server)
.get('/')
.expect(200, done);
});
it('404 everything else', function testPath(done) {
request(server)
.get('/foo/bar')
.expect(404, done);
});
it('responds to /customers/getCustomerData', function testPath(done) {
request(server)
.get('/customers/getCustomerData?id=0987654321')
.end(function(err, res){
res.should.have.status(200);
res.body.should.be.a('object');
res.body.status.should.equal("success");
res.body.data.customerId.should.equal("0987654321");
done();
});
});
});
Currently this code is fetching data from database but i want Unit testing using mock data. How can i achieve this?
__EDIT__
I want to test the code which is written inside Express js routes file. this routes i am calling inside app.js file like this
var customers = require('./routes/customers');
app.use('/customers', customers);
now the code which customers route file contain is
function getCustomerData(req, res, next) {
var response = {};
var cb = function (response) {
res.send(response);
}
var modelObj = req.models.customer_master;
var data = req.query;
controllers.customers.get(modelObj, data, cb);
};
router.get('/getCustomerData', function (req, res, next) {
getCustomerData(req, res, next);
});
I want to test the response of "get" method using mock data
You want to stub your controller middlewares i guess. As you didn't provide any server side code, i just asume some things:
app.get('/', rootController.get);
Now you want to stub this controller:
it('responds to /', function testSlash(done) {
const rootController = require('./path/to/your/controller');
const rootControllerStub = sinon.stub(rootController, "get",
function(req, res, next){
res.status(200).json({stubbed: 'data'});
});
request(server)
.get('/')
.expect(200)
.expect({stubbed: 'data'})
.end(done);
});
If you wish to mock, you can use sinon express mocks here or if you want to test the actual response data, JSON, use this example
The express route, in the example, takes a parameter and returns a JSON
it('should respond with JSON data', function (done) {
request(server)
.get('/about/jv')
.expect(200)
.end(function (err, response) {
assert.equal(response.header['content-type'], 'application/json; charset=utf-8');
assert.deepEqual(response.body, {
"data":{
"username":"hellojv"}
});
done();
});
but as mentioned above, if you want to use sinon then use the mock library. The example uses Mocha and supertest.
Additionaly, if you write many test files, the stub may not work because of cache. I have to clear cache before initializing the stub and the server. The order is also important.
// have to clear every module which belongs to the require chain
// APP require FOO ROUTE require FOO CONTROLLER require BAR LIB
const caches = [
'../app',
'../routes/foo',
'../controller/foo',
];
caches.forEach(cache => {
delete require.cache[require.resolve(cache)];
});
// mock
const bar = require('../lib/bar');
sinon.stub(bar, 'bar').callsFake(async function() {
return null;
});
app = require('../app');
// ... then the test ...
I found this thread helpful.
I have some middleware functions in my Express app which make outgoing request to a separate server and then send the response returned back to the client.
So this kinda thing:
var request = require('request'),
helpers = require('./helpers.js');
//GET
module.exports.fetch = function(req, res) {
var options = helpers.buildAPIRequestOptions(req);
request(options, function(err, response, body){
res.status(response.statusCode).send(body);
});
};
I am looking at writing unit tests and would like to mock out and return my own responses when the outgoing requests withing these functions gets fired.
I have come across supertest and have had a go at writing a suite like so:
var app = require('./index.js'),
request = require('supertest')(app),
should = require('should');
//GET
describe('GET requests', function(){
it('should do something', function(done){
request
.get('/api/schemes')
.expect(200, done)
.end(function(err, res){
// console.log(res);
// console.log(err);
res.status.should.equal(200);
});
});
});
I think I need something like sinon here, so I could spy on a request that would hit my middleware function and return a response of my choosing. I am just struggling to understand how to add the stubbing to my test.
Can someone advise further please?
Thanks
node-nock can record requests made via the http module (and so, by proxy, request). These can then be queued for replaying in your test suite. The GitHub page has great documentation.
We started a node application where we are going to use Express as the router. In one of our controllers, we have this defined:
var express = require('express');
var router = express.Router();
// api/products
router.get('/', function (req, res) {
res.json({ products: [] });
});
// api/products/:id
router.get('/:id', function (req, res) {
res.json({ id: req.params.id });
});
module.exports = router;
I've been trying to follow examples on how to test this and came up with:
var hippie = require('hippie');
var server = require('../controllers/products');
describe('Products Controller Tests', function () {
describe('/products endpoint', function () {
it('returns an array of products', function (done) {
hippie(server)
.json()
.get('/products')
.expectStatus(200)
.end(function (err, res, body) {
if (err) throw err;
done();
});
});
});
});
But I'm always getting the following error:
Test Name: Products Controller Tests /products endpoint returns an array of products
Test Outcome: Failed
Result StandardOutput:
not ok 1 Products Controller Tests /products endpoint returns an array of products
TypeError: Cannot read property 'apply' of undefined
at Immediate. (C:\Api\node_modules\express\lib\router\index.js:618:14)
tests 1
pass 0
fail 1
What is the best way to unit test these controllers? Is there a different library I should be using?
What about extracting the behaviour of your routes and unit testing that?
Something like this
var express = require('express'),
router = express.Router(),
routes = require('./routes');
router.get('/:id', routes.getId);
So that in your unit test you can have
describe('getId', function() {
var route = require('../routes').getId;
var req = // build your request object with params and so on
var res = // stub this, for example with sinon
it('whatever', function() {
route(req, res);
expect(res.send.calledOnce).to.be.true;
// and so on
});
});
Once you're covered this with unit tests (faster to run, you can hook them up on pre-commit hook), you can integration test the route, without the need to mock the underlying HTTP library, with proper calls using request for example.