Mocha tests timeout although the post client works well - javascript

I always get this error
Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
idk what's wrong with mocha tests hope someone helps (the post client works tho)
controller.js
module.exports.get_post_tags = (req, res) => {
PostTag.find({})
.then(tags => res.json(tags))
.catch(err => {
console.error(err)
res.send('An error happened while getting the data please try again later')
})
}
api.js
// #method GET
// #route /api/posttag
// #desc get all post tags
router.get('/posttags', get_post_tags)
unit_tests.js
describe('PostTag', function() {
it('Get all post tags', function(done) {
chai.request(app)
.get('/api/posttags')
.end((err, res) => {
expect(res).to.have.status(200)
done()
});
});
}

Related

Execution flow using next()

I am new to express and have a question about mechanics of next() function.
Am I correct that once next() is called it immediately triggers execution of app.get, whilst everything below next() will be executed asynchronously?
If so, why 'Am I executed?' is not printed to console once I put big delay in setTimeout()?
Please explain execution flow in the code below.
app.param('seriesId', (req, res, next) => {
... // Check for presence of series
console.log('I am executed');
next();
setTimeout(() => {console.log('Am I executed?')}, 1000); // Prints for 100, does not print for 1000
});
app.get('/:seriesId', (req, res, next) => {
... // Call to db to get series object
res.status(200).json({series: series});
});
Calling next() will handle control over to the next middleware in the pipe. In your example, this would be the app.get.
However, the method does not behave like a return statement, so any code you put after, will get executed too.
Given the example below, if you would start the server and navigate to http://localhost:1337/foo, the log statements would be:
well here we are
executing the get
const express = require('express');
const app = express();
app.param('param',(req, res, next) => {
next();
setTimeout(() => console.log('well here we are'), 1000);
});
app.get('/:param', (req, res) => {
setTimeout(() => {
console.log('executing the get');
res.status(200).send();
}, 2000);
});
app.listen(1337);
console.log('app started at http://localhost:1337');
Branching in middleware
A good practice to avoid confusion, is to make sure calls to next() are placed at the end of your execution. For example, don't do this:
if(aCondition) {
next()
}
next(new Error('Condition was false'));
But do:
if(aCondition) {
next()
} else {
next(new Error('Condition was false'));
}
Alternatively, what I do is always return next() calls, to avoid middleware from executing any further code.
Executing async code in middleware
And a final remark: if you need to execute asynchronous code in your middleware, then only call next() once this code has finished executing.
Don't do:
loadUserFromDB()
.then(u => req.user = u);
next();
But do:
loadUserFromDB()
.then(u => {
req.user = u;
next();
});

express, mocha testing always returns 404

My express POST route is:
app.post("/addPost", function(req, res) {
let newComment = { post: req.body.createP, comment: req.body.createC };
myDB.push(newComment);
res.render("index.ejs", { posts: myDB });
});
And my mocha test
describe("POST /", function() {
it("it ", function(done) {
supertest(myApp.app)
.post("/")
.expect(200)
.end(function(err, res) {
if (err) return done(err);
done();
});
});
});
Manually, the POST route works fine, but the mocha test always returns 404 instead of 200. Also, the mocha test for GET routes does work. Any ideas whats causing this?
Plus, how would one test html form data being sent via a POST request. Thanks in advance!

Using chai to mock http requests

I'm testing a nodejs app written using express. For the unit testing I'm using chai and sinon. I have the following route in my API that I would like to test.
In my test, I'm simulating the get request with the following code:
chai.request(app)
.get('/downloads')
.send({ wmauth: {
_identity: {
cn: "username",
}
} })
.end((err, res) => {
res.status.should.be.equal(200);
res.body.should.be.a('object');
res.body.should.have.property('Items', []);
AWS.restore('DynamoDB.DocumentClient');
done();
However, I'm always getting the error "Cannot read property '_identity' of undefined". Because the object "wmauth" is not sent in the request, so it is undefined. I have tried to use the send method to try to include it in the request, but no luck. I guess I need to mock it somehow and send it into the request but have no idea how to do it. Could someone help me with this?
Below the method to test:
app.get('/downloads', async (req, res) => {
const created_by_cn = req.wmauth['_identity'].cn;
if(!created_by_cn) {
return res.status(400).json({
error: 'Mandatory parameters: created_by_cn',
});
}
try {
const data = await downloadService.getDownloads(created_by_cn);
return res.status(200).json(data);
}
catch(error){
res.status(500).json({error: error.message});
}
});
THanks
I guess you forgot to use req.body as in:
const created_by_cn = req.body.wmauth['_identity'].cn;
Hope can solve your issue
Since chai-http use superagent, so according to its doc, you need to use query() in order to pass query parameter in get request:
chai.request(app)
.get('/downloads')
.query({ wmauth: {_identity: {cn: "username"}}})
.end((err, res) => { ... });
Then in the express route you can find the parameters in req.query:
app.get('/downloads', function (req, res) {
const created_by_cn = req.query.wmauth._identity.cn;
...
})

In Express.js, should I return response or not?

For Express.js 4.x I can't find wether I should return the response (or next function) or not, so:
This:
app.get('/url', (req, res) => {
res.send(200, { message: 'ok' });
});
Or this:
app.get('/url', (req, res) => {
return res.send(200, { message: 'ok' });
});
And what is the difference?
I do not agree with the answer above.
Sometimes the callback function can return several responses depending on the logic of the app:
router.post("/url", function(req, res) {
// (logic1)
res.send(200, { response: 'response 1' });
// (logic2)
res.send(200, { message: 'response 2' });
}})
This will throw this error:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent
to the client
Which can actually be solved with using return. It can also be solved with using if else clauses.
You don't. The (req, res) signature tells express this is the last function in the chain, and it does not expect a return value from this function. You can add a return statement, but it won't "do anything", beyond the JS engine performing some additional (but meaningless) overhead.
It depends.
Calling the res or req callback doesn't mean your routing function is gonna stop working
app.get('/url', (req, res) => {
if (true) {
res.send(200, { message: 'ok' });
}
const newFunction = () => {
// stuff useless to your routing function
}
newFunction()
});
In here the newFunction() is gonna get called and it's useless, it's gonna impact your server performances.
you better use return res.send(200, { message: 'ok' }); everytime, except if you wanna make a process in the background...
A process typically that can't be expected more than the classical 30 seconds http request. (Me I am making one that takes 4 or 5 hours everyday for example :D)

Mongoose open connection issue with Supertest

I am unable to run multiple Supertest/Mocha tests as I get an error Error: Trying to open unclosed connection. - I found this post which suggest looping and checking connection status. Wondering if there is a better way? perhaps something that was added in Supertest recently to handle this.
In your Mocha tests add a before function to connect to MongoDB like so
var mongoose = require('mongoose');
describe('My test', function() {
before(function(done) {
if (mongoose.connection.db) return done();
mongoose.connect('mongodb://localhost/puan_test', done);
});
});
Ok - was pretty close. What I had to do was remove the describe method call and place a before() call in a common file to all tests - supertest or just straight mocha unit tests.
var db;
// Once before all tests - Supertest will have a connection from the app already while others may not
before(function(done) {
if (mongoose.connection.db) {
db = mongoose.connection;
return done();
}
db = mongoose.connect(config.db, done);
});
// and if I wanted to load fixtures before each test
beforeEach(function (done) {
fixtures.load(data, db, function(err) {
if (err) throw (err);
done();
})
});
By omitting the describe() call the above it makes it available to all tests.
// Also you can use the 'open' event to call the 'done' callback
// inside the 'before' Mocha hook.
before((done) => {
mongoose.connect('mongodb://localhost/test_db');
mongoose.connection
.once('open', () => {
done();
})
.on('error', (err) => {
console.warn('Problem connecting to mongo: ', error);
done();
});
});

Categories