Simple Unit Testing NodeJS/Express - javascript

Hi I am pretty new to NodeJs and I am trying to write my first tests.
I am kind of stuck with the setup, so I was hoping for some help.
I wrote these two functions:
app.js:
var express = require('express')
, cors = require('cors')
, app = express();
app.get('/a_nice_jsonp',cors(corsOptions), function(req, res, next){
var result = parseCookies(req);
res.jsonp(result);
});
app.get('',function(req,res,next){
res.statusCode = 200;
res.end()
});
I do not export it as module as it is my only file.
I assume it's pretty easy to write the tests for that. I started with something like this:
app-test.js:
var expect = require('expect.js');
var express = require('express');
var expressApp = express();
describe('app js test', function() {
describe('GET /', function() {
it('should respond to GET with empty path', function () {
expressApp.get('', function(req, res, body){
expect(res.status).to.equal(200);
});
})
});
});
I suppose it really reads like a simple task, but I seem to fail over the setup of the test and how to do it.
Can anyone help me out here?
EDIT: The above test runs fine. However, I have difficulties to test e.g. .end() as well as the result in the jsonp request. I simple do not know how to do it?!

When you do
expressApp.get('', function(req, res, body){
expect(res.status).to.equal(200);
});
you are just mapping the route.
To test your REST API, you have to use a library like supertest (there is an example of testing using express + mocha in that link)
it works this way
var request = require('supertest');
var express = require('express');
var app = express();
app.get('/a_nice_jsonp',cors(corsOptions), function(req, res, next){
var result = parseCookies(req);
res.jsonp(result);
});
app.get('',function(req,res,next){
res.statusCode = 200;
res.end()
});
describe('app js test', function() {
describe('GET /', function() {
it('should respond to GET with empty path', function (done) {
request(app)
.get('')
.expect(200)
.end(done)
});
});
});
Edited with separated files
app.js
var express = require('express')
, cors = require('cors')
, app = express();
app.get('/a_nice_jsonp',cors(corsOptions), function(req, res, next){
var result = parseCookies(req);
res.jsonp(result);
});
app.get('',function(req,res,next){
res.statusCode = 200;
res.end()
});
module.exports = app;
app-test.js
var request = require('supertest');
var app = require('app.js');
describe('app js test', function() {
describe('GET /', function() {
it('should respond to GET with empty path', function (done) {
request(app)
.get('')
.expect(200)
.end(done)
});
});
});

Related

Nodejs / Express.js/ Body-parser Unit Test: How to come through middlewares to test the routing function

I have been working on this problem for several days but I couldn't find any solution.
For each of my function in the route class I have this 2 Middlewares
index.js
const browser = require('browser-detect');
const detectBrowser = (req,res,next) => {
const result = browser(req.headers['user-agent']);
console.log(result);
if (result) {
if (result.name === 'chrome') {
console.log('Browser: '+result.name+ ' OK!');
next();
} else if (result.name=== 'firefox') {
console.log('Browser: '+result.name+ ' OK!');
next();
} else {
res.render('browser-response');
}
}
};
const redirectHome = (req,res,next) => {
if(req.session.token && req.session.firstName && req.session.lastName) {
if (!req.session.checked) {
res.redirect('/term-of-service');
}
else {
res.redirect('/index');
}
} else {
next();
}
};
and a simple function I want to test is:
router.get('/', detectBrowser, redirectHome, (req, res) => {
res.render("login");
});
I plan to use Mocha and Supertest as frameworks to test the router.get(/) function, but couldn't find anyway to mock the browser and the variables of session (session.token, session.firstName, session.lastName, session.checked).
Does anyone have an idea about this?
Thank you in advance.
For this question I already found out a work around solution.
For the middleware detectBrowser we just need to add
} else if (result.name=== 'node') { next(); }
because we are working in the node enviroment so those lines of code will make the test file pass through the middleware.
For the second middleware we just need to provide stubbing session information for the test. Below is an example :
const route = require ("../../routes/index");
const request = require("supertest");
const express = require("express");
const bodyParser = require('body-parser');
const chai = require('chai');
const expect = chai.expect;
//create app with valid credentials (not yet accept term of service )
let mockingLoggedIn;
//setup mocking session
mockingLoggedIn = express();
mockingLoggedIn.use(express.urlencoded({extended: false}));
mockingLoggedIn.set('view engine', 'ejs');
mockingLoggedIn.use(bodyParser.json());
mockingLoggedIn.use(bodyParser.urlencoded({extended: true}));
// lets stub session middleware
mockingLoggedIn.use(function (req, res, next) {
req.session = {};
next();
});
//provide a fake login
mockingLoggedIn.get('*', function (req, res, next) {
// and provide some accessToken value
req.session.token = "test";
req.session.firstName= 'test';
req.session.lastName = 'test';
req.session.checked = false;
next()
});
mockingLoggedIn.use(route);
And in the test we just need to use that stubbed app to make request to the route. For example:
describe("Testing / route and /login route works", () => {
it('testing index route: GET / should return status 200 and render login site',
(done)=> {
request(mockingLoggedIn) // request an app with stubbed credentials
.get("/")
.expect("Content-Type", "text/html; charset=utf-8")
.expect(200)
.end(function (err,res) {
expect(err).to.be.null;
done();
})
});
});
Hopefully this will help someone :)

Pass sockets.io from express server file to route file

I would use sockets in a separate route file .
I'm using the method mentioned in this answer : Express 4 Routes Using Socket.io
I have copied exactly the same logic. In server file :
var http = require("http");
var admin = require('firebase-admin');
var firebase = require("firebase");
var express = require("express");
var app = express();
var bodyParser = require("body-parser");
var port = process.env.app_port || 8080; // set our port
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var server = app.listen(port);
var io = require("socket.io")(server);
var routerProj = require("./routes/routes")(io);
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT ,DELETE');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,*");
next();
});
var config = {
.... DB Configuration ....
};
firebase.initializeApp(config);
var serviceAccount = require("./ServiceAcountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://datatable-18f93.firebaseio.com"
});
io.on("connection", function (client) {
console.log("Un client est connecté !");
//routerProj(client);
});
app.use("/v1", routerProj, function (req) {
//Create HTTP server and listen on port 8000 for requests
});
My connection socket is working and the console.log runs in terminal
routes.js file
var express = require("express"); // call express
var router = express.Router(); // get an instance of the express Router
var admin = require("firebase-admin");
var returnRouter = function (client) {
router.use(function (req, res, next) {
// do logging
client.on('save-message', function (socket) { console.log("heheyy") })
});
router
.route("/")
.get(function (req, res, err) {
// Get a database reference to our posts
var db = admin.database();
var ref = db.ref("/");
// Attach an asynchronous callback to read the data at our posts reference
ref.once("value", function (snapshot) {
var list = [];
snapshot.forEach(function (elem) {
list.push(elem.val());
})
list = JSON.stringify(list);
//list = JSON.parse(list)
console.log(err);
//console.log(JSON.stringify(list))
res.send(list);
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
res.status(500).send(errorObject.code);
});
});
router
.route("/")
.post(function (req, res, err) {
console.log(req.body);
// Get a database reference to our posts
var db = admin.database();
var ref = db.ref("/");
ref.push(
{
"text": req.body.text
}
);
});
return router;
}
module.exports = returnRouter;
save-message is emit in Angular when my arr is running :
ngOnInit() {
this.socket.emit('save-message', { room: "hello" });
}
Save-message event is not getting read neither the routes file, In my angular application services does not get data from routes. and console.log in get and post routes does not work.
My question is how to get sockets working in a reparate file ?
You should move the socket.io listener outside of the express use route. It's not really clear why you would want it there as it will register a new listener every time someone makes a request to your v1 endpoint.
You likely aren't seeing the messages because the listener does not register until someone makes a request to the v1 endpoint and the client already sent its message.
var returnRouter = function (client) {
// do logging
client.on('save-message', function (socket) {
console.log("heheyy");
});
...
};

Express routes returning 404s

I have a couple of simple routes that I have misconfigured and not sure why.
app.js:
//app setup
var http = require('http');
var bodyParser = require('body-parser');
var express = require('express');
var routes = require('./routes');
var agent = require('./routes/agent');
var config = require('./config');
var app = express();
app.server = http.createServer(app);
app.use(bodyParser.json({
limit : config.bodyLimit
}));
app.use(bodyParser.urlencoded({
extended : true
}));
app.use('/v1', routes);
app.use('/v1/agent', agent);
app.server.listen(config.port);
console.log('API listening on port ' + app.server.address().port);
module.exports = app;
This returns responses on the /v1/ route (index.js):
'use strict';
var express = require('express');
var router = express.Router();
router.get('/', function (req, res) {
res.status(403).json({
message: 'Invalid request.'
});
});
module.exports = router;
in the agent route, I have a POST handler that is being handled correctly at /v1/agent/login. But while a GET routed at /v1/agent/ works, a GET routed to /v1/agent/123 returns a 404:
'use strict';
var agentController = require('../controller/agent.js');
var express = require('express');
var router = express.Router();
function handleError(objError, res) {
res.status(500).json({ errorMessage : objError.message });
}
router.get('/', function (req, res) {
res.status(200).json({
message: 'OK' // works fine
});
});
router.get('/:id'), function (req, res) {
var agentNum = req.params.id;
res.send(req.params); // 404 here
try {
//res.status(200).json({ message: 'hello agent.'});
} catch (err) {
// handleError(err, res);
}
};
router.post('/login', function (req, res) {
var agentNum, password;
// works fine
});
router.post('/pwr', function (req, res) {
//also works fine
});
module.exports = router;
My understanding is that the app.use method should redirect the route and any GET requests appended to that route to the one I specified (agent), so why is it that the one with params fails while the root one succeeds?
Thank you
You're not passing the callback correctly.
router.get('/:id')
router.get('/:id', function(req, res) {
var agentNum = req.params.id;
res.send(req.params); // 404 here
try {
//res.status(200).json({ message: 'hello agent.'});
} catch (err) {
// handleError(err, res);
}
});

MongoDB - TypeError: users.aggregate is not a function

I'm trying to query a collection using aggregate but getting TypeError: users.aggregate is not a function. Here's my code:
./app.js (reduced to fit)
var express = require('express');
var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:27017/mydb');
var users = require('./routes/users');
var app = express();
app.use(function(req, res, next) {
req.db = db;
next();
});
app.use('/users', users);
module.exports = app;
./routes/users.js
var express = require('express');
var router = express.Router();
router.get('/test', function(req, res) {
var users = req.db.get('users');
users.aggregate([{ $match: { username: 'test0' }}], function(err, data) {
res.json(data);
});
});
module.exports = router;
I'm running MongoDB version 3.2.10 and the above query works fine in the console. I've looked up solutions and they all suggest to check the MongoDB version, which I've already done. I've also tried req.db.collection('users').aggregate (as suggested by another post) and receive a similar error: req.db.collection is not a function. What am I missing?
EDIT:
Running users.find({ username: 'test0' }, func... works and returns correct data.
EDIT2: Added more code.
You can do like this.
var app = require('express')();
var expressMongoDb = require('express-mongo-db');
app.use(expressMongoDb('mongodb://localhost/test'));
app.get('/', function (req, res, next) {
req.db // => Db object
});
I tried with this. It is working in my local.
var app = require('express')();
const db = require('monk')('localhost/test')
app.use(function(req,res,next){
req.db = db;
next();
});
app.get('/', function (req, res, next) {
var db = req.db;
var users = db.get('users');
users.aggregate([
{$match: { firstName: 'Test 2' }}
]).then(function(docs) {
console.log(docs)
})
});
app.listen(3010, function () {
console.log('Example app listening on port 3010!');
});

Dynamic routes with different functions in express js

I have loads of router.get functions in my code which I think, could be reduced to a single switch-case function. Here is what I have tried:
function handlerA(req, res) {}
function handlerB(req, res) {}
var routes = {
'/url-one': handlerA,
'/url-two': handlerB
}
router.get('/*', function(req, res) {
var url = req.url;
if (routes[url]) {
routes[url](req, res);
}
});
This works but also, significantly slows my application. Is there any other solution which would not hit the performance of my app?
Thanks
Is there a reason you don't want to use router.get functions? I would guess express.js is internally performing the same logic that you are doing anyway. You are just replacing get functions with handlers.
If you are using similar logic between multiple routes, that may be worth abstracting.
I usually go with a setup like this:
app.js
routes.js
api/
user/
index.js
user.controller.js
user.model.js
image/
index.js
image.controller.js
image.model.js
/api/user/index.js:
var express = require('express');
var controller = require('./user.controller');
var router = express.Router();
router.get('/', controller.index);
router.post('/', controller.create);
module.exports = router;
/api/user/user.controller.js:
var User = require('./user.model');
exports.index = function(req, res) {
// Show list of users
};
exports.create = function (req, res, next) {
// Create user
};
/routes.js:
module.exports = function(app) {
// Insert routes below
app.use('/api/users', require('./api/user'));
app.use('/api/images', require('./api/image'));
// All undefined asset or api routes should return a 404
app.route('/:url(api|auth|components|app|bower_components|assets)/*')
.get(errors[404]);
// All other routes should redirect to the index.html
app.route('/*')
.get(function(req, res) {
res.sendfile(app.get('appPath') + '/index.html');
});
};
And lastly, the /app.js:
// Set default node environment to development
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var express = require('express');
var mongoose = require('mongoose');
var config = require('./config/environment');
// Connect to database
mongoose.connect(config.mongo.uri, config.mongo.options);
// Populate DB with sample data
if(config.seedDB) { require('./config/seed'); }
// Setup server
var app = express();
var server = require('http').createServer(app);
require('./config/express')(app);
require('./routes')(app);
// Start server
server.listen(config.port, config.ip, function () {
console.log('Express server listening on %d, in %s mode', config.port, app.get('env'));
});
// Expose app
exports = module.exports = app;
Most of this is directly from the Yeoman Generator Angular-Fullstack and it has a really nice setup!

Categories

Resources