I have an express route in a Node application that uses Mongoose for querying a Mongo database. There is a promise used in the get request to find items and I am not sure how to test this promise.
I am not very familiar with unit testing node applications.
Here is the code for the express route, this works but I am not sure how to test it:
var express = require('express');
var router = express.Router();
var promise = require('bluebird');
// bluebird.promisifyAll is used on Mongoose in app.js
var ItemModel = require('./itemModel');
router.get('/', function(req, res, next) {
ItemModel.findAsync()
.then(function(items) {
res.status(200).send(items);
})
.catch(function(err) {
next(err);
});
});
module.exports = router;
Here is what I have stubbed out in the test so far. I am not sure how to test the promise in the routes.get method :
describe('ItemRoute', function() {
var express = require('express');
var bodyParser = require('bodyParser');
var supertest = require('supertest');
var sinon = require('sinon');
var expect = require('chai').expect;
var assert = require('chai').assert;
var ItemModel = require('./ItemModel');
var ItemRoute = require('ItemRoute');
var uri = '/items/';
var agent;
beforeEach(function(done) {
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(uri, releaseNotesRoute);
agent = supertest.agent(app);
done();
});
describe('GET', function() {
it('returns an empty array when no items are stored in Mongo', function() {
// Not sure how to test the route here with a get that
// uses a promise, ItemModel.findAsync().then
});
});
});
to able to use promises in test, you should have to install sinon-as-promises module from npm. Then you can mock ItemModel like this:
var itemModelMock = sinon.mock(ItemModel);
itemModelMock.expects('findAsync').resolves([]);
Related
I'm new to nodeJS and testing and I'd like to know how I can test my application routes properly. I've read some articles that uses supertest and chai-http to call the POST method but I believe this way would be more of an integration testing instead of unit testing my app.
I've read about Sinon but I'm having a hard time applying it on my code like I don't know what to stub, how I can manipulate the data from the request body so I can cover different branches of my conditional statements. I'm monitoring my code coverage with nyc so I'm also aiming to increase my unit test coverage.
I would appreciate it a lot if someone can guide me on this. Thanks in advance!
server.js
const express = require('express');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.listen(8080, function () {
logger.info('App is now running on port 8080');
});
app.use('/', require('./routes/generateURL.js'));
module.exports = app;
generateURL.js
const express = require('express');
const router = express.Router();
router.post('/generate-url', (req, res) => {
let result = {
status: false
};
const acctId = req.body.accountId;
const baseURL = 'http://somecompany.com/billing/';
const dateToday = new Date();
try {
if (accountId) {
result.status = true;
result.bill = baseURL + acctId + '/' + dateToday;
} else {
throw 'Missing accountId';
}
} catch(err){
console.log(err);
}
return res.send(result);
});
module.exports = router;
I have created a service in node.js for basic crud operations. However when I start service it throws Route.get() requires a callback function but got a [object Undefined] error. I am not able to figure out where the error is.
Here is my code.
Models:
agreement_master.js.
const mongoose = require('mongoose');
const agreementmaster = mongoose.Schema({
ClientId:{type:Number},
UserId:{type:Number},
StartDate:{type:Date},
});
var Agreement = module.exports =
mongoose.model('Agreement',agreementmaster);
module.exports.addmAgreement=function (data,callback){
data.save(callback);
}
module.exports.getallmAgreement= function (data,callback){
var query = {status:true};
Agreement.find(query, callback);
}
routes:
agreement_master.js
var express = require('express'),
router = express.Router(),
magreement = require('../controller/agreement_master');
router.post('/addmAgreement', magreement.addmAgreement);
module.exports = router;
Controller:
agreement_master.js
const Agreement= require('../models/agreement_master');
exports.addmAgreement = function (req, res){
var data = JSON.parse(JSON.stringify(req.body));
var agreement = new Agreement(data);
agreement.ClientId = req.body.ClientId;
agreement.UserId= req.body.UserId;
agreement.StartDate=new Date();
Agreement.addmAgreement(agreement, function (err, obj) {
if (err) return res.json({err, status:'error'});
if(obj){
return res.json({
message:'agreement added',
});
}
});
};
index.js
const express = require('express');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const expressValidator = require('express-validator');
const cookieParser = require('cookie-parser');
mongoose.connect('mongodb://local/local-host')
const app = express();
error comes at this part in the below line:
const agreement = require('./routes/agreement_master');
app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(expressValidator());
app.use(cookieParser());
//Add Routes here
app.use('/agreement', agreement);
app.set('port', (process.env.PORT || 3001));
var server = app.listen(app.get('port'), function(){
console.log('Server Started on port ' + app.get('port'));
});
module.exports = app;
user module.exports instead of exports.
exports doest export anything and will not be used by require();
module.exports.addmAgreement = function (req, res){
var data = JSON.parse(JSON.stringify(req.body));
var agreement = new Agreement(data);
agreement.ClientId = req.body.ClientId;
agreement.UserId= req.body.UserId;
agreement.StartDate=new Date();
Agreement.addmAgreement(agreement, function (err, obj) {
if (err) return res.json({err, status:'error'});
if(obj){
return res.json({
message:'agreement added',
});
}
});
};
try this
router.post('/addmAgreement', function(req, res){
magreement.addmAgreement
});
instead of
router.post('/addmAgreement', magreement.addmAgreement);
Making this simple Node.js Express API I encountered an odd problem:
I am creating a model and inserting data into it and then saving it to my MongoDB. But the record is never saved but I also don't get any error. I have checked if MongoDB is running and both syslog for Node errors and mongod.log for MongoDB errors as well as my own Wilson debug.log file. All contain no errors.
I use postman to test the API and do get a response every time. It's just that the data does not get saved to MongoDB (I used the mongo console with db.collection.find() to check for inserted records).
Any idea why this could be happening?
my code:
api.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var http = require('http');
var https = require('https');
var fs = require('fs');
var winston = require('winston');
// Configure logging using Winston
winston.add(winston.transports.File, { filename: '/home/app/api/debug.log' });
winston.level = 'debug';
// Request body parser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Enable https
var privateKey = fs.readFileSync('path to private key');
var certificate = fs.readFileSync('path to cert file');
var credentials = {
key: privateKey,
cert: certificate
};
// ROUTERS
var router = express.Router();
var speciesRouter = require('./app/routes/speciesRouter');
router.use('/species', speciesRouter);
// Routes prefix
app.use('/api/v1', router);
// SERVER STARTUP
http.createServer(app).listen(3000);
https.createServer(credentials, app).listen(3001);
speciesRouter.js
var express = require('express');
var mongoose = require('mongoose');
var router = express.Router();
var Sighting = require('../models/sighting');
var winston = require('winston');
// Database connection
var dbName = 'dbname';
mongoose.connect('mongodb://localhost:27017/' + dbName);
var db = mongoose.connection;
db.on('error', function(err){
winston.log('debug', err);
});
router.route('/')
.post(function(req, res) {
var sighting = new Sighting();
sighting.user_key = req.body.user_key;
sighting.expertise = req.body.expertise;
sighting.phone_location = req.body.phone_location;
sighting.record_time = req.body.record_time;
sighting.audio_file_location = '/var/data/tjirp1244123.wav';
sighting.probable_species = [{species_name:'Bosaap', percentage:100}];
var error = '';
winston.log('debug', 'test');
// This does not get execute I suspect..
sighting.save(function(err) {
winston.log('debug', 'save');
if (err) {
winston.log('debug', err);
error = err;
}
});
res.json({
probable_species: probable_species,
expertise: req.body.expertise,
error: error
});
});
module.exports = router;
sighting.js (model)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var SightingSchema = new Schema({
user_key: String,
expertise: Number,
phone_location: { lat: Number, lng: Number },
record_time: Number,
audio_file_location: String,
probable_species: [{ species_name: String, percentage: Number }]
});
module.exports = mongoose.model('Sighting', SightingSchema);
Did you try updating your mongodb.
sudo npm update
You can try using promise.
return sighting.save().then(function(data){
console.log(data); // check if this executes
return res.json({
probable_species: probable_species,
expertise: req.body.expertise,
error: error
});
}).catch(function(err){
console.log(err);
});
One more thing dont use res.json outside the save function because in async code it will run without waiting for save function to complete its execution
While working with NodeJS project with mongoose for MongoDB, I used following code snippet to import all the mongoose models.
fs.readdirSync(modelsPath).forEach(function (file) {
require(modelsPath + '/' + file);
});
This worked flawlessly.
Recently, I started working on a Rubix project. It included a nodeJs server with ES6 code (using babel).
The above code snippet for importing mongoose models does not work.
On further experimentation, I found that for require(), variable is not allowed. If write the file path itself in require, i.e.
require('path/to/file'), it works. But if I do something like
var filePath = 'path/to/file';
require(filePath);
It stopped working. There was no error. It just hung before starting server.
Am I missing anything basic from ES6?
edit
Following is the content of module I'm trying to import
var express = require('express'),
router = express.Router(),
mongoose = require('mongoose'),
User = mongoose.models.User,
api = {},
auth = require('../utils/apiAuth'),
_ = require("lodash"),
apiResponse = require('../utils/apiResponse'),
apiErrors = require('../utils/apiErrors'),
config = require('../config/config'),
bcrypt = require("bcryptjs");
// ALL
api.users = function (req, res) {
console.log('here?');
User.find(function(err, users) {
if (err) {
return apiResponse.sendError(apiErrors.APPLICATION.INTERNAL_ERROR, null, 500, req, res);
} else {
return apiResponse.sendResponse(users, 200, req, res);
}
});
};
//.... other apis ....//
router.get('/users', api.users);
module.exports = router;
It works with all the previous projects I've worked with.
Could it have anything to do with Rubix?
Note: Too long, and would be impratical as a comment
Here is how I tried your code. Calling /users do print here?.
main.js:
'use strict';
//Dependencies
const express = require('express'),
app = express(),
t = './router.js';
app.use(require(t));
app.get('*', (req, res) => {
console.log('?');
res.end();
});
app.listen(2219);
router.js:
'use strict';
//Export
var express = require('express'),
router = express.Router(),
api = {};
// ALL
api.users = function (req, res) {
console.log('here?');
res.end();
};
//...
router.get('/users', api.users);
//...
module.exports = router;
I'm using Node.js, Express.js, and node-serial port. Call to get the list of serial ports is asynchronous and I'm trying to make it synchronous with Fibrous, but can't get it to work. Here's the code:
var express = require('express');
var serialPort = require("serialport");
var fibrous = require('fibrous');
var app = express();
...
app.post('/', function(req, res, next) {
console.log('before execution');
detectDevices.sync();
console.log('after execution')
});
...
var detectDevices = fibrous(function() {
var ports = serialPort.sync.list();
console.log('mfg='+ports[0].manufacturer);
});
Error says "Can't wait without a fiber". I've tried to use 'Futures' from Fibrous and some other example, but can't make it work in the POST handler of Express.js. What is the proper way to have my detectDevices execute synchronously in the app.post() function?
Mike S is correct. The following code works very well:
var express = require('express');
var serialPort = require("serialport");
var fibrous = require('fibrous');
var app = express();
app.use(fibrous.middleware);
...
app.post('/', function(req, res, next) {
console.log('before execution');
detectDevices.sync();
console.log('after execution')
});
...
var detectDevices = fibrous(function() {
var ports = serialPort.sync.list();
for (var i = 0; i < ports.length; i++) {
console.log(port.comName);
console.log(port.pnpId);
console.log(port.manufacturer);
}
});