Mocha call all "it" callbacks simulations (Testing middleware) - node.js

I try to test a middleware in mocha.
The problem is, that all "it" calls waiting for the previous one to finish, before executing their callback.
it(`should trigger pre hook 1`, (done) => {
use((next) => {
setTimeout(() => {
done();
next();
}, 1000);
});
});
it(`should trigger pre hook 2`, (done) => {
use((next) => {
setTimeout(() => {
done();
next();
}, 1000);
});
});
start(() => {
// middleware done
});
The second it(...) waits for the first to complete.
And thats exactly the problem, since the second use(...) is not called before i fire the start(...) function, so it never gets executed and the test fails.
How can i tell mocha to execute all "it" callbacks and wait not for the previous one to complete (or fails)?

Try a spy instead of done so you can layout the tests as needed without relying on mocha to control the flow.
describe('middleware', function(){
// initialise use/start for this test
const m1 = sinon.spy()
const m2 = sinon.spy()
use((next) => {
setTimeout(() => {
m1();
next();
}, 1000);
});
use((next) => {
setTimeout(() => {
m2();
next();
}, 1000);
});
it(`should process a request through middleware`, function(done){
start(() => {
// middleware done
expect(m1.calledOnce, `m1`).to.equal(true)
expect(m2.calledOnce, `m2`).to.equal(true)
done()
});
})
})
The spy will also let you check on more complex call scenarios in the middleware when you have functional code in there.

Related

Unit test promise result inside Event Listener in Node

I have the following code that I want to test.
emitter.on("request", function(req, res) {
mock_finder.getMockedResponse().then((mockedResponse) => {
res.end(mockedResponse);
});
});
Then, I have this unit test.
it("should return mocked response", () => {
// given
const mockedResponse = {
success: true
};
mock_finder.getMockedResponse.mockImplementation(() => Promise.resolve(mockedResponse));
const res = {
end: jest.fn()
}
// when
emitter.emit('request', req, res);
// then
expect(res.end).toHaveBeenCalledWith(mockedResponse);
});
This test is not working because res.end(mockedResponse); is executed after the test finishes.
How can I test the promise response after an event is called?
Given there's no real async code going on here, you can verify the result on the next tick:
if('should return mocked response', done => {
...
emitter.emit('request', req, res);
process.nextTick(() => {
expect(res.end).toHaveBeenCalledWith(mockedResponse);
done()
});
})

Node.js: Run mocha tests in a request callback

I want to run some tests whose settings need to be downloaded first via a HTTP GET.
My download is successful but my test does not run when it's inside the request callback. I know it's not the best structure but I'd also like to know why this is not working.
describe('test', () => {
request.get({
url: 'https://google.com',
}, (err, status, body) => {
// The content is downloaded successfully.
console.log(body);
// This test never runs, why?
it('should be able to run inside a request.get', () => {
});
});
});
I know this code works but I would still like to know why the previous example does not.
describe('test', () => {
it('should be able to run inside a request.get', () => {
request.get({
url: 'https://google.com',
}, (err, status, body) => {
console.log(body);
});
});
});
EDIT: The suggestion provided by Jankapunkt's comment works: Moving the 'it' and 'describe' together allows for a successful download and test run.
request.get({
url: 'https://google.com',
}, (err, status, body) => {
// The content is downloaded successfully.
console.log(body);
// The describe and it are within the same closure.
describe('test', () => {
// This test runs successfully.
it('should be able to run inside a request.get', () => {
});
});
});
Old subject but I did like this for a Mock mongo connection:
const manager = require('./manager')
const assert = require('assert')
const MongoClient = require('./MockMongo')
let conn
describe('test execution', function() {
it('db connection', function (done) {
MongoClient.connect('test url')
.then((db) => {
conn = db
done()
})
})
it('test 1', function (done) {
manager.methodOfManager(conn, 'param1', 'param2')
.then(r => {
assert.equal(r.result, 'ok')
done()
})
.catch(err => {
console.log(err.message)
done(err)
})
})
})
It will print:
test execution
✓ db connection (5ms)
✓ Test 1 (sepa) (125ms)
2 passing (0s)
Approach 1: Tests inside your GET result
Use describe() around the it() within the callback function and avoid arrow functions like the following:
it("...", () => {});
It is discouraged in mocha when you have changing contexts.
Instead use
it("...", function(){});
and use .bind , done() or promises when required in async tests.
Putting this together into your code example, you may find your code to be similar to the following:
request.get({
url: 'https://google.com',
}, (err, status, body) => {
// The content is downloaded successfully.
describe('test', function() {
it('should be able to run inside a request.get', function() {
assert.isDefined(status);
assert.isDefined(body);
//...and so on
});
});
});
By the way - it is only a bad structure if for your approach is a better structure available.
Approach 2 - Wrap request.get in your unit
This is (in my opinion) the better and more mocha-like approach, where you execute the request inside the test and use the done() callback to notify mocha, that you are done:
describe('test', function() {
let request;
beforeEach(function(){
// request = ...
});
it('should be able to get a request result', function(done) {
request.get({
url: 'https://google.com',
}, (err, status, body) => {
assert.isDefined(status);
assert.isDefined(body);
//...and so on
// at the end call done
done();
});
});
You can ensure that request is initialized each test as a new fresh instance by using the beforeEach hook.

Multiple before() or beforEach() in mocha

I need to do multiple async calls in before() hook in mocha. I need to delete a user, then signup , verify email and finally login to get token to authenticate all other test cases. Here is my code snippet :
const userInfo = {
"password": "pass123",
"email": "test#email.com",
};
var token = '' , userId = '';
before((done) => {
// Delete the user if already exists
User.remove({
email: userInfo.email
}).then((res) => {
// console.log(res.result);
})
.end(done);
done();
});
before((done) => {
request(app)
.post('/api/users')
.send(userInfo)
.expect(200)
.expect((res) => {
})
.end(done);
});
before((done) => {
User.findOne({
email: userInfo.email
}).then((res) => {
userId = res._id;
request(app)
.post('/api/users/verify-email')
.send({'token' : userId})
.expect(200)
.expect((res) => {
})
.end(done);
})
.end(done);
done();
});
Here these calls are not executing in sequence. I need to fetch userId before verifying the email, but I am getting below error:
POST /api/users/verify-email 401 4.082 ms - 45
1) "before all" hook
First of all, yes, mocha allows multiple before hooks and guarantees that they are called in the right order. To make sure of this you could run this snippet.
'use strict';
const results = [];
const assert = require('assert');
before(done => {
setTimeout(() => {
console.log(`First 'before'`);
results.push(1);
done(); //Will be called last
}, 1000)
});
before(done => {
setTimeout(() => {
console.log(`Second 'before'`);
results.push(2); //Will be called second
done();
}, 300)
});
before(done => {
setTimeout(() => {
console.log(`Third 'before'`);
results.push(3); //Will be called first
done();
}, 100)
});
describe('Before hooks order', () => {
it('should before hooks sequentially', () => {
//Check if the hooks were called in the right order anyway
assert.deepEqual(results, [1, 2, 3]);
});
});
//Output is:
// First 'before'
// Second 'before'
// Third 'before'
But to make this happen you need to call done() only when all the async operations are done to let mocha know that the hook is completed and it should run the next one.
Also there is a rule that any Node.js callback must be called only once. So here are a couple of fixes:
before((done) => {
// Delete the user if already exists
User
.remove({
email: userInfo.email
})
.then((res) => {
// console.log(res.result);
})
.end(done);
//Do not call done here() because User.remove have only started
//We need to wait until it finishes. Done will be called in .end method
// done();
});
before((done) => {
//All good here
request(app)
.post('/api/users')
.send(userInfo)
.expect(200)
.expect((res) => {
})
.end(done);
});
before((done) => {
User.findOne({
email: userInfo.email
}).then((res) => {
userId = res._id;
//You need a return statement here so the outer promise waits
//Until the internal call finishes
return request(app)
.post('/api/users/verify-email')
.send({'token': userId})
.expect(200)
.expect((res) => {
});
//We must not call callback multiple times, so remove this.
// .end(done);
})
//Now this 'end' will happen only after both calls finish
.end(done);
//Remove this please, for the same reason as with the first 'before'
// done();
});
Please check it out. I'm not able to run your code (don't have your api), so please let me know of any problems.

Mocha run async tests in parallel with done() callback

I'm running some asynchronous tests with Mocha, but some future tests can't be executed until previous ones are completed. For this, I can simply use done() callback to run them synchronously:
describe('first operations', function() {
it('should do something', function(done) {
longOperation(function(err) {
done();
});
});
it('should do something', function(done) {
longOperation(function(err) {
done();
});
});
});
describe('second operations', function() {
it('should do something', function(done) {
longOperation(function(err) {
done();
});
});
it('should do something', function(done) {
longOperation(function(err) {
done();
});
});
});
Doing so though, slows down the entire operation because I'm stuck running each it() block synchronously. I'd like to run the inner tests asynchronously, and each describe block synchronously, but the done() callback doesn't seem to work that way (at least, using async).
Am I doing something wrong, or is that simply not supported? If not, is there a way I can get around this to accomplish my goal?
describe('first operations', function(done) {
async.parallel([
function(callback) {
it('should do something', function() {
longOperation(function(err) {
callback();
});
});
},
function(callback) {
it('should do something', function() {
longOperation(function(err) {
callback();
});
});
}
], function(err) {
done();
});
});
describe('second operations', function(done) {
async.parallel([
function(callback) {
it('should do something', function() {
longOperation(function(err) {
callback();
});
});
},
function(callback) {
it('should do something', function() {
longOperation(function(err) {
callback();
});
});
}
], function(err) {
done();
});
});
mocha-parallel-tests seems to have been created to fill this need. Here's a description from the project site:
Normally tests written with mocha run sequentially. This happens so because each test suite should not depend on another. But if you are running tests which take a lot of time (for example tests with Selenium Webdriver) waiting for so much time is impossible.
I believe this will run all tests in parallel though. To limit the describe blocks to run sequentially you could put them in individual files and then run mocha-parallel-tests separately on these files.
context.describe() doesn't seem to be an instance of Runnable. context.it(), on the other hand seems to be creating an instance of Runnable. It looks like only instances of Runnable receive a callback.
So no, it looks like you cannot run describe() blocks serially while running enclosed it() blocks asynchronously.

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
})
})

Resources