Mocha unit test for Promise throws error - node.js

I'm trying to unit test a promise. Here is the code :
it('it should return some 10 user data with ok status code when called with url ', (done) => {
return user.getUsers('https://jsonplaceholder.typicode.com/users')
.then((response) => {
console.log('me here')
assert.equal(JSON.parse(response).length, 10)
})
.catch((err)=>{
console.log('me in error')
assert.fail('err')
})
})
The above code when run throws the following error :
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (C:\Users\ajay\jay-workspace\UniTestModule\test\user.test.js)

done isn't called, this results in test timeout.
Mocha natively supports promises. done shouldn't be used when there are promises; instead, promises should be returned:
it('it should return some 10 user data with ok status code when called with url ', () => {
return user.getUsers('https://jsonplaceholder.typicode.com/users')
.then((response) => {
console.log('me here')
assert.equal(JSON.parse(response).length, 10)
});
})
Rejected promise will fail the test, no need for assert.fail as well.

You should call done() callback when using async testing (for details check https://mochajs.org/#asynchronous-code).
it('it should return some 10 user data with ok status code when called with url ', (done) => {
user.getUsers('https://jsonplaceholder.typicode.com/users')
.then((response) => {
console.log('me here')
assert.equal(JSON.parse(response).length, 10);
done();
})
.catch((err)=>{
console.log('me in error')
assert.fail('err');
done(err);
})

You should use --timeout hook and increase the number of ms like ./node_module/.bin/mocha test/ --timeout=5000
OR you can add this.timeout(5000) in the test case body
it('it should return some 10 user data with ok status code when called with url ', (done) => {
user.getUsers('https://jsonplaceholder.typicode.com/users')
.then((response) => {
console.log('me here')
assert.equal(JSON.parse(response).length, 10);
this.timeout(5000);
setTimeout(done, 3000);
})
https://mochajs.org/#test-level

Related

Why does my model creation timeout when run in jest but works fine from the server?

I'm learning how to use jest and have a very simple route I'm trying to test, that builds a small payload and creates a model, persisting to mysql.
describe('Validation Routes', function () {
beforeAll(async () => {
await db.sequelize.sync({ force: true })
})
test('responds to /createValidationField', async () => {
let payload = validationBody;
const res = await request(app)
.post('/api/validations/createValidationField')
.send(payload);
//.set('Content-Type', 'application/json');
//expect(res.header['content-type']).toBe('application/json; charset=utf-8');
expect(res.statusCode).toBe(200);
});
});```
This always results in
thrown: "Exceeded timeout of 30000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
12 | })
13 |
> 14 | test('responds to /createValidationField', async () => {
| ^
But if I make the request with the server running, the result is as expected.
Inside of the controller:
ValidationField.create(validationField)
.then(data => {
res.status(200).send({message: 'Validation Field creation successful: ' + data.id});
})
.catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while creating the Validation Field."
});
});
Interestingly, the model is making it to the database, even when the test itself timesout. I'm not sure why ValidationField.create would never return anything, the context of a test. Has anyone run into this before?
I'm using express 4.18.2, jest 29.3.1, supertest 6.3.3

Mocha isn't displaying any details for failed tests

I'm migrating an app from Sails.js v0.12 to v1.0, which includes upgrading mocha from ^3.5.0 to ^5.2.0. I assume that is the root of the issue, but I can't seem to find a fix.
Before, when a test failed, there would be a summary of the error at the end of the mocha reporter output: the specific assertion that failed, file name, line number, error message, etc. Now, the reporter is coloring the it block in red, but no additional details are show.
I've tried changing the reporter in mocha.opts, which works for the actual execution output, but nothing is enabling the summary at the end. What am I missing?
// ./test/integration/models/User.test.js
describe('User', () => {
describe('find()', () => {
it('should return an array of users', () => {
return User.find()
.then((users) => {
users.should.be.a('array');
true.should.be.false; // No problems if this is removed
});
});
});
});
In the console:
> node ./node_modules/mocha/bin/mocha test/lifecycle.test.js test/integration/**/*.test.js
√ OtherModel method() should do something: 17ms
1) User find() should return an array of users
'Done.'
PS C:\repos\myproject>
Turns out that Mocha is fine and my test definitions are fine, I had simply fixed a totally different migration issue incorrectly. Since version 4, mocha will no longer automatically kill itself when it thinks all tests are complete. This means that one of these two options must be used:
Add --exit to mocha.opts or to wherever the command is called
Run process.exit() in your test suite's JavaScript
I tried the second option by adding process.exit() to the after() block in my test bootstrap file. This is a bad idea and resulted in the confusing behavior above.
To solve my issue, I removed my changes to the after() block and added --exit to mocha.opts. Thanks to Dhruv Choudhary for pointing me in the right direction.
you can use done callback. The first strategy suggested in the mocha documentation is using the ‘done’ callback. This is an extra argument to the callback in the it . You call it after the last assertion in your test.
I have seen many people using done() method in wrong way. for example, look at below code,
describe('User', () => {
describe('find()', () => {
it('should return an array of users', (done) => {
return User.find()
.then((users) => {
users.should.be.a('array');
true.should.be.false; // No problems if this is removed
done();
});
});
});
});
The above test will work fine and show the test passing, But calling done() in the same then callback is a bad idea because The above code works well until your expectation fails, you might get error like
The above failure is not very useful . If we want to utilize the mocha’s error we shouldn’t call done() from the same then() callback. See the below test
describe('User', () => {
describe('find()', () => {
it('should return an array of users', (done) => {
return User.find()
.then((users) => {
users.should.be.a('array');
true.should.be.false;
})
.then(() => done(), done)
.catch((error) => {
done(error);
});
});
});
});
do not forget to wrap your error with catch block.
Now see the difference in the mocha’s failure message with actual and expected..
Please try adding done callback to your test case .
describe('User', () => {
describe('find()', () => {
it('should return an array of users', (done) => {
return User.find()
.then((users) => {
users.should.be.a('array');
true.should.be.false; // No problems if this is removed
done();
});
});
});
});

How to test a asynchronous server code using mocha chai?

In my mocha-test suite, I want to test a functionality which makes a asynchronous call behind the scene. How can I wait until the asynchronous call has finished ?
For example, I make two back to back post calls. The first post call also makes an asynchronous call internally, until that asynchronous operation is complete the second post call won't pass.
I need either of below:
1) to put a delay between the two post calls so that to make sure the asynchronous part in the first post is complete.
2) to make the second post call repetitively until it passes.
3) or how to test out the asynchronous call through mocha-chai ?
Below is the example:
describe('Back to back post calls with asynchronous operation', ()=> {
it('1st and 2nd post', (done) => {
chai.request(server)
.post('/thisis/1st_post')
.send()
.end((err, res) => {
expect(res.statusCode).to.equal(200);
/* HERE I Need A Delay or a way to call
the below post call may be for 5 times */
chai.request(server)
.post('/thisis/second_post')
.send()
.end((err, res) => {
expect(res.statusCode).to.equal(200);
});
done();
});
});
});
Is there a way to handle this ? Please help.
Thanks.
In order to test an asynchronous function with mocha you have the following possibilities
use done only after the last callback in your sequence was executed
it('1st and 2nd post', (done) => {
chai.request(server)
.post('/thisis/1st_post')
.send()
.end((err, res) => {
expect(res.statusCode).to.equal(200);
/* HERE I Need A Delay or a way to call
the below post call may be for 5 times */
chai.request(server)
.post('/thisis/second_post')
.send()
.end((err, res) => {
expect(res.statusCode).to.equal(200);
//call done only after the last callback was executed
done();
});
});
});
use done callback with promises
describe('test', () => {
it('should do something async', (done) => {
firstAsyncCall
.then(() => {
secondAsyncCall()
.then(() => {
done() // call done when you finished your calls
}
})
});
})
After a proper refactor you will get something like
describe('test', () => {
it('should do something async', (done) => {
firstAsyncCall()
.then(secondAsyncCall())
.then(() => {
// do your assertions
done()
})
.catch(done)
})
})
use async await, much cleaner
describe('test', () => {
it('should do something async', async () => {
const first = await firstAsyncCall()
const second = await secondAsyncCall()
// do your assertion, no done needed
});
})
An other moment to keep in mind is the --timeout argument when running mocha tests. By default mocha is waiting 2000 miliseconds, you should specify a larger amount when the server is responding slower.
mocha --timeout 10000

Ensure that done() callback is being called in this Mocha test

Looking at other questions, can't really find the cause of the problem. I am trying to test using mocha.
it("Should not do the work",function(done) {
axios
.post("x/y",{ id:a2 })
.then(function(res) {
assert(false,"Should not do the work");
done();
})
.catch(function(res) {
assert.equal(HttpStatus.CONFLICT,res.status);
done();
});
});
it("Should do the work",function(done) {
axios
.post("/x/y",{ id: a1 })
.then(function(res) {
done();
})
.catch(done);
});
The result was:
√ Should not do the work (64ms)
1) Should do the work
1 passing (20s)
1 failing
1) Error: Timeout of 20000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
Increasing the timeout didn't work.
Don't forget you can simply return a promise in Mocha and it will deal with it accordingly. In your first example are you sure those blocks are actually executed?
Doing an assertion may cause an exception, which can sabotage what you're trying to do. If your promise library supports it you can always:
it("Should not do the work",function(done) {
axios.post("x/y",{ id:a2 })
.then(function(res) {
assert(false,"Should not do the work");
})
.catch(function(res) {
assert.equal(HttpStatus.CONFLICT,res.status);
})
.finally(done);
});
Ensuring that should be done regardless.
Even better:
it("Should not do the work",function() {
return axios.post("x/y",{ id:a2 })
.then(function(res) {
assert(false,"Should not do the work");
})
.catch(function(res) {
assert.equal(HttpStatus.CONFLICT,res.status);
})
});
Watch for doing catches on assertions and assertions in catches. A better plan might be async:
it("Should not do the work", async function() {
var res = await axios.post("x/y",{ id:a2 })
assert.equal(HttpStatus.CONFLICT,res.status);
});

Test will not call done() when failing

I am writing a unit test to test my postgres schema. I am using node-pg, mocha, sinon, and chai.
This works - the test passes with no issues:
describe('When adding a user', ()=> {
it('should reject since email is used somewhere else', (done)=> {
pool.query(`INSERT INTO users(email, id, token)
VALUES($1, $2, $3)`, ['foo#email.com', '12346', 'fooToken'])
.then((result)=> {
console.log('nothing in here runs, you will not see this');
done()
})
.catch((result) => {
result.constraint.should.have.string('email_already_exists');
done();
})
})
});
But to make sure I am not getting a false positive, I change the assert to result.constraint.should.not.have.string('email_already_exists'); to purposely make the test fail.
Instead of the test failing, I get Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test..
What am I getting this?
If you would still like to use Promises for this, the problem is that unhandled exceptions in Promises are unfortunately not propagated but rather are silently ignored. As a result, no one calls Mocha's done method, leading to the timeout.
Attaching a listener to Node's unhandledRejection event as documented here should demonstrate this.
If you modify your original code and add a call to the Promise's done method (this isn't Mocha's done method!), then you'll be able to catch all errors and pass them to Mocha's done method:
it('tests something', done => {
pool.query('...')
.then(result => {
// ...
})
.catch(result => {
// assertion that fails
})
.done(result => {}, error => { done(error); });
});
Note that Promise.done() isn't (yet) part of the standard, but is nonetheless supported by many implementations. See for example here.
Answer:
The promise chain for node-pg causes this strange issue during testing. If I work off of callback, then no issue:
describe('When adding a user', ()=> {
it('should reject since email is used somewhere else', (done)=> {
function callback(err, result) {
err.constraint.should.not.have.string('email_already_exists');
done();
}
pool.query(`INSERT INTO users(email, id, token)
VALUES($1, $2, $3)`, ['foo#email.com', '12346', 'fooToken'], callback)
})
});

Resources