sinon.useFakeTimers() can stub global Date constructor new Date()
Which purposes and use cases has sandbox.useFakeTimers ?
From documentation
Fakes timers and binds the clock object to the sandbox such that it too is restored when calling sandbox.restore(). Access through sandbox.clock
it still unclear how to use the second method.
new Date() in SUT still returns original time-stamp
The idea is not to replace Date; it is to avoid waiting on setTimout as it says in the docs:
Fake timers is a synchronous implementation of setTimeout and friends
that Sinon.JS can overwrite the global functions with to allow you to
more easily test code using them
Here's an example on how to use it:
var assert = require('assert');
var sinon = require('sinon');
var executed = false;
function doSomething() {
setInterval(function() {
executed = true;
}, 10000);
}
describe('doSomething', function() {
beforeEach(function() {
this.clock = sinon.useFakeTimers();
});
afterEach(function() {
this.clock = sinon.restore();
});
it('should execute without waiting on the timeout', function(){
doSomething();
this.clock.tick(10001);
assert.equal(executed, true);
});
});
In this example, the function doSomething will execute after 10000 milliseconds. Instead of waiting on that to assert the test, one could simulate time passing by using this.clock.tick(10001) and then assert that the test is passing.
Related
Somehow I'm not able to write Mocha JS test for a relatively very simple function. The JavaScript Source file looks like this
exports.cb = function() {
console.log("The function is called after 3 seconds");
}
exports.testfn = function(cb) {
setTimeout(cb, 3000);
}
And the test code is written as
describe('Main Test', function(){
it('A callback Tests', function(done){
asn.testfn(asn.cb);
done();
});
});
I'm encountering 2 problems.
The test code ends immediately with done()
If I don't call done(), then the function is called but tests fails because it expected to call done() for async functions
I've looked into documentations but not sure how this can be done.
I can write tests using promises and it works fine. But for the scenarios where we need to use setTimeout, how shall it be done?
Assuming what you're trying to test is testfn, you wouldn't use cb, you'd use a callback in the test; see comments:
describe('Main Test', function(){
it('testfn calls the function after three seconds', function(done){
// Remember the start time
var start = Date.now();
// Schedule callback
asn.testfn(function() {
// Has it been at least three seconds?
if (Date.now() - start < 3000) {
// No, trigger an error
} else {
// Yes, all's good!
done();
}
});
});
});
If you want to call asn.cb for some reason, you'd do it in the anonymous function above, but if you want to test asn.cb, you should do that serparately from testing asn.testfn.
describe('Main Test', function(){
it('A callback Tests', function(done){
asn.testfn(function() {
asn.cb();
done();
});
});
});
Good day!
I want to test whether parseUrl method is called, but as the result: test is failed - parseUrl was never called, although if I put the parseUrl() outside of the $interval service's function, then test pass successfully.
Here is the place, where parseUrl is called:
testMethod() {
let intervalPromise = this._$interval(() => {
this.parseUrl('test', 'test_code_name');
}, 500);
}
parseUrl(url, name) {}
Here is the test case:
it('Expect testMethod to be called', function () {
TestService.testMethod()
spyOn(TestService, 'parseUrl').and.callThrough();
expect(TestService.parseUrl).toHaveBeenCalled();
});
Also the fact is, if I put the testMethod() outside of the $interval service, then test pass successfully.
In your test you need to inject the $interval service (could use ngMock) and call $interval.flush(500);
var $interval;
angular.mock.inject(function (myModuleService, _$interval_) {
// Initialize the service under test instance
$interval = _$interval_;
});
it('Expect testMethod to be called', function () {
TestService.testMethod()
spyOn(TestService, 'parseUrl').and.callThrough();
$interval.flush(500);
expect(TestService.parseUrl).toHaveBeenCalled();
});
Here is a link to the docs: https://docs.angularjs.org/api/ngMock/service/$interval
Use $interval.flush(millis) to move forward by millis milliseconds and trigger any functions scheduled to run in that time.
What is the best way to test IIFE (Immediately Invoked Function Expression) that calls itself recursively with setTimeout:
(function myFuncToBeTested() {
// Code to be tested
...
setTimeout(myFuncToBeTested, timeout) // timeout should be checked
})()
I found the following solution that replaces global setTimeout function with own stub. This has following issues:
// Saving original setTimeout. This should be restored in test cleanup
originalSetTimeout = global.setTimeout
// Replace with function
global.setTimeout = function setImmediate(myFunc, interval) {
// FIXME: This function now always called
// Save interval to be tested
savedInterval = interval
}
could this function be made into an object?
var myObject = (function(){
function start(){
myFuncToBeTested();
setTimeout(start, 10);
return this;
}
function myFunctToBeTested(){
//Code to be tested
}
return {
start: start,
myFuncToBeTested: myFuncToBeTested
}
})().start();
and then you could use testing framework of your choice to test:
assert( myObject.myFuncToBeTested() == expectedValue );
I want to suggest a hybrid solution between thedarklord47's answer and your experiments with stubbing setTimeout. An IIFE like you have is inherently difficult to test, since you left no approach by which to check if it has been called. You can modify your API as follows:
var repeater = {
start: function () {
this.func();
setTimeout(this.start.bind(this), timeout);
},
func: function () {
// code to be tested
}
};
Then your test can look something like this (since you tagged with sinon I have used it, and in particular its fake timer API which will allow you to check your interval functionality):
// setup
var clock = sinon.useFakeTimers();
var spy = sinon.spy(repeater, 'func');
// test
repeater.start();
assert(spy.calledOnce);
// advance clock to trigger timeout
clock.tick(timeout);
assert(spy.calledTwice);
// advance clock again
clock.tick(timeout);
assert(spy.calledThrice);
// teardown
clock.restore();
spy.restore();
I have this function that I expect to be invoked after 5s of invoking the jasmine test script.
I tried the traditional way described in the jasmine docs:
describe("Tests:", function(){
it("Expects slowFunction() will be called", function(){
var slowFunctionSpy = spyOn(window, 'slowFunction').andCallThrough();
init();
waitsFor(function() {
expect(slowFunctionSpy).toHaveBeenCalled();
}, "Call Not Answered by Remote End.", 10000);
});
});
the init() function fires a chain of events, that is it inoves a function which ultimately brings it to slowFunction() being invoked.
I have left out the run() method because I think if the waitsFor() gets the expect() to be true the test should pass right?
I have also tried jasmine.async but the test still fails.
describe("Tests:", function(){
var foo=false;
var async = new AsyncSpec(this);
async.beforeEach(function(done){
setTimeout(function(done){
foo = true;
init();
done();
}, 10000);
});
it("Expects slowFunction() will be called", function(){
var slowFunctionSpy = spyOn(window, 'slowFunction').andCallThrough();
expect(slowFunctionSpy).toHaveBeenCalled();
});
});
Probably theres something I do not clearly understand about. Some help in clearing out my ideas please?
UPDATE: slowFunction() is a custom event and based on my google search outcome, I think spyOn() doesnt work for events. So new question:
How to spy on a custom event in Jasmine?
I'm trying to understand this example code, what is the function of line 15, why start(timeout)? (Sorry, I'm new to programming)
var schedule = function (timeout, callbackfunction) {
return {
start: function () {
setTimeout(callbackfunction, timeout)
}
};
};
(function () {
var timeout = 1000; // 1 second
var count = 0;
schedule(timeout, function doStuff() {
console.log(++count);
schedule(timeout, doStuff);
}).start(timeout);
})();
// "timeout" and "count" variables
// do not exist in this scope.
...why start(timeout)?
In that example, there's actually no reason for passing timeout into start, since start doesn't accept or use any arguments. The call may as well be .start().
What's happening is that schedule returns an object the schedule function creates, and one of the properties on that object is called start, which is a function. When start is called, it sets up a timed callback via setTimeout using the original timeout passed into schedule and the callback function passed into schedule.
The code calling schedule turns around and immediately calls the start function on the object it creates.
In the comments, Pointy points out (well, he would, wouldn't he?) that the callback function is calling schedule but not doing anything with the returned object, which is pointless — schedule doesn't do anything other than create and return the object, so not using the returned object makes the call pointless.
Here's the code with those two issues addressed:
var schedule = function (timeout, callbackfunction) {
return {
start: function () {
setTimeout(callbackfunction, timeout)
}
};
};
(function () {
var timeout = 1000; // 1 second
var count = 0;
schedule(timeout, function doStuff() {
console.log(++count);
schedule(timeout, doStuff).start(); // <== Change here
}).start(); // <== And here
})();
It's not very good code, though, frankly, even with the fixes. There's no particularly good reason for creating a new object every time, and frankly if the book is meant to be teaching, this example could be a lot clearer. Inline named function expressions and calls to methods on objects returned by a function...absolutely fine, but not for teaching. Still, I don't know the context, so those comments come with a grain of salt.
Here's a reworked version of using the schedule function by reusing the object it returns, and being clear about what bit is happening when:
(function () {
var timeout = 1000; // 1 second
var count = 0;
// Create the schedule object
var scheduleObject = schedule(timeout, doStuff);
// Set up the first timed callback
scheduleObject.start();
// This is called by each timed callback
function doStuff() {
// Show the count
console.log(++count);
// Set up the next timed callback
scheduleObject.start();
}
})();
The function schedule is executed as a function. That function returns an object. Like you can see with the { start... }. With the returned object it calls out the start function. This is called chaining. So the start function is executed after is set the function.
What is strange is that the timeout is passed to the start function which has no parameters.