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();
});
Related
So, I've got the following test using Jest and Supertest:
describe('GET /healthcheck', () => {
test('Should return 200 in the GET / health check', (done) => {
request
.get('/healthcheck')
.set({ correlationId: mock.correlationId, Accept: 'application/json' })
.expect('Content-Type', 'application/json; charset=utf-8')
.expect(200)
.end((err, res) => {
if (err) return err;
expect(res.body).toEqual(expect.objectContaining({status: 'UP'}));
return done();
});
});
And I'm getting the async timeout error. I'm also getting an EADDRIUSE, so it may be the cause of the timeouts, I don't know.
I've already tried to add some flags like runInBand and maxWorkers on jest, but none worked. I've tried adding async/await to the test call, and it didn't work as well. I added jest.setTimeout and it didn't work too. I may be getting out of options.
Hope someone can help me, thanks!
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.
Here are my HTTP routes
app.get('/', (req, res) => {
res.status(200).send('Hello World!')
})
app.post('/sample', (req, res) => {
res.status(200).json({
x:1,y:2
});
})
I would like to test for the following
1) GET request working fine.
2)the /sample response contains the properties and x and y
const request = require('supertest');
const app = require('../app');
describe('Test the root path', () => {
test('It should response the GET method', () => {
return request(app).get('/').expect(200);
});
})
describe('Test the post path', () => {
test('It should response the POST method', (done) => {
return request(app).post('/sample').expect(200).end(err,data=>{
expect(data.body.x).toEqual('1');
});
});
})
But I got the following error on running the test
Jest has detected the following 1 open handle potentially keeping Jest
from exiting:
return request(app).get('/').expect(200);
you need to call done() in the end() method
const request = require("supertest");
const app = require("../app");
let server = request(app);
it("should return 404", done =>
server
.get("/")
.expect(404)
.end(done);
});
This trick worked;
afterAll(async () => {
await new Promise(resolve => setTimeout(() => resolve(), 500)); // avoid jest open handle error
});
As described in this github issue.
Hi You can use the toEqual function as well
describe('Test the post path', () => {
test('It should response the POST method', () => {
return request(app).post('/sample').expect(200).toEqual({ x:1,y:2
});
});
})
There are lots of methods can be used instead.You can go throw the official documentation which covers every jest function https://jestjs.io/docs/en/expect
As a general tip to debug this error, add --detectOpenHandles to your npm script that runs Jest e.g.
"scripts": {
...
"test": "jest --detectOpenHandles"
}
This should tell you exactly which part of the code is causing the issue (probably some type of server connection, particularly if its async).
In general, if you can move the connection code to a separate function in a file outside of your tests, then import and call it in your tests, this will also fix the issue.
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', () => {...})
...
});
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.