Mocha before hook is not working with chai-http - javascript

This is my test code. I'm testing an API. The problem is the "after" hook is working and dropping database after the test ends. But the "before" hook is not working. what's the issue here? I tried but unable to find out the issue. I tried to run the before hook with only one dummy test like logging something in the console. Didn't work either.
const chai = require('chai');
const { assert } = require('chai');
const chaiHttp = require('chai-http');
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
require('../resolvedir');
const User = require('models/User');
const server = require('bin/www');
const testData = require('./test_data');
chai.use(chaiHttp);
describe('Empty User Collection before test', function () {
it('should drop User Collection before test starts', function () {
before(function (done) {
User.collection.drop();
done();
});
});
});
describe('Testing /registration end point', () => {
it('should return a valid JWT token', (done) => {
chai.request(server)
.post('/register')
.send({ name: testData.name, email: testData.email, password: testData.password })
.end((err, res) => {
assert.equal(res.status, 200, 'Http response code is 200');
assert.exists(res.body.auth, 'Auth confirmation message exist');
assert.isTrue(res.body.auth, 'Auth confirmation message is true');
assert.exists(res.body.token, 'JWT token is neither null or undefined');
assert.isString(res.body.token, 'JWT token is string');
done();
});
});
it('should fail registration', (done) => {
chai.request(server)
.post('/register')
.send(testData)
.end((err, res) => {
assert.equal(res.status, 409, 'Http response code is 409');
assert.isString(res.body.message);
assert.equal(res.body.message, 'User Exist');
done();
});
});
});
describe('Testing /login end point', function () {
it('should get a valid JWT token on successful login', function (done) {
chai.request(server)
.post('/login')
.send({ email: testData.email, password: testData.password })
.end((err, res) => {
assert.isString(res.body.token, 'JWT token is string');
done();
});
});
});
describe('Empty User Collection after test', function () {
it('should drop User Collection after test ends', function () {
after(function (done) {
User.collection.drop();
done();
});
});
});

Mongoose and MongoDB support promises. chai-http supports promises as well.
before should reside inside describe block, not inside it.
Mocha supports promises for asynchronous blocks, no done is necessary. But the tests use done and in inconsistent way. before is asynchronous, but done() is called synchronously. done() is called only on success in tests, when assertion fails this results in test timeout.
It should be:
describe('Empty User Collection before test', function () {
before(function () {
return User.collection.drop();
});
it('should drop User Collection before test starts', function () {
...
});
});
And
it('should get a valid JWT token on successful login', function () {
return chai.request(server)
.post('/login')
.send({ email: testData.email, password: testData.password })
.then((res) => {
assert.isString(res.body.token, 'JWT token is string');
});
});
And etc.
If a database should be dropped in Testing /registration end point test suite, there should before that drops a database as well - or all tests can have parent describe with before:
describe('Suite', function () {
before(function () {
return User.collection.drop();
});
describe('Testing /registration end point', () => {...})
describe('Testing /login end point', () => {...})
...
});

Related

How to make mocha wait before moving to the next test

When i ran npm test i got a 'TypeError [ERR_HTTP_INVALID_HEADER_VALUE]: Invalid value "undefined" for header "x-access-token"' error. Seems like mocha moves on to the second test before getting the token. I tried adding a delay with the setTimeOut method but i still got the above error.
// creates valid-user object
const validUser = {
username: 'Rigatoni',
email: 'yahoo.com',
password: 'qwerty1234567',
};
describe('Post Tests', () => {
// login and get token...
let token;
before((done) => {
request(app)
.post('/api/v1/auth/login')
.send(validUser)
.end((err, res) => {
// eslint-disable-next-line prefer-destructuring
token = res.body.token;
console.log('token', token);
expect(res.status).to.equal(200);
});
// console.log('token test');
done();
});
describe('GET all posts', () => {
it('should return all posts', (done) => {
request(app)
.get('/api/v1/posts')
.set('x-access-token', token)
.end((err, res) => {
expect(res.body.success).to.equal(true);
});
done();
});
});
});
Your tests are almost right!
The done callback is provided to let Mocha know when it's OK to move on. However, you are calling done() in your tests right after calling the asynchronous request method; Mocha thinks the test is done before you even make the request.
Move your done() call for each test into a callback function (for example, on the line right after your expect()), so that it isn't executed until after the request completes. Then Mocha will wait until the test is over before moving on.
Example:
request(app)
.get('/api/v1/posts')
.set('x-access-token', token)
.end((err, res) => {
expect(res.body.success).to.equal(true);
done();
});

Mocha test fail ensure don() is called

Hi I have strange problem while testing code with Mocha:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves
Here is code:
describe('POST /notes', () => {
it('should create new note', (done) => {
const title = 'Test title';
const text = 'Test text';
const category = 'Test category';
request(app)
.post('/notes')
.send({title, text, category})
.expect(200)
.expect(res => {
expect(res.body.title).toBe(title);
})
.end((err, res) => {
if (err)
return done(err);
Note.find({text: text}).then(notes => {
expect(notes.length).toBe(1);
expect(notes[0].title).toBe(title);
done();
}).catch(err => done(err));
});
});
it('should not create new note with invalid body data', done => {
request(app)
.post('/notes')
.send({})
.expect(400)
.end((err, res) => {
if (err)
return done(err);
Note.find().then(notes => {
expect(notes.length).toBe(notesDummy.length);
done();
}).catch(err => done(err));
});
})
});
First test fails with error described above. As it comes to the second, it passes. Both tests are similar and I don't know what I am missing... Any ideas ?
If you are interacting with a live database, it's possible that the operation just takes longer than 2 seconds to complete. The test for a successful operation would take longer than the negative test if you have server-side validation happening before interacting with the database.
You can extend the timeout in mocha using this.timeout(<some number in milliseconds>) :
it('should create new note', (done) => {
this.timeout(9000); // set it to something big to see if it fixes your issue
const title = 'Test title';
const text = 'Test text';
const category = 'Test category';
request(app)
.post('/notes')
.send({title, text, category})
.expect(200)
.expect(res => {
expect(res.body.title).toBe(title);
})
.end((err, res) => {
if (err)
return done(err);
Note.find({text: text}).then(notes => {
expect(notes.length).toBe(1);
expect(notes[0].title).toBe(title);
done();
}).catch(err => done(err));
});
});
The only other thing I can think of is that your server side code is hanging somewhere and not sending a response (or that Notes.find() is not resolving or rejecting for some reason). Your test code looks fine to me.
I'm not 100% sure that the expects outside of promise-land at the beginning will cause done to be called if they fail:
.expect(200)
.expect(res => {
expect(res.body.title).toBe(title);
})
Maybe add some logging to see whether it ever gets to your .end handler?
Also, what are you importing to get .expect methods on your request? We should look at its docs to see about done hooks.

module.exports = Promise.all not working inside tests

I want to just make sure that my server is running before I create PR's locally to test that nothing is broken.
worker.js
My server exports a promise
module.exports = Promise.all([
hbsPartialsLoaded,
])
.then(() => {
let server;
if (!isTestEnvironment) {
server = app.listen(config.port);
}
return { server, app };
});
tests
let { expect, request } = require('chai')
.use(require('chai-http'))
.use(require('chai-cheerio'));
const config = require('../../app/config');
const worker = require('../../app/worker');
describe('server response', function () {
worker.then(() => {
before(function () {
server.listen(config.port);
});
it('should return 200', function (done) {
request.get(`http://localhost:${config.port}`, function (err, res, body){
expect(res.statusCode).to.equal(200);
done();
});
});
after(function () {
worker.close();
});
})
});
Running Tests
NODE_ENV=test mocha --timeout 20000 --recursive test/ --compilers js:babel-core/register
0 passing (1ms)
My tests are never run. How can I get it so I wait for sever.js to finish its promises before the tests are run?
You didn't export the promise correctly, so the calling is bad, because you may not get callback if the require("worker.js") finished before calling .then, it should be worker().then not worker.then, but that's not the only problem.
The worker.js should return a function that launches the Promise.all. So change the module.exports = Promise.all... to module.exports = () => Promise.all...
Use before to launch the server and call it synchronously. Inside it you can use the asynchronous functions as you want.
The server.listen has a callback on second argument, that tells you when it finishes, so you can use promise and resolve it there.
An example:
var expect = require('chai').expect;
describe('x', () => {
before(() => new Promise((resolve, reject) => setTimeout(resolve, 500)));
it('should work', (done) => setTimeout(() => expect(0).to.be.above(0), 500));
});
Better example for your case:
var expect = require('chai').expect;
var app = require('express')();
describe('x', () => {
before(() => new Promise((resolve, reject) => {
app.listen(3000, () => {
console.log('The server launched');
resolve();
});
}));
it('should work', (done) => {
console.log('I got called after the server got launched! :)');
setTimeout(() => expect(1).to.be.above(0), 500)
});
});
it() functions should be called directly inside describe(). Nested inside a promise doesn't read well nor follow the standard testing process
let { expect, request } = require('chai')
.use(require('chai-http'))
.use(require('chai-cheerio'));
const config = require('../../app/config');
const worker = require('../../app/worker');
describe('server response', function () {
before(function () {
server.listen(config.port);
});
it('should return 200', function (done) {
worker.then(() => {
request.get(`http://localhost:${config.port}`, function (err, res, body){
expect(res.statusCode).to.equal(200);
done();
});
})
});
after(function () {
worker.close();
});
});

Properly stubbing request/response with Sinon/Mocha

I'm relatively new to unit-testing on the backend and need some guidance as to how to unit-test the following. I'm using Mocha/Should/Sinon.
exports.get = function(req, res) {
if (req.query.example) {
return res.status(200).json({ success: true });
} else {
return res.status(400).json({error: true});
}
}
You can use Sinon's spy and stub functions to test your code like this:
const { spy, stub } = require('sinon');
const chai = require('chai');
chai.should();
describe('the get function', () => {
let status,
json,
res;
beforeEach(() => {
status = stub();
json = spy();
res = { json, status };
status.returns(res);
});
describe('if called with a request that has an example query', () => {
beforeEach(() => get({ query: { example: true } }, res));
it('calls status with code 200', () =>
status.calledWith(200).should.be.ok
);
it('calls json with success: true', () =>
json.calledWith({ success: true }).should.be.ok
);
});
describe('if called with a request that doesn\'t have an example query', () => {
beforeEach(() => get({ query: {} }, res));
it('calls status with code 400', () =>
status.calledWith(400).should.be.ok
);
it('calls json with error: true', () =>
json.calledWith({ error: true }).should.be.ok
);
});
});
In the first beforeEach call, I'm creating a stub named status and a spy named json.
The status stub is used to test if the status method of the response is called with the correct response code.
The json spy is used to test if the json method of the response is called with the correct JSON code.
Note I'm using stub for status to be able to return the mock response from any call that goes to the status method, otherwise the chaining (res.status().json()) would not work.
For json it suffices to use a simple spy, because it is at the end of the chain.

Mocha: Multiple "it" calls in single server request

I'm trying to test 40+ API endpoints using Mocha. I would like to perform a few subtests as a part of a single server call.
For example, I would like to test if it('returns valid JSON... and it('returns a valid status code..., etc.
configs.forEach(function(config) {
describe(config.endpoint, () => {
it('...', function(done) {
server
.post(config.endpoint)
.send({})
.expect('Content-type', /json/)
.expect(200)
.end(function(err, res) {
//it('has a proper status code', () => {
expect(res.status).toEqual(200);
//})
//it('does not have an error object', () => {
expect(res.body.hasOwnProperty('error')).toEqual(false);
//})
done();
})
})
})
})
The problem is that I cannot nest it statements, but I am relying on the callback, via done() to dictate when the response has been received, so I have to wrap the call in an it statement...
Because some of these requests take half of a second to resolve, and there are 40+ of them, I don't want to create separate tests for these. Creating separate tests would also duplicate the config.endpoint, and I'd like to see if the tests are passing for each endpoint all in one place.
How can I create multiple tests for a single server call?
Here's how I accomplished this, using mocha, chai, and supertest (API requests):
import { expect } from "chai"
const supertest = require("supertest");
const BASE_URL = process.env.API_BASE_URL || "https://my.api.com/";
let api = supertest(BASE_URL);
describe("Here is a set of tests that wait for an API response before running.", function() {
//Define error & response in the 'describe' scope.
let error, response;
//Async stuff happens in the before statement.
before(function(done) {
api.get("/dishes").end(function(err, resp) {
error = err, response = resp;
done();
});
});
it("should return a success message", function() {
console.log("I have access to the response & error objects here!", response, error);
expect(response.statusCode).to.equal(200);
});
it("should return an array of foos", function() {
expect(response.body.data.foo).to.be.an("array");
});
});
configs.forEach(function(config) {
describe(config.endpoint, () => {
var response;
it('...', function(done) {
server
.post(config.endpoint)
.send({})
.expect('Content-type', /json/)
.expect(200)
.end(function(err, res) {
response=res;
done();
})
});
it('has a proper status code', () => {
expect(response.status).toEqual(200);
})
it('does not have an error object', () => {
expect(response.body.hasOwnProperty('error')).toEqual(false);
})
})
})
What about this ?
I am not sure about nesting of test cases but it will work for u.

Categories

Resources