500 equals 400 passes in a mocha test? - node.js

Why does the following test pass?
"use strict";
const
path = require('path'),
Dexter = require('../src/Dexter.js'),
chai = require('chai'),
chaiHttp = require('chai-http'),
expect = chai.expect,
dexterServer = new Dexter(path.resolve(__dirname, 'test/data/sample.har'));
chai.use(chaiHttp);
describe('Rest API', () => {
before(() => {
dexterServer.startUp();
});
it('should\'ve started the server', function () {
chai.request('http://127.0.0.1:1121')
.get('/')
.end(function(err, response){
console.log(response.status);
expect(500).to.equal(400);// This passes? What?
done();
});
});
after(() => {
dexterServer.tearDown();
});
});
When I do a console.log of the response.status, I see a 200. But when I do
expect(response.status).to.equal(400);//response.status is an int
passes the test!
What am I doing wrong?

You forgot to pass done callback. it was treated as sync with 0 assumptions.
it('should\'ve started the server', function (done) {
chai.request('http://127.0.0.1:1121')
.get('/')
.end(function(err, response){
console.log(response.status);
expect(500).to.equal(400);// This passes? What?
done();
});
});

You have to pass done in it, before and after statement to maintain the asynchronous flow.
describe('Rest API', (done) => {
before(() => {
dexterServer.startUp();
});
it('should\'ve started the server', function (done) {
chai.request('http://127.0.0.1:1121')
.get('/')
.end(function(err, response){
console.log(response.status);
expect(500).to.equal(400);// This passes? What?
done();
});
});
after((done) => {
dexterServer.tearDown();
});
});

Mocha supports promises so you could use the fact that chai-http produces promises and just return the promise:
it('should\'ve started the server', function () {
// Return the promise.
return chai.request('http://127.0.0.1:1121')
.get('/')
// Use .then instead of .end.
.then(function(response){
console.log(response.status);
expect(500).to.equal(400);
});
});
If you need to do special processing of errors, you could have a .catch too. Otherwise, you can let Mocha handle any error as a failure.

Related

Getting “Error: Resolution method is overspecified”? in beforeEach and afterEach

When I use done in beforeEach or afterEach I get this error “Error: Resolution method is overspecified” and the test fails.
But now if remove the done() all my tests pass but the terminal hangs without exiting the test script.
I am using knex.js as a query builder.
Is there a solution to this problem?
beforeEach(async (done) => {
await db.migrate.rollback(migrationConfig);
await db.migrate.latest(migrationConfig);
await db.seed.run(seedConfig);
done();
});
// cleaning db before running tests
afterEach(async (done) => {
await db.migrate.rollback(migrationConfig);
done();
});
describe("POST /user/login", () => {
it("should return a jwt after loging in user", (done) => {
chai
.request(server)
.post("/user/login")
.send({
email: "saaransh#test.com",
password: "test123",
})
.end((err, res) => {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property("token");
done();
});
});
});
If you are using async handler functions, then you should not give it parameter done. Promise returned by async function will tell Mocha when executing the function is ready.
beforeEach(async () => {
await db.migrate.rollback(migrationConfig);
await db.migrate.latest(migrationConfig);
await db.seed.run(seedConfig);
});
// cleaning db before running tests
afterEach(async () => {
await db.migrate.rollback(migrationConfig);
});

why done runs earlier before supertest request on sequelize?

const request = require('supertest');
const app = require('../app');
request(app)
.get("/videos")
.expect(200)
.end(async (err,res) => {
if (err) {
console.error(err);
done();
} else {
console.log(res.body);
done(); // <- this is the question line
}
If I take off the done from the code, the test will print the result, but if I have done there, sequelize still print but there is no res.body print on the console.
Anyone knows why?
I think it's because of the asynchronous nature of javascript.
By default, Jest tests complete once they reach the end of their execution. That means this test will not work as intended:
const request = require('supertest');
const app = require('../app');
request(app)
.get("/videos")
.expect(200)
.end(async (err,res) => {
if (err) {
console.error(err);
// done();
} else {
console.log(res.body);
// done();
}
The problem is that the test will complete as soon as function completes asynchronosly.
Moving to, after putting done()
const request = require('supertest');
const app = require('../app');
request(app)
.get("/videos")
.expect(200)
.end(async (err,res) => {
if (err) {
console.error(err);
done();
} else {
console.log(res.body);
done();
}
And then, in that case, it waits for the done function before finishing the test.
For more details. Please check here.
I hope it helps. Thanks
Try to remove async from .end(async (err,res) => { line so the callback is not considered asynchronous anymore.

Why my Supertest test that should be failing is passing?

I'm starting my project based on this repo:
https://github.com/madhums/node-express-mongoose
The first thing I decided to do was write tests, so I went to the test file, and it looks something like this:
var mongoose = require('mongoose');
var should = require('should');
var request = require('supertest');
var app = require('../server');
var context = describe;
// other stuff you want to include for tests
before(function (done) {
// clear db and other stuff
done();
});
describe('Users', function () {
describe('POST /users', function () {
it('should create a user', function (done) {
request(app)
.post('/users')
.field('name', 'foo')
.field('email', 'foo')
.field('password', 'foo')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res){
console.log(err);
if(err){
console.log("error");
}
// console.log(res);
});
done();
});
});
});
after(function (done) {
// do some stuff
done();
});
I haven't actually created the route, so the test should be failing, and I even do get an error on .end, so any idea why is the test not failing?
My console shows me this when I run npm test
Express app started on port 3000
Users
POST /users
✓ should create a user
[Error: expected "Content-Type" matching /json/, got "text/html; charset=utf-8"]
error
1 passing (653ms)
The problem is that your test is asynchronous, but your code is synchronous. Specifically, the done() line is always called.
You need to move the done() line into the .end block, and add done(err) for the error case, like this:
.end(function(err, res){
if(err){
console.log("error");
done(err);
}
else {
console.log(res);
done();
}
});

Supertest + Express won't fail

This is more or less a duplicate of supertest test express middleware
but after a year, I figured I'd start a new question.
var express = require('express');
var request = require('supertest');
var app1 = express();
app1.get('/myapp', function (req, res) {
res.send(200, { name: 'myapp' });
});
request = request(app1);
it('should fail', function () {
request
.get('/hahahahahahahaha')
.expect(123);
});
As far as I can tell, that will always erroneously pass. The fact that the path is wrong and is expecting a different status code doesn't matter.
And - more generically (without Express), it looks like this always passes, also:
it('should fail', function () {
request('http://thisdoesnotexist.mydomain')
.get()
.expect(200);
});
This doesn't work either:
it('should fail', function () {
request('http://thisdoesnotexist.mydomain')
.get()
.expect(200)
.end(function (err, res) {
if (err) {
throw err;
}
});
});
Any thought as to why this happens, or how to actually test such a scenario?
With supertest you need to terminate your chain somehow.
expect will take a finished callback as the second parameter, and you can use the build in mocha callback for this. Like so:
describe('potato', function() {
it('should fail', function(done) {
request
.get('/hahahahahahahaha')
.expect(123, done);
});
});
Specifying a done option like this will instruct mocha to wait until it's heard back from you before proceeding to the next test.
The difference is the parameter: done
describe('XXX', function() {
it('XXX', function() {
// always passing
})
})
describe('YYY', function(done) {
it('YYY', function() {
// always passing
})
})
describe('ZZZ', function() {
it('ZZZ', function(done) {
// normal
})
})

How do I properly fail an async unit test in jasmine-node

Why does the following code fail with a timeout? It looks like 'should' throws an error and done() never gets called? How do I write this test so that it fails correctly instead of having jasmine reporting a timeout?
var Promise = require('bluebird');
var should = require('chai').should();
describe('test', function () {
it('should work', function (done) {
Promise.resolve(3)
.then(function (num) {
num.should.equal(4);
done();
});
});
});
console output is:
c:>jasmine-node spec\
Unhandled rejection AssertionError: expected 3 to equal 4
...
Failures:
1) test should work
Message:
timeout: timed out after 5000 msec waiting for spec to complete
Using .then() and only done()
it('should work', (done) => {
Promise.resolve(3).then((num) => {
// your assertions here
}).catch((err) => {
expect(err).toBeFalsy();
}).then(done);
});
Using .then() and done.fail()
it('should work', (done) => {
Promise.resolve(3).then((num) => {
// your assertions here
}).then(done).catch(done.fail);
});
Using Bluebird coroutines
it('should work', (done) => {
Promise.coroutine(function *g() {
let num = yield Promise.resolve(3);
// your assertions here
})().then(done).catch(done.fail);
});
Using async/await
it('should work', async (done) => {
try {
let num = await Promise.resolve(3);
// your assertions here
done();
} catch (err) {
done.fail(err);
}
});
Using async/await with .catch()
it('should work', (done) => {
(async () => {
let num = await Promise.resolve(3);
// your assertions here
done();
})().catch(done.fail);
});
Other options
You specifically asked about jasmine-node so that's what the above examples are about but there are also other modules that let you directly return promises from tests instead of calling done() and done.fail() - see:
https://www.npmjs.com/package/jasmine-promises
https://www.npmjs.com/package/jasmine-as-promised
https://www.npmjs.com/package/jasmine-promise-matchers
https://www.npmjs.com/package/jasmine-then
If you want to use Promises in your Mocha suite, you have to return it instead of using the done() callback, like:
describe('test', function () {
it('should work', function () {
return Promise.resolve(3)
.then(function (num) {
num.should.equal(4);
});
});
});
An even cleaner way to write that would be with chai-as-promised module:
describe('test', function () {
it('should work', function () {
return Promise.resolve(3).should.eventually.equal(4);
});
});
Just make sure to require it properly and tell chai to use it:
var Promise = require('bluebird');
var chai = require('chai');
var should = chai.should();
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);

Resources