I'm learning unit testing. So far I was able to run simple tests like "Add two numbers and test if they are above 0", but I want to build a REST API using TDD. So far I have this:
My routes/index.js file:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function (req, res, next) {
res.send({val: true});
});
module.exports = router;
My index.test.js file:
var mocha = require('mocha');
var assert = require('chai').assert;
var index = require('../routes/index');
describe('Index methods', () => {
it('Returns true', done => {
index
.get('http://localhost:3000')
.end(function (res) {
expect(res.status).to.equal(200);
done();
})
})
});
I user a tutorial to do this, but when I try to run this I get:
TypeError: index.get(...).end is not a function
So I'm guessing there is something wrong, but have no idea what. That's my first day learning TDD so if you see anything stupid please let me know.
Doing this:
it('Returns true', done => {
var resp = index.get('http://localhost:3000/');
assert.equal(resp.val === true);
done();
})
Also results in an error:
AssertionError: expected false to equal undefined
1. Install the dev dependencies for mocha
chai: assertion library for node and browser,
chai-http: HTTP Response assertions for the Chai Assertion Library.
2. You need to export your server,
'use strict';
/*eslint no-console: ["error", { allow: ["warn", "error", "log"] }] */
const express = require('express');
const app = express();
//...
const config = require('config');
const port = process.env.PORT || config.PORT || 3000;
//....
app.listen(port);
console.log('Listening on port ' + port);
module.exports = app;
3. Write your tests as:
If your test script is users.spec.js,it should start by:
// During the rest the en variable is set to test
/* global describe it beforeEach */
process.env.NODE_ENV = 'test';
const User = require('../app/models/user');
// Require the dev-dependencies
const chai = require('chai');
const chaiHttp = require('chai-http');
// You need to import your server
const server = require('../server');
const should = chai.should();
// Set up the chai Http assertion library
chai.use(chaiHttp);
// Your tests
describe('Users', () => {
beforeEach((done) => {
User.remove({}, (err) => {
done();
});
});
/**
* Test the GET /api/users
*/
describe('GET /api/users', () => {
it('it should GET all the users', (done) => {
chai.request(server)
.get('/api/users')
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a('array');
res.body.length.should.be.eql(0);
done();
});
});
});
// More test...
});
You can take a look at my repository, Github - Book Store REST API
const chai = require('chai');
const expect = require('chai').expect;
const chaiHttp = require('chai-http');
chai.use(chaiHttp);
first install chai
it('Returns true', done => {
return chai.request(index)
.get('/')
.then(function (res) {
expect(res.status).to.equal(200);
done();
})
})
var mocha = require('mocha');
var assert = require('chai').assert;
var index = require('./index');
var req = require('supertest');
describe('Index methods', () => {
it('Returns true', done => {
req(index)
.get('/')
.end(function (res) {
expect(res.status).to.equal(200);
done();
})
})
});
also in your terminal type npm i supertest --save-dev
simple test case to check if the server is running properly.
const chai = require('chai'),
chaiHttp = require('chai-http'),
server = require('../app'),
faker = require('faker'),
should = chai.should();
chai.use(chaiHttp);
describe('Init', function () {
it('check app status', function (done) {
chai.request(server).get('/').end((err, res) => {
should.not.exist(err);
res.should.have.status(200);
done();
})
});
});
Test Cases for get API
describe('/Get API test', function () {
it('Check the api without user id parameter', function (done) {
chai.request(server).get('/post-list').end((err, res) => {
should.not.exist(err);
res.should.have.status(401);
res.body.should.be.a('object');
res.body.should.have.property('message');
res.body.should.have.property('message').eql('User Id parameter is missing');
done();
})
});
it('Check the api with user id. Success', function (done) {
chai.request(server).get('/post-list?user_id=1').end((err, res) => {
should.not.exist(err);
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('userId');
res.body.should.have.property('title');
res.body.should.have.property('body');
done();
})
});
});
Test Case for Post API
describe('/POST API test', function () {
it('Check the api without parameters . failure case', function (done) {
chai.request(server).post('/submit-data').send({}).end((err, res) => {
should.not.exist(err);
res.should.have.status(401);
res.body.should.be.a('object');
res.body.should.have.property('message');
res.body.should.have.property('message').eql('Mandatory params are missing!');
done();
})
});
it('Check the API with valid parameters. Success', function (done) {
chai.request(server).post('/submit-data').send({name:faker.name.firstName(),email:faker.internet.email()}).end((err, res) => {
should.not.exist(err);
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('message');
res.body.should.have.property('message').eql('data saved successfully');
done();
})
});
});
Add test cases as per the different case available in your API.
Find here the basic terminologies and complete sample application to proceed: https://medium.com/#pankaj.itdeveloper/basics-about-writing-tests-in-nodejs-api-application-4e17a1677834
Related
Given is my code to test a post request with an Authorization header set to the jwt token and a path parameter passed in to the post path, i.e. the id:5ee9b12ab08b6c3c58375a6d
Is there a better way to do this?
const expect = require("expect");
const request = require("request");
const chai = require("chai");
let chaiHttp = require("chai-http");
let server = require("../app");
let should = chai.should();
chai.use(chaiHttp);
describe("Admin Priveleges", () => {
describe("/Update Status", () => {
it("Update membership and registration status", (done) => {
chai
.request(server)
.post("/api/v2/user/update-status/5ee9b12ab08b6c3c58375a6d")
.set('Authorization', "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZWU5YjEzN2IwOGI2YzNjNTgzNzVhNmUiLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE1OTI0NjEyMjIyMDgsIm5hbWUiOiJVdGthcnNoIFNocml2YXN0YXZhIiwiaWF0IjoxNTkyMzc0ODIyfQ.M53gRzIppbhhLSCf9bD6xcdXfITiD1jUOzTlDqHK3is")
.send({
membership_status: "active",
registration_status: "pending_approval",
status_comment: "Good going"
})
.end((err, res) => {
if (err) throw err;
if (should) console.log("****Status Updated Successfully****");
res.should.have.status(200);
done();
});
}).timeout(30000);
});
});
So this is my testing code and each time I run this for testing I get the following error:
How can I solve this error?
When I copy-pasted you 'url' in web console, it showed the actual string with the otherwise 'invisible' .
Test:
context('Should not show "Request path contains unescaped characters, in Mocha/chai testing"', function() {
it('POST /api/v2/user/update-status/5ee9b12ab08b6c3c58375a6d', function(done) {
chai
.request(server)
.post('/api/v2/user/update-status/5ee9b12ab08b6c3c58375a6d')
// .post('/api/v2/user/update-status/5ee9b12ab08b6c3c58375a6d') // with the 'hidden dots'
.set('Authorization', "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZWU5YjEzN2IwOGI2YzNjNTgzNzVhNmUiLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE1OTI0NjEyMjIyMDgsIm5hbWUiOiJVdGthcnNoIFNocml2YXN0YXZhIiwiaWF0IjoxNTkyMzc0ODIyfQ.M53gRzIppbhhLSCf9bD6xcdXfITiD1jUOzTlDqHK3is")
.send({
membership_status: "active",
registration_status: "pending_approval",
status_comment: "Good going"
})
.end((err, res) => {
// if (err) throw err;
// if (should) console.log("****Status Updated Successfully****");
// res.should.have.status(200);
expect(res).to.have.status(404);
done();
});
});
})
I a doing unit test with Sinon to at least try to get something to pass and am out of luck. I wasn't able to find anything online.
I have 2 problems:
1) I am trying to get a simple response, but it fails saying spy is false. When I log it, it says it's true.
2) I want to test the template in the callback function is equal to 'New Title'. I am unable to figure how to pass req, res, and next into router.get
router.js
const express = require('express'), router = express.Router();
router.get('/', (req, res, next) => {
var template = {
title: req.title,
item: req.item,
description: 'N/A'
};
res.render('index', template);
module.exports = router;
});
router.spec.js
const router = require('./router');
var res = {};
var req = {
title: 'New Title',
item: 'Blank Item'
};
var template = {
title: req.title,
item: req.item,
description: 'N/A'
};
it('1) should call the response', ()=>{
var spy = sinon.spy(route, 'get');
route.get('/', ()=>{});
console.log(spy.calledOnce); // equals true
assert(spy.calledOnce).toBeTruthy();
spy.restore();
});
it('2) should return a status 200', ()=>{
var stub = sinon.stub().yield([req, res, next]);
route.get('/', stub); // main problem
assert.equal(200, res.statusCode);
stub.restore();
});
I want to access the route handler so I can do further testing. Where and how can I implement route handling in this situation?
Express app for routing is usually best to test with integration testing not unit testing that you attempted to do. Supertest can be used as the library.
Another improvement that we can do is to separate the logic to generate template into another file. And for this service, we can make a unit test on it. Use mocha or jest can be the option.
Example:
const request = require('supertest');
const express = require('express');
const service = require('./service'); // our new service file
const app = express();
app.get('/', function(req, res) {
const template = service.getTemplate(req);
res.render('index', template);
});
// integration test, ideally must be separated into a test file e.g. app-integration-test.js
request(app)
.get('/')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res) {
if (err) throw err;
});
// service.js
function getTemplate(req, res) {
return {
title: req.title,
item: req.item,
description: 'N/A'
};
}
// service-unit-test.js
describe('service test', function() {
it('returns template correctly', function() {
const req = {
title: 'someone',
item: 'my item',
}
const template = service.getTemplate(req);
expect(template).to.eql({
title: 'someone',
item: 'my item',
description: 'N/A'
})
})
})
Hope it helps!
I'm looking to change requestHandler.value to 5 for my functional styled tests.
When running the suite, creating 1000 documents in the db is not really an option, so is it possible to change it's value programmatically before running the suite and then reset it afterwards? I can create 5 documents in db before the test to work with.
Of coarse I can stub countDocumentsInDb() in unit tests to return what I need, but I've simplified logic below for the sake of the question.
app.js:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var requestHandler = require('./lib/requestHandler.js');
var PORT = 4000;
app.route('/validate')
.get(function(req, res) {
requestHandler.process(req, res);
});
if (!module.parent) {
server.listen(PORT, function(err) {
if (err) {
return;
}
});
}
module.exports = app;
requestHandler.js:
var requestHandler = {
value: 1000,
process: function(req, res) {
numberOfDocumentsInDb = countDocumentsInDb();
if (numberOfDocumentsInDb === this.value) {
res.send(true);
} else {
res.send(false);
}
}
};
module.exports = requestHandler;
FVT style test ..
var Promise = require('promise');
var request = require('supertest');
var chai = require('chai');
chai.should();
var server = require('../../app.js');
describe('app.js', function() {
describe('/validate', function() {
it('should return true if number of documents in db matches pre-defined value', function(done) {
var fvtPromise = new Promise(function(fulfill) {
request(server)
.get('/validate')
.expect(200)
.end(function(err, res) {
if (err) {
throw err;
}
res.body.should.equal(true);
fulfill(null);
});
});
fvtPromise.done(function() {
done();
});
});
});
});
You can play with the require.cache, that will allow you to modify the values of requestHandler.
Is just an example I hope you get the idea.
- In the before each modify the require cache and set your test values
-In the after each set back the original values
-Please notice that the const server = require('./app.js'); is inside the test, so it will take the cache vales
e.g.
describe('test with cache', function(){
require('./requestHandler');
let originalValues;
beforeEach(function() {
originalValues = require.cache[ require.resolve('./requestHandler') ].exports;
require.cache[ require.resolve('./requestHandler') ].exports = {
value:5,
process: function(req, res) {
//other stuff
}
};
});
afterEach(function() {
require.cache[ require.resolve('./requestHandler') ].exports = originalValues;
});
it('should pass', function(){
const server = require('./app.js');
var fvtPromise = new Promise(function(fulfill) {
request(server)
.get('/validate')
.expect(200)
.end(function(err, res) {
if (err) {
throw err;
}
res.body.should.equal(true);
fulfill(null);
});
});
fvtPromise.done(function() {
done();
});
expect(true).to.be.true;
});
});
I've got a simple express app that looks like this:
var SendMandrillTemplate = require('send-mandrill-template');
var sendMandrillTemplate = new SendMandrillTemplate('api-key-goes-here');
var app = require('express')();
app.get('/', function(req, res, next) {
sendMandrillTemplate.sendTemplate(
'template-name-goes-here',
'email#here.com', {
value: 123
},
function(err) {
if (err) {
res.send('ERR - ', err)
} else
res.send('DONE')
});
});
module.exports = app;
I export the app object, so I can mount this in a separate server.js like this -
var app = require('./app')
app.listen(1234, function() {
console.log('Running on port 1234');
});
This is to enable me to use supertest a bit easier.
Here's my test so far:
var app = require('./app')
var request = require('supertest')
var SendMandrillTemplate = require('send-mandrill-template');
describe('GET /', function() {
var sendTemplateStub;
before(function() {
//I think i need to setup a spy on the created instance of SendMandrillTemplate.sendTemplate
//sendTemplateStub = //?
});
it('calls sendTemplate on sendMandrillTemplate instance', function(done) {
request(app)
.get('/')
.expect(200)
.end(function(err, res) {
if (err) throw err;
//assert sendTemplateStub was called with 'template-name-goes-here'
//etc...
done();
})
})
})
As you can see, I'm having trouble stubbing the SendMandrillTemplate constructor
If I wasn't newing up an instance of SendMandrillTemplate I could do something like:
sendTemplateStub = sinon.stub(SendMandrillTemplate, 'sendTemplate')
But of course, in this scenario this won't work...
You can get away with something as simple as
var SendMandrillTemplate = require('send-mandrill-template');
sinon.stub(SendMandrillTemplate.prototype, 'sendTemplate');
I'm using something very similar to the following to execute a series of API tests using Mocha. This is great, but it requires making a separate API call for each test. I want to use the same API call and run multiple tests against that response. I've been reading that you can use before to do it, but none of the examples around the web actually show it working with API calls?
var chai = require('chai');
var request = require('request');
var async = require('async');
var assert = chai.assert,
expect = chai.expect,
should = chai.should();
describe('/', function () {
it('should return 200', function (done) {
request.get('http://localhost:8000', function (err, res, body) {
res.should.have.status(200);
done();
});
});
it('should say "Hello, world!"', function (done) {
request.get('http://localhost:8000', function (err, res, body) {
body.should.have.property('type', 'aType');
done();
});
});
});
You could do this with a before function like so...
var chai = require('chai');
var request = require('request');
var async = require('async');
var assert = chai.assert,
expect = chai.expect,
should = chai.should();
describe('/', function () {
var firstRequest;
before(function(done) {
request.get('http://localhost:8000', function(err, res, body) {
firstRequest = {
err:err,
res:res,
body:body
};
done();
});
});
it('should return 200', function (done) {
firstRequest.res.should.have.status(200);
done();
});
it('should say "Hello, world!"', function (done) {
firstRequest.body.should.have.property('type','aType');
done();
});
});
However, unless you have a really good reason to do this, I think you're better off just combining the tests.
var chai = require('chai');
var request = require('request');
var async = require('async');
var assert = chai.assert,
expect = chai.expect,
should = chai.should();
describe('/', function () {
it('should return 200 and say "Hello, world!"', function (done) {
request.get('http://localhost:8000', function (err, res, body) {
res.should.have.status(200);
body.should.have.property('type', 'aType');
done();
});
});
});
If the test fails Mocha will report the specific reason why it failed even though there are two assertions.