Testing with Jasmine a method that fires an async request - javascript

I'm trying to use Jasmine to test asynchronous methods.
I have something like this:
function change(obj) {
setTimeout(function() { obj.value = 1 }, 500);
}
In my test:
it('should change the value', function(done) {
....
obj.value = 0;
change(obj);
done();
obj.value.should.equal(1)
}
How can I get it work?
UPDATE: It works like this now, but it messes with some other tests that worked before, should I reset something after the test?

You can call done using setTimeout
setTimeout(function(){
done();
}, 1000);

Related

How to spy on function calling other function in Jasmine?

I have the problem:
var async = require('async');
function a() {
async.series([b,c], function(err) {
console.log('Done');
});
};
function b(next) {
next();
};
function c(next) {
next();
};
var methods = {
a: a,
b: b,
c: c
};
And I am trying to write a test like so:
spyOn(methods.a);
methods.a();
expect(methods.b).toHaveBeenCalled();
expect(methods.c).toHaveBeenCalled();
However both b and c do not register as having been called. Any ideas how to properly test this behavior?
If you use spy on function or method then Jasmine will be look at this function for check call it. And called function under Jasmine Spy is not execute its code by default.
spyOn(methods, "a");
methods.a();
expect(methods.a).toHaveBeenCalled();
In your case, you need check async code execution. We can do it with done function:
it("should support async execution", function(done) {
var MAX_ASYNC_DELAY = 2000;
spyOn(methods, "b");
spyOn(methods, "с");
methods.a();
setTimeout(function(){
expect(methods.b).toHaveBeenCalled();
expect(methods.c).toHaveBeenCalled();
done();
}, MAX_ASYNC_DELAY );
});
It will work if in methods.a() you will use next:
function a() {
async.series([methods.b, methods.c], function(err) {
console.log('Done');
});
}
If such adjustment is not possible, you should rewrite the test case in the following:
it("should support async execution", function(done) {
var MAX_ASYNC_DELAY = 2000;
spyOn(window, "b");
spyOn(window, "с");
methods.a();
setTimeout(function(){
expect(b).toHaveBeenCalled();
expect(c).toHaveBeenCalled();
done();
}, MAX_ASYNC_DELAY );
});
Owen Ayres advises not to use setTimeout in the test case. But this is impossible in your case if you are using Jasmine. Because jasmine.DEFAULT_TIMEOUT_INTERVAL is timeout waiting for call done function.
Example, your async timeout is eqaul nearly 10000 ms and you set MAX_ASYNC_DELAY to 11000 ms. The test case will be marked as failed, because jasmine.DEFAULT_TIMEOUT_INTERVAL equal 5000 ms by default. That need use override this param:
var originalTimeout;
beforeEach(function() {
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 12000; // ms to wait for done()
});
it("should support async execution", function(done) {
var MAX_ASYNC_DELAY = 11000;
// test case from above
});
afterEach(function() {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
if you use Jasmine version 2.2 and above you can write:
it("should support async execution", function(done) {
var MAX_ASYNC_DELAY = 11000;
// test case from above
}, 12000);
Avoid setTimeout in a unit test at all costs. Here is how you should test it in a readable, 'Triple A Testing' format. Using Jasmine's async done will ensure it waits for a certain length of time before failing if the function call is never made. If you want to customise this for this test case, you could do something like defined in my beforeEach below (but inside the test itself).
beforeEach(function() {
// these are not required, including to show you can have if desired
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // ms to wait for done()
});
it('calls methods b and c when a is called', function (done) {
var a = spyOn(methods.a);
var b = spyOn(methods.b);
methods.a();
expect(a).toHaveBeenCalled();
expect(b).toHaveBeenCalled();
done();
});
afterEach(function() {
// could be inline of above test if not needed for multiple cases.
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
Do not use timeouts in the test. This is not a clean way of testing and should be avoided unless absolutely essential.

How can I use setTimeout() functions within Mocha test cases?

I'm writing a test in Mocha / Node js and want to use a setTimeout to wait for a period before executing a block of code.
How can I accomplish this?
It appears that within a Mocha test case, setTimeout() does not work. (I am aware that you can setTimeout per test case and per test file, that's not what I need here.)
In a js file run with Node, ie, node miniTest.js, this will wait 3 seconds, then print the line inside the setTimeout function.
miniTest.js
console.log('waiting 3 seconds...');
setTimeout(function() {
console.log('waiting over.');
}, 3000);
In a js file run with Mocha, ie, mocha smallTest.js, this will not wait, and will finish executing and exit without ever printing the line inside the setTimeout function.
smallTest.js:
mocha = require('mocha');
describe('small test', function() {
it('tiny test case', function() {
console.log('waiting 3 seconds...');
setTimeout(function () {
console.log('waiting over.')
}, 3000);
});
});
You are forgetting to pass parameter in it('tiny test case', function() and call done() after console.log in setTimeout method.
describe('small test', function(){
it('tiny test case', function(done){
console.log('waiting 3 seconds');
setTimeout(function(){
console.log('waiting over.');
done();
}, 3000)
})
})
You need to have done passed as a parameter in your test which will be invoked once the test passes.
You can write your test like
mocha = require('mocha');
describe('small test', function(done) {
it('tiny test case', function() {
console.log('waiting 3 seconds...');
setTimeout(function () {
console.log('waiting over.');
done();
}, 3000);
});
});
This will wait 3 seconds after that it will print 'waiting over' and pass the test. You can also have a condition inside the timeout depending upon whether the condition is satisfied or not you can pass the test by calling
done();
or fail the test by either throwing an error or passing the error message in
done("Test Failed");
Have your test function take a parameter (typically called done). Mocha will pass a function that you'll call in the setTimeout function (e.g. after console.log call done()).
See https://mochajs.org/#asynchronous-code.
This is a complete example. You need to call done() in every assertion you make. You can leave out the before function and do the setTimeout in one of your it functions, but it should still use and call done() after assert.
var foo = 1;
before(function(done) {
setTimeout(function(){
foo = 2;
done();
}, 500)
});
describe("Async setup", function(done){
it("should have foo equal to 2.", function(done){
expect(foo).to.be.equal(2);
done();
});
it("should have foo not equal 3.", function(done){
expect(foo).to.be.not.equal(3);
done();
});
});

Meteor: Synchronous method

I'm failing to run a method on the server side synchronously, meaning to wait for it to be done.
mymethod: function(par1, par2){
var timer = Meteor.setTimeout(function() {
//do something
});
}
I tried to use Meteor.wrapAsync without success, whether I wrap the timer or the entire method like this:
Meteor.wrapAsync(Meteor.call('mymethod', par1, par2));
Weird.
if (Meteor.isServer) {
Meteor.methods({
mymethod: function(par1, par2) {
var timer = Meteor.setTimeout(function() {
console.log("Hey!");
}, 1000);
}
});
Meteor.call('mymethod', 'par1', 'par2');
}
works fine here in a newly created 0.9.3.1 app.

What's wrong with this unit test of an async JavaScript function (via Mocha/Sinon)?

I was trying to put together a small example to show co-workers but can't figure out what's wrong with this test that I've put in a gist.
Essentially I want to test a function that does something async, but use Sinon's spy() functionality to assure it completes:
function asyncHello(name, delay, cb) {
setTimeout(function() {
console.log("running after ", delay);
cb("hello " + name);
}, delay);
}
suite('Mega Suite', function(){
suite("testing async hello", function() {
test('should call the callback', function(done) {
var cb = sinon.spy();
asyncHello("foo", cb);
cb.should.have.been.called();
done();
});
});
});
Thought using Mocha and done() to resolve a test that depends on an async function (setTimeout, in this case) would work, but maybe someone can point out where I'm wrong. Thanks!
You don't need Sinon for this:
function asyncHello(name, delay, cb) {
setTimeout(function() {
console.log("running after ", delay);
cb("hello " + name);
}, delay);
}
suite('Mega Suite', function(){
suite("testing async hello", function() {
test('should call the callback', function(done) {
asyncHello("foo", 1000, function () {
done();
});
});
});
});
There were two problems in this code:
You called asyncHello("foo", cb); which made it so that your delay argument inside the function was set to cb and the cb argument inside the function was undefined.
Even after fixing the 1st item cb.should.have.been.called(); was called before the function passed to setTimeout could execute.
You basically don't need to use Sinon because if you just set a callback to call done() then you know the test is successful. If there's a problem anywhere done() won't get called and the test will fail.

Expecting a timeout in QUnit

I have an asynchronous QUnit test where the test should pass if the operation times out. (I'm testing that if you omit an optional errorCallback and do something that throws an error, basically nothing happens no matter how long you wait.)
How would I do that? If I use Qunit.config.testTimeout then the test will fail on timeout. I want to set a timeout and have the test succeed when the timeout is reached.
Why not just go with a setTimeout call making the test succeed?
e.g.:
expect(1);
stop();
doOperation(function () {
start();
ok(false, "should not have come back");
});
setTimeout(function () {
start();
ok(true);
}, timeoutValue);
This is how I do in these cases (roughly):
function timeout(assert,to,error){
var done = assert.async();
var a = setTimeout(function(){
assert.equal(to,undefined,error);
done();
},to);
return function(){
done();
clearTimeout(a);
};
}
then you can:
...
var done = timeout(assert,2000,"not joined");
r.join(function(data){
assert.ok(true,"join confirmed");
done();
})
You may agument timeout function to timeout(assert,to,toCB) and execute the toCB instead of my dummy assert.equal

Categories

Resources