Ok so I'm obviously new to mocha. From my understanding after reading the docs and googling this should work but it isn't:
describe("Check before", function(){
var beforeCalled = false;
before(function(){
setTimeout(function() {
beforeCalled = true;
done();
}, 150);
});
it("should run after before called", function(){
expect(beforeCalled).to.equal(true);
})
})
the it part doesn't wait for 'before' to finish and is called. Maybe I read the docs wrong or I'm missing something, not sure.
Any insight would be helpful.
The done callback must be in the function signature for mocha to wait.
before(function(done){
setTimeout(function() {
beforeCalled = true;
done();
}, 150);
});
I've got into the habit of always using done when there are mixed synchronous and async tests. Mocha can finish as if no tests have failed if you forget one async done on an it.
Related
Getting some practice running tests with mocha chai and nightmare. Everything seems to work until I get into my evaluate block.
var Nightmare = require('nightmare'),
should = require('chai').should()
describe('Frontend Masters', function() {
this.timeout(20000);
it('should show form when loaded', function(done) {
var nightmare = new Nightmare({show: true})
nightmare
.goto('https://frontendmasters.com/')
.wait('a[href*="https://frontendmasters.com/login/"]')
.click('a[href*="https://frontendmasters.com/login/"]')
.wait('#rcp_login_form')
.evaluate(function() {
return window.document.title;
}, function(result) {
result.should.equal('Login to Frontend Masters');
done();
})
.run(function(){
console.log('done')
});
});
});
I've thrown in console logs and it never makes it into the evaluate. I've tried passing in several selectors into my wait() function, but it doesnt seem to be having an effect. Only error I'm receiving is that my timeout has been exceeded. But it doesnt matter how long i set it for
What version of Nightmare are you using?
The signature for .evaluate() has changed, and I think that may be the source of your issues. The second function you're passing in - the one that used to be for handling the results of the evaluation - is actually getting passed as an argument to the first .evaluate() argument. In other words, the second argument is never run, done() is never called, and your test will time out.
Also worth mentioning: .run() is not directly supported. Use.then() instead.
Finally, let's modify your source to reflect the above to get you started:
var Nightmare = require('nightmare'),
should = require('chai')
.should()
describe('Frontend Masters', function() {
this.timeout(20000);
it('should show form when loaded', function(done) {
var nightmare = new Nightmare({
show: true
})
nightmare
.goto('https://frontendmasters.com/')
.wait('a[href*="https://frontendmasters.com/login/"]')
.click('a[href*="https://frontendmasters.com/login/"]')
.wait('#rcp_login_form')
.evaluate(function() {
return window.document.title;
})
.then(function(result) {
result.should.equal('Login to Frontend Masters');
console.log('done')
done();
})
});
});
Running this with mocha results in timing out, rather than letting mocha catch the error so it could fail immediately..
var when = require('when');
var should = require('should');
describe('', function() {
it('', function(done) {
var d = when.defer();
d.resolve();
d.promise.then(function() {
true.should.be.false;
false.should.be.true;
throw new Error('Promise');
done();
}); }); });
http://runnable.com/me/U7VmuQurokZCvomD
Is there another way to make assertions inside the promise, such that when they fail they are caught by mocha causing it to fail immediately?
As per chai recommendation, I looked into it and it seems I have to have a direct access to the promise object, right? The problem is that I'm not using promise directly.. My bad if I simplified but This would be a more closer to reality example
function core_library_function(callback){
do_something_async(function which_returns_a(promise){
promise.then(function(){
callback(thing);
}); }); }
describe('', function() {
it('', function(done) {
core_library_function(function(thing){
...
done();
}); }); });
So I really have no control over the promise directly, it's abstracted far far away.
When using promises with Mocha, you'll have to return the promise in the test and will want to remove the done parameter since the callback isn't being used.
it('', function() {
var d = when.defer();
d.resolve();
return d.promise.then(function() {
throw new Error('Promise');
});
});
This is described in the docs under Working with Promises:
Alternately, instead of using the done() callback, you can return a promise.
Why does mocha timeout when an assertion fails inside a Q future? You also don't get to see the assertion failure when this happens. This does not happen if I just use callbacks. How should I write this while still using futures but get to see the assertion error instead of a timeout?
var Q = require('q');
function hack() {
var ret = Q.defer();
ret.resolve(true);
return ret.promise;
}
it('test', function(done) {
hack().then(function(bool) {
assert(false);
done();
});
});
The assertion call throws an exception, which is caught by Q in order to properly conform to the promises spec. So mocha never reaches done(), nor does it see an exception thrown. You could do something like this:
it('test', function(done) {
hack().then(function(bool) {
assert(false);
done();
}).catch(function(err){
done(err);
});
});
[edit] Alternatively, you can omit the done argument altogether and just return the promise directly from the test function, in which case mocha will pass/fail the test based on the outcome of the returned promise:
it('test', function() {
return hack().then(function(bool) {
assert(false);
});
});
...which is a nice way to simplify your test functions. Props to Taytay elsewhere in this thread for pointing this out.
Mocha now supports promises in unit tests, so you can just return the promise instead of relying upon calling (done) from a then handler. It's easier and safer (because you won't forget to call done)
So you could just write:
it('test', function() {
return hack().then(function(bool) {
assert(false);
});
});
That would fail because the promise would fail, and Mocha would detect it.
This is from the Mocha docs in the section "Working with Promises": https://mochajs.org/
Improving on greim's answer including what callumacrae added in a comment, you can do it like this:
it('test', function(done) {
hack().then(function(bool) {
assert(false);
done();
}).catch(done);
});
When I'm testing with Mocha, I often have a combination of both asynchronous and synchronous tests that need to run.
Mocha handles this beautifully allowing me to specify a callback, done, whenever my tests are asynchronous.
My question is, how does Mocha internally observe my tests and know that it should wait for asynchronous activity? It seems to wait anytime I have the callback parameter defined in my test functions. You can see in the examples below, the first test should timeout, the second should proceed and finish before user.save calls the anonymous function.
// In an async test that doesn't call done, mocha will timeout.
describe('User', function(){
describe('#save()', function(){
it('should save without error', function(done){
var user = new User('Luna');
user.save(function(err){
if (err) throw err;
});
})
})
})
// The same test without done will proceed without timing out.
describe('User', function(){
describe('#save()', function(){
it('should save without error', function(){
var user = new User('Luna');
user.save(function(err){
if (err) throw err;
});
})
})
})
Is this node.js specific magic? Is this something that can be done in any Javascript?
This is simple pure Javascript magic.
Functions are in fact objects, and they have properties (such as the number of parameters are defined with the function).
Look at how this.async is set in mocha/lib/runnable.js
function Runnable(title, fn) {
this.title = title;
this.fn = fn;
this.async = fn && fn.length;
this.sync = ! this.async;
this._timeout = 2000;
this._slow = 75;
this.timedOut = false;
}
Mocha's logic changes based whether or not your function is defined with parameters.
What you're looking for is Function's length property which can tell how many arguments a function is expecting. When you define a callback with done it can tell and treats it asynchonously.
function it(str, cb){
if(cb.length > 0)
//async
else
//sync
}
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/Length
How can I get this test to pass without resorting to runs/waitsFor blocks?
it("cannot change timeout", function(done) {
request("http://localhost:3000/hello", function(error, response, body){
expect(body).toEqual("hello world");
done();
});
});
You can (now) set it directly in the spec, as per Jasmine docs.
describe("long asynchronous specs", function() {
var originalTimeout;
beforeEach(function() {
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
});
it("takes a long time", function(done) {
setTimeout(function() {
done();
}, 9000);
});
afterEach(function() {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
});
Sent pull request for this feature (https://github.com/mhevery/jasmine-node/pull/142)
it("cannot change timeout", function(done) {
request("http://localhost:3000/hello", function(error, response, body){
expect(body).toEqual("hello world");
done();
});
}, 5000); // set timeout to 5 seconds
To set the global Jasmine-Node timeout, do this:
jasmine.getEnv().defaultTimeoutInterval = timeoutYouWouldPrefer;// e.g. 15000 milliseconds
Credit to developer Gabe Hicks for figuring out the .getEnv() part via debugging in spite of misinformation in the README doc which claims it's done by setting jasmine.DEFAULT_TIMEOUT_INTERVAL.
If you want to set a custom timeout just for one it(), you could try passing the timeout (milliseconds) as a third argument (after the string statement and the function). There's an example of that being done here, but I'm not sure what would happen if the custom timeout was longer than Jasmine's default. I expect it would fail.
Looks like you can now add it as the last argument for the it function:
describe('my test', function(){
it('works', function(done){
somethingAsync().then(done);
}, 10000); // changes to 10 seconds
});
In Angular, put this outside your describe block:
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
This applies to all the tests in the .spec.ts file
Put it after describe statement:
describe("A saves to DB", function() {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
Adding: jasmine.DEFAULT_TIMEOUT_INTERVAL = yourTime; on a helper file worked for me.
In my case I had multiple tests cases and while I was using the aforementioned solution with was using the:
beforeEach(function() {
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
});
the DEFAULT_TIMEOUT_INTERVAL was not updated at the first test case, so I had to add this:
beforeAll(() => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
})
to my code to successfully run all the tests.
To do this globally for all of your tests (in the case of e2e or integration testing) you can use a helper.
A helper file when configured correctly should get loaded before the tests are executed and allow you to change the DEFAULT_TIMEOUT_INTERVAL globally:
spec/support/jasmine.json
{
...
"helpers": [
"/path/to/helpers/**/*.ts"
]
}
helpers/timeout.ts
jasmine.DEFAULT_TIMEOUT_INTERVAL = 300000;
Why not by spying on setTimeout()?
Something like:
var spy = spyOn(window, 'setTimeout').andCallFake(function (func, timeout) {
expect(timeout).toEqual(2500);
func();
});
setTimeOut(function () { ... }, 2500);
expect(spy).toHaveBeenCalled();
Change j$.DEFAULT_TIMEOUT_INTERVAL to 10000 in following file: npm\node_modules\jasmine-core\lib\jasmine-core