Testing REST API and rendering with EJS - node.js

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"})

Related

Node.js - Testing REST API routes with supertest

Req.body is not accessible in the routes while making a post request. It would be highly appreciative of someone if he/she help me getting through it. Here is screenshot of my microservice.test.js file. Am I missing something?
import request from "supertest";
import mongoose from "mongoose";
import config from "../config/env";
import routes from "../server/routes";
import { parseResponse, doRequest } from "../server/utils/helperFunctions";
const app = express();
app.use("/", routes);
jest.setTimeout(30000);
The code provided doesn't provide much insight, as I would expect all of the handling of the request to be in your route handler. Is the issue that you are unable to access the body when running tests with supertest? Or that it isn't working at all. More information would be very helpful.
If it is a supertest issue, I would recommend checking out the docs for good examples. Here is one I pulled directly from the NPM site where they POST some data with a request body and then verify the response body:
describe('POST /user', function() {
it('user.name should be an case-insensitive match for "john"', function(done) {
request(app)
.post('/user')
.send('name=john') // x-www-form-urlencoded upload
.set('Accept', 'application/json')
.expect(function(res) {
res.body.id = 'some fixed id';
res.body.name = res.body.name.toLowerCase();
})
.expect(200, {
id: 'some fixed id',
name: 'john'
}, done);
});
});
Also, if you are trying to test your server you should probably import your server code instead of creating a new express instance. For example, in your server code you'll have something like this:
server.js
const express = require('express');
const app = express();
app.use('/', ...) // middleware/route config
...
module.exports = app;
Your server would then use this server like this:
index.js
const app = require('./server')
const port = 4000
app.listen({ port }, () => {
const location = `http://localhost:${port}`
logger.info(`🚀 Server ready at ${location}`)
})
module.exports = app
Now that you have structured your code this way, in your test you can import your server as well (so you are testing your actual server, not a new server that you made up):
server.test.js
const app = require('../../../server');
const request = require('supertest')(app);
describe('Server', () => {
it('does a thing', async () => {
const { body } = await request
.post('http://path/to/test')
.send({ data: 'some data' })
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect(200);
expect(body.thing).toBeTrue();
});
});
expressjs version lower than 4 include body parsing middleware
import bodyParser from 'body-parser';
app.use(bodyParser());
example test
it('.post should work with data', function (done) {
var app = express();
app.use(bodyParser());
app.post('/', function(req, res){
res.send(req.body.name);
});
request(app)
.post('/')
.send({ name: 'tobi' })
.expect('tobi', done);
})

Mocha, Chai & Sinon: Checking internal working of an API

Let's suppose I have a POST endpoint /user/:id and this endpoint, internally calls a function getUserData(id) and then returns the result to the caller, which in-turn returns the output, after JSON.stringify()ing.
Now, I need to ensure that getUserData(id) is called, for at-least once. How can I stub / spy getUserData(id) function, when I am using chai-http to make a post request to the server? Is it even a correct approach?
I adapted the tutorial from https://scotch.io/tutorials/test-a-node-restful-api-with-mocha-and-chai down to a barebones server and test that you can use to do a basic API test.
As Mr.Phoenix said, you don't need to get too deep into the nitty gritty of your handler, just pass some data to your endpoint and check the result against what you expect to get.
Here are 2 files you can use to do this test:
index.js
const express = require('express')
const app = express()
app.get('/material',(req, res)=>{
res.json([])
//res.json(['stone', 'wood'])
})
function getUserData(id){
return 42
}
const port = 3031
app.listen(port, function(err){
console.log("Listening on port: " + port)
})
module.exports = app
test.js
process.env.NODE_ENV = 'test'
// const Material = require('./materials') // conroller
const chai = require('chai')
const chaiHttp = require('chai-http')
const server = require('./index')
const should = chai.should()
chai.use(chaiHttp)
describe('/GET material', () => {
it('it should get all the materials', (done)=>{
chai.request(server)
.get('/material')
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.a('array')
res.body.length.should.be.eql(0) // start empty
done()
})
})
})

how to use sinon js with Express js unit testing

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.

Simple Mocha/Chai test for Nodejs/Express API

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).

Node Express Unit Test JSON Response

Just created a new open source middleware project for express. I want to be able to unit test the json response from the routes it generates... Is there anyway I can do this without actually firing up a grunt serve and checking the url?
So goal would be for someway to run the route but instead of sending json to the browser I can store it in a variable / etc...
What the middleware does is generates routes based on annotations in javascript files.
https://github.com/kmgilbert100/annotation-route-loader
I would like to make my unit test include testing the JSON responses you can see in the above url under tests/routes/**/*
Note app.use(loader) would load all the routes
Below is the current mocha test
// npm modules
const chai = require('chai');
const _ = require('lodash');
const express = require('express');
// local modules
var routeLoader = require('../src/index');
// testing module methods
const assert = chai.assert;
describe('annotation-route-loader', () => {
// store collection of routes
var routePaths = [];
before("Create collection to check from", () => {
var loader = routeLoader({
baseUrl: '/',
path: './routes',
pattern: '**/*.js',
params: {
sports: [
'footbal',
'baseball',
'motocross',
'hockey'
]
}
});
loader['stack'].forEach( stack => {
routePaths.push({
path: stack.route.path,
methods: stack.route.methods
})
})
});
it('Should make sure the default path is valid', (done) => {
// Try And Find Path
var defaultPath = _.find(routePaths, {path: '/'});
assert.isObject(defaultPath);
assert.isTrue(defaultPath.methods.get);
// Make Callback
done()
});
it('Should make sure the sports path is valid', (done) => {
// Try And Find Path
var defaultPath = _.find(routePaths, {path: '/sports'});
assert.isObject(defaultPath);
assert.isTrue(defaultPath.methods.get);
// Make Callback
done()
});
it('Should make sure the sports list path is valid', (done) => {
// Try And Find Path
var defaultPath = _.find(routePaths, {path: '/sports/list'});
assert.isObject(defaultPath);
assert.isTrue(defaultPath.methods.get);
// Make Callback
done()
});
})
Thanks for the comments!
https://github.com/visionmedia/supertest
Ended up using supertest to get the job done!
See below snippet...
var request = require('supertest');
var express = require('express');
var app = express();
app.get('/user', function(req, res) {
res.status(200).json({ name: 'tobi' });
});
request(app)
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res) {
if (err) throw err;
});

Resources