'Body Parse' error for 404 test in Mocha + Supertest - node.js

I am trying to write tests to ensure that my Express API is correctly returning the right HTTP status codes for various scenarios. I am using Mocha, and Supertest for requests to the API in the tests. Right now I'm getting very unexpected results, which are detailed below.
Using: Express, body-parser, Sequelize, Mocha, Supertest
GET /users/:id
models.User.find(req.params.id).complete(function(err, foundUser) {
if (err) {
logger.error(err, 'Error');
return err;
}
console.log('user: ' + foundUser);
if (foundUser != null) {
res.json({ user: foundUser.getJsonRepresentation() });
}
else {
res.status(404);
res.json({ error: 'Not found' });
}
});
Tests for this method
it('responds with the right user', function(done){
request(app)
.get(apiPath + '/users/' + createdUser.id)
.set('Accept', 'application/json')
.expect(function(res) {
res.body.user.id.should.equal(createdUser.id);
})
.expect(200, done);
});
it('responds with the right error code for non-existent resource', function(done) {
request(app)
.get(apiPath + '/users/1000')
.expect(404, function(err, res) {
console.log(err);
console.log('Response: ' + res);
done();
});
});
For the 404 test, I get this error: { [Error: Parse Error] bytesParsed: 12, code: 'HPE_INVALID_STATUS' } in the callback. The res is undefined.
I have tried several different syntax forms for this expect call: .expect(404, function(err, res) { and none of them have worked. I've also tried all the different syntax forms for this as well:
res.status(404);
res.json({ error: 'Not found' });
Can anyone offer some insight into what is going on here?

Maybe the issue is in the following code snippet:
if (err) {
logger.error(err, 'Error');
return err;
}
It seems to be triggering the error but not actually returning it to the supertest client.
You can try to return the error to the client instead of only logging it, like this:
if (err) {
logger.error(err, 'Error');
res
.status(500);
.json({ error: error.message });
return err;
}

Related

API spec exits after first falling test Mocha + Chai + Express

I am using mocha for tests on a new project.
For a test file containing dummy express server all works fine. Here is the code:
describe('Our application', function() {
let app, server;
before(function(done){
app = createApp();
server = app.listen(function(err) {
if (err) { return done(err); }
done();
});
})
after(() => {
server.close()
})
it('should execute fail', function(done) {
request(app)
.get('/')
.set('Content-Type', 'application/json')
.expect(200, (err, res) => {
if(err) return done(err);
expect(res.body.success).to.equal('abcd');
done();
});
});
it('should execute fail', function(done) {
request(app)
.get('/')
.set('Content-Type', 'application/json')
.expect(500, (err, res) => {
if(err) return done(err);
expect(res.body.success).to.equal(true);
done();
});
});
it('should execute basic root request', function(done) {
request(app)
.post('/')
.set('Content-Type', 'application/json')
.send({a: 1})
.expect(200, (err, res) => {
if(err) return done(err);
expect(res.body.success).to.equal(true);
done();
});
});
});
I deliberately made all tests fail, but each is executed and I see the result:
Our application
1) should execute fail
2) should execute fail
3) should execute basic root request
0 passing (19ms)
3 failing
1) Our application
should execute fail:
Error: expected 200 "OK", got 400 "Bad Request"
...
However, when I run it for our server (use different logic in before and after hook to start/close server), the tests exit after first failure and show a different assertion error:
1) should fail when registering with email without top level domain
AssertionError: expected 'Invalid user information provided, or…' to deeply equal 'Invalid email provided'
at Test.<anonymous> (file:///Users/azildzic/scaleup/postmarket-backend/test/api/authentication/registration-spec.js:68:34)
at Test.assert (node_modules/supertest/lib/test.js:172:8)
at Server.localAssert (node_modules/supertest/lib/test.js:120:14)
at Object.onceWrapper (node:events:627:28)
at Server.emit (node:events:513:28)
at emitCloseNT (node:net:1880:8)
at process.processTicksAndRejections (node:internal/process/task_queues:81:21) {
showDiff: true,
actual: 'Invalid user information provided, or not every field provided',
expected: 'Invalid email provided',
operator: 'strictEqual',
uncaught: true
}
So in the first case I got Error, in the second I got AssertionError, why?
Also, in the first case there is no this part at the end of stack trace:
showDiff: true,
actual: 'Invalid user information provided, or not every field provided',
expected: 'Invalid email provided',
operator: 'strictEqual',
uncaught: true
Why?
It's worth mentioning that both test files are using mocha/chai/supertest. Also, the second test files has async actions defined in controller. Is this maybe a circuit breaker?
Any help is appreciated, as I'm quite new to mocha/chai and node.js in general

Send Server Response in bulks in express app

I am using the oracledb driver for my app combined with this library https://github.com/sagiegurari/simple-oracledb
I wish to send the results from my query in bulks, but I keep getting the error:
Error: Can't set headers after they are sent.
Here is my code:
router.get('/', function (req,res) {
"use strict";
oracledb.getConnection(connAttrs.database, function (err, connection) {
if (err) {
// Error connecting to DB
res.set('Content-Type', 'application/json');
res.status(500).send(JSON.stringify({
status: 500,
message: "Error connecting to DB",
detailed_message: err.message
}));
return;
}
connection.query("Select * from solvedtasks",{},{
splitResults: true, //True to enable to split the results into bulks, each bulk will invoke the provided callback (last callback invocation will have empty results)
bulkRowsAmount: 1000 //The amount of rows to fetch (for splitting results, that is the max rows that the callback will get for each callback invocation)
},
function onResults (err, results) {
if (err) {
res.set('Content-Type', 'application/json');
res.status(500).send(JSON.stringify({
status: 500,
message: "Error getting the user profile",
detailed_message: err.message
}));
} else if(results.length)
{
res.send(results);
}
else {
// Release the connection
console.log("done");
connection.release(
function (err) {
if (err) {
console.error(err.message);
} else {
console.log("GET /SolvedTasks : Connection released");
}
});
}
});
});
});
This error obviously happens because it keeps doing res.send(results) more than once. I get just the first 1000 rows and after that the error occurs. Any idea how to solve this, keep sending the results in bulks but not getting the error?

request params when using Mocha and Chai to test file node.js

In the code below, I use req.body to get param from request.
Now, I want get param by using req.user (or req.someName, ...) but I don't know how to do this.
it.only('updateEmail',function(done){
chai.request(server)
.post('updateEmail')
.send({
new_email: faker.internet.email()
})
.end(function(err, res){
if (err){
console.log('err: ', err)
done()
}
else {
console.log('res: ', res.body)
done()
}
});
});

Supertest mongoose query issue

I am using supertest, mocha and expect for testing my app. I encountered an issue where the document returned is null and there is no error.
router.get('/user', function (req, res) {
User.findOne({
_id: '56c59bb07a42e02d11a969ae'
}, function (err, user) {
if(err) return res.status(404).json({message: 'not found: ' + err.message});
res.status(200).json(user);
});
});
When I test this on Postman I always get 200 which is what I expected but when I run the test I get 404 :(
My simple test code below where I always get the 404.
it('get user', function (done) {
request(app)
.get('/user')
.expect(200)
.end(function (err, res) {
if (err) throw err;
done();
});
});
Both Postman and the test are referring to the same mongoose database so I'm sure that it should be able to fetch the user. How mongoose and the app are setup in my server below.
mongoose.connect('mongodb://localhost/scratch', options);
app.listen(port, function () {
console.log('Scratch started on port ' + port);
});
Is there something I need to do to make it work?
I modified the test a bit where the User is created on 'before'.
before(function (done) {
connection.on('error', console.error);
connection.once('open', function () {
done();
});
mongoose.connect(config.db[process.env.NODE_ENV]);
var userInfo = {
"username": "naz2#gmail.com",
"password" : "123456",
"nickname": "naz"
}
var newUser = User(userInfo);
newUser.save(function (err, doc) {
if(err) {
console.log('err: ' + err.message);
} else{
console.log('saved');
}
})
console.log(mongoose.connection.readyState);
done();
});
Then ran the same test and it worked!
My guess is that during the test the app is querying against documents in memory( I verified that by checking the db and the new user was not added) and not to an existing document like I was expecting when testing with Postman. Which means I need to seed the test db first before I can use it for the test.
I am new to Nodejs and I'm curious to what caused the documents to be created in memory and how mongoose/express know that it is ran by a test/supertest and behave accordingly.

NodeJS, Is it a bad practise to return res.json

I'm building a ExpressJS application with NodeJS. My question is there any performance difference if I do
app.get('/test', function(req, res) {
fn(function(err, data) {
if (err) {
return res.json(400, {
error: 1,
msg: "some error"
});
}
///more code
});
});
instead of
app.get('/test', function(req, res) {
fn(function(err, data) {
if (err) {
res.json(400, {
error: 1,
msg: "some error"
});
return;
}
///more code
});
});
Do returning the res variable make any addition load on the server. Both codes work, just the first looks better to me and I save 1 line.
On the contrary, I think many would tell you this sort of idiom is a very sound practice as it makes clear to the reader (often your future self) that you are exiting). What is very nice about the strategy in this particular case is that you can save a bit more code since you now only have a single statement in your conditional branch, which means you can lose some curly braces.
app.get('/test', function(req, res) {
fn(function(err, data) {
if (err) return res.json(400, {
error: 1,
msg: "some error"
});
///more code
});
});
But you asked if there was a performance difference. If there is, I think it would be all but imperceptible.
Returning an object in a function don't make additional load.
On your exemple, based on callback function, there is no difference.
But what if app.get return a Promise ?
This code will provide an Unhandled rejection Error
app.get('/test')
.then( (data) =>
{ /* do something with your data that can throw a functional error
for exemple request for a user on your database based on your data */
if (!user) res.json(401, {msg: 'USER NOT FOUND'});
if (user.someProperty) //will throw an error when user is not found
res.json(200, {msg: 'USER DID IT'});
})
.catch( (err) => {
res.json(500, {msg: 'OUTCH'});
throw(err);
});
This code will not
app.get('/test')
.then( (data) =>
{ /* do something with your data that can throw a functional error
for exemple request for a user on your database based on your data */
if (!user) return res.json(401, {msg: 'USER NOT FOUND'});
if (user.someProperty) //will not be evaluate when user is not found
return res.json(200, {msg: 'USER DID IT'});
})
.catch( (err) => {
res.json(500, {msg: 'OUTCH'});
throw(err);
});
When using promise always return ;)

Resources