How do I change the timeout on a jasmine-node async spec - node.js

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

Related

My nightmare test isnt getting into my evaluate statement

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

node mocha async hooks not working?

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.

Node.js sinon stubbing a function in parallel executions causes failed tests

I have 2 test cases which test the same function just taking 2 different executions paths, so to illustrate:
MyClass.prototype.functionBeingTested = function() {
if (this.check1()) {
this.isCheck1Called = true;
} else if (this.check2()) {
this.isCheck1Called = false;
} else {
...
}
};
My 2 test cases are as follow:
it('should take check1() execution path', function() {
var myClass= new MyClass({}, {}, {});
var check1Stub sinon.stub(MyClass.prototype, 'check1');
check1Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(true);
});
it('should take check2() execution path', function() {
var myClass= new MyClass({}, {}, {});
var check2Stub sinon.stub(MyClass.prototype, 'check2');
check2Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(false);
});
Now by default, check1() returns false so I don't stub it in the second test case, but by the time the second case is running, the check1() function stub is still active and causes the second case to enter the execution path of the first case as-well, making the second case test fail.
I understand it's a problem of test running in parallel and the first sinon stub still being used by the first test case, is there anyway I can solve this problem?
At the end of the first test, you should restore the original method (which is always a good thing, to prevent tests from being influenced by previous tests):
check1Stub.restore()
Or, alternatively, you can use a Sinon sandbox to run each test in:
describe('MyClass', function() {
beforeEach(function() {
this.sinon = sinon.sandbox.create();
});
afterEach(function() {
this.sinon.restore();
});
it('should take check1() execution path', function() {
var myClass = new MyClass({}, {}, {});
// `this.sinon` is the sandbox
var check1Stub = this.sinon.stub(MyClass.prototype, 'check1');
check1Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(true);
});
it('should take check2() execution path', function() {
var myClass = new MyClass({}, {}, {});
var check2Stub = this.sinon.stub(MyClass.prototype, 'check2');
check2Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(false);
});
});
(See mocha-sinon, which does exactly the same)

How to unit test console output with mocha on nodejs?

Take into account the following example Javascript code below:
function privateFunction (time) {
if (time < 12) { console.log('Good morning'); }
if (time >= 12 && time <19) { console.log('Good afternoon'); }
else { console.log('Good night!'); }
};
How should I unit test that on nodejs using mocha (and possibly sinonjs), noticing that this is a private function called inside a module? I need to pass in the argument and check if the function is logging the right thing to the console.
Can I do the same with console.warn and console.error?
I prefer mocha-sinon over "plain" sinon because it integrates nicely with Mocha.
Example:
var expect = require('chai').expect;
require('mocha-sinon');
// Function to test, can also be in another file and as long as it's
// being called through some public interface it should be testable.
// If it's not in any way exposed/exported, testing will be problematic.
function privateFunction (time) {
if (time < 12) { console.log('Good morning'); }
if (time >= 12 && time <19) { console.log('Good afternoon'); }
else { console.log('Good night!'); }
}
describe('privateFunction()', function() {
beforeEach(function() {
this.sinon.stub(console, 'log');
});
it('should log "Good morning" for hours < 12', function() {
privateFunction(5);
expect( console.log.calledOnce ).to.be.true;
expect( console.log.calledWith('Good morning') ).to.be.true;
});
it('should log "Good afternoon" for hours >= 12 and < 19', function() {
privateFunction(15);
expect( console.log.calledOnce ).to.be.true;
expect( console.log.calledWith('Good afternoon') ).to.be.true;
});
it('should log "Good night!" for hours >= 19', function() {
privateFunction(20);
expect( console.log.calledOnce ).to.be.true;
expect( console.log.calledWith('Good night!') ).to.be.true;
});
});
One potential issue: some Mocha reporters use console.log as well, so the tests that stub it may not yield any output.
There's a workaround, but it's not ideal either because it will intersperse Mocha output with the output from privateFunction(). If that's not a problem, replace beforeEach() with this:
beforeEach(function() {
var log = console.log;
this.sinon.stub(console, 'log', function() {
return log.apply(log, arguments);
});
});
ignoring the fact that it's a private function, i would take a couple of steps; refactor my code for better separation of concerns, and utilise this separation with test doubles.
take all the side effects outside to their own modules (the side effect here is writing to the console):
out.js
function log (message) {
console.log(message);
};
module.exports = {log};
app.js
const {log} = require('out');
function greeter (time) {
if (time < 12) {
log('Good morning');
}
if (time >= 12 && time < 19) {
log('Good afternoon');
} else {
log('Good night!');
}
};
module.exports = {greeter};
use some module proxy/spy, like proxyquire to replace the whole out writer when testing:
app.spec.js
describe('output writers', function(){
const fakeOut = {
log: sinon.spy(),
};
const app = proxyquire('./app', {
'out': fakeOut
});
it('should log to the fake out', function(){
app.greeter(15);
assert(fakeOut.log.calledOnce);
});
});
If your purpose is solely to test console output, I would suggest instead of stubs / spies etc on method calls, to use something like:
test-console
monitor stdout/stderr instead, you can use ideas from this gist

How do I sinon.stub a nested method with a callback?

I need to test a method that includes a sub-method which makes a call to an API server. I’d like to stud this internal sub-method, but I can’t seem to do that. Here’s an example:
var requests = require('./requests.js');
var utilityClass = {
methodCreatesObject: function (callback) {
// Here’s the method I’m trying to stub:
requests.makeCallToAPI(requestObject, function (err, responseFromAPI) {
doSomethingWithResponse(responseFromAPI, function (err, finalObject) {
if (err) {
callback(err, null);
} else {
callback(null, finalObject); // <- Want to test the value of finalObject
}
});
});
}
}
So, my test looks something like this (updated to show loading requests.js before utility.js):
var should = require('should'),
Joi = require('joi'),
sinon = require('sinon'),
requests = require('../lib/modules/requests.js'),
utility = require('../lib/modules/utility.js')
;
// Start my tests:
describe('Method', function () {
before(function () {
var fakeAPIresponse = { ... }
sinon.stub(requests, 'makeCallToAPI').yield(null, fakeAPIresponse);
});
it('should produce a well-formed finalObject', function (done) {
utilityClass.methodCreatesObject(function (err, response) {
if (err) {
done(err);
} else {
response.should.do.this.or.that;
done();
}
});
});
});
As I understand it, .yields() should try to run the first callback it detects in the arguments and feed its own arguments to it (resulting in doSomethingWithResponse(responseFromAPI, function () {...})). However, when running mocha, I’m getting an error indicating that the API server could not be reached, which suggests that the real requests.makeCallToAPI() is being called, and not my stub.
I must be missing something. What am I doing wrong here?
Where are you requiring the request.js? You will need to require request.js before you load up the module you want to test.
Edit 1: Using sinon.js
Here is a gist of what I meant: https://gist.github.com/limianwang/1114249de99c6a189384
Edit 2: Using proxyquire
If you are intending to test simply the utilities without concern of what actually happens within the requests.makeAPICall, you can use something like proxyquire to do the trick. If you are concerned with the actual logic within requests.js, you can use sinon.stub to stub out the actual request.get api.

Resources