How to write a test case for a setInterval() function - javascript

I have a timer and assume a specific function will be executed when the counter is counting to 3.
var a_interval_function = function(){
var counter = 1;
var interval = setInterval(function(){
if(counter === 5){
clearInterval(interval);
}
// run the function when the counter is 3
if(counter === 3){
a_function_should_be_runned();
}
counter++;
}, 500);
return interval;
}
However, I don't know how to establish a valid test case for testing the counter as well as the timing when the function is executed. Does anyone know how to do it? Something like the following:
// and some test case like this
it('a timer test', function(done){
var interval = a_interval_function();
expect(a_function_should_be_runned.state).to.equal({
name: 'runned',
counter: 3,
time: 300,
});
});
Thanks.

Perhaps you can use sinon.useFakeTimers().
For example:
var sinon = require('sinon');
var expect = require('chai').expect;
var a_function_should_be_runned = sinon.spy();
var a_interval_function = function(){
var counter = 1;
var interval = setInterval(function(){
if(counter === 5){
clearInterval(interval);
}
// run the function when the counter is 3
if(counter === 3){
a_function_should_be_runned();
}
counter++;
}, 500);
return interval;
}
describe('timer tests', function() {
before(function() {
this.clock = sinon.useFakeTimers();
});
after(function() {
this.clock.restore();
});
it('a timer test', function() {
var interval = a_interval_function();
// At time 0, we don't expect the function to have been called.
expect(a_function_should_be_runned.called).to.be.false;
// Advance clock 500ms.
this.clock.tick(500);
expect(a_function_should_be_runned.called).to.be.false;
// Advance clock again (1s since start)
this.clock.tick(500);
expect(a_function_should_be_runned.called).to.be.false;
// Advance clock again (1.5s since start). This should
// trigger the call to `a_function_should_be_runned`.
this.clock.tick(500);
expect(a_function_should_be_runned.called).to.be.true;
});
});

Here is my naïve approach:
it('a timer test', function(done){
var interval = a_interval_function();
setTimeout(function () {
expect(a_function_should_be_runned.state).to.equal({
name: 'runned',
counter: 3,
time: 300,
});
done();
}, 3.5 * 500);
});
What you do here is basically waiting 1.75s and expecting that the a_function_should_be_runned function has been executed on timeout. Then you call the expect function in order to check your assertion. Finally you call done(). Note that done() is called inside the setTimeout callback function. If you don't call done() your test just times out.

Easiest way to check if the code / function gets executed is just by putting in an alert or console.log, so you have visual confirmation of what is happening. Also you can console.log the counter in your interval so you can see the counter going up.
grammar nazies in the house....
[edit]
var a_interval_function = function(){
var counter = 1;
var interval = setInterval(function(){
if(counter === 5){
clearInterval(interval);
}
// run the function when the counter is 3
if(counter === 3 && testFunction()){
a_function_should_be_runned();
}
counter++;
}, 500);
return interval;
}
function testFunction(){
if(KeyboardNinja == 'awesome'){
return true;
} else {
return false;
}
}
Your test will never fail :P

Related

Is it possible to delay a variable in a for-loop with set timeout?

Is it possible to delay the variable value inside window.setTimeout and have the milliseconds value of the timeout be my time variable below?
var value = null;
var time = 5000;
for(var i = 0; i < 30; i++){
if(value === "a"){
console.log("You made it!");
} else {
console.log("You didn't make it!");
}
time = time - 100;
}
You can also use
for(i=0;i<30;i++)
setTimeout(function(){
alert('hello');
}, 5000);
alert('hey');
}
But it'll work in different way. It'll give "hello" right away and after 5 seconds it'll show "hey" .
You can use "clearTimeout()" method to clear timeout .
Yes you can do That using setInterval() method:
var myVar=setInterval(function() {
//codehere
}, 100);
Here 100 millisecond is the Interval
Use clearInterval() to stop time:
clearInterval(myVar);
Here myVar is the variable name of setInterval function.
You can create a callback function to do so
var value = null;
var time = 5000;
var limit=30;
var i = 0;
function delay(limit, time, callback) {
loop();
function loop(){
if(value = "a")// it may be a comparison (you are assigning value).
{
setTimeout(function(){
i++;
if (i<=limit && time >= 0){
callback("callback after"+time);
callback("You made it!");
loop();
}
}, time)
}
else
{
callback("You didn't make it!");
}
time=time-100;
}
}
// Calling a callback function
delay(limit,time, function(callback){
console.log(callback);

Counter stop out of the window browser

im trying to create a counter, the problem is that im trying to make the counter run only if the user is in the window, if the user goes out of the window or to another separator the counter should stop untill he comes back.
Here is my code:
$(window).blur(function(){
console.log("Counter Should Stop");
});
$(window).focus(function(){
window.onload = function(){
(function(){
var counter = 10;
setInterval(function() {
counter--;
if (counter >= 0) {
span = document.getElementById("count");
span.innerHTML = counter;
}
// Display 'counter' wherever you want to display it.
if (counter === 0) {
alert('this is where it happens');
clearInterval(counter);
}
}, 1000);
})();
}
});
You've got some scoping issues, as well as nested function issues. For readability, as well as helping you debug, I'd recommend refactoring it into separate function names for each event. This also helps promote reusability.
This should do what you're looking for:
(function(){
// your global variables
var span = document.getElementById("count");
var counter = 10;
var timer;
// your helpers
var startTimer = function() {
// do nothing if timer is already running
if (timer) return;
timer = setInterval(function() {
counter--;
if (counter >= 0) {
span.innerHTML = counter;
}
// Display 'counter' wherever you want to display it.
if (counter === 0) {
alert('this is where it happens');
stopTimer();
}
}, 1000);
};
var stopTimer = function() {
clearInterval(timer);
timer = null;
};
// your handlers
var onBlur = function() {
stopTimer();
};
var onFocus = function() {
startTimer();
};
var onLoad = function() {
startTimer();
};
// assign your handlers
$(window).load(onLoad);
$(window).blur(onBlur);
$(window).focus(onFocus);
})();

Not able to kill previous counter when countdown is placed in a loop

I am using a simple countdown as such below which is working fine except when it is placed in the loop. During looping both previous and new counter remains working .I want to kill the previous counter and start with a new, which i am not able to achieve. Can anybody help on this please
function triggerEvery60Sec(){
var myCounter = new Countdown({
seconds:5, // number of seconds to count down
onUpdateStatus: function(sec){console.log(sec);}, // callback for each second
onCounterEnd: function(){ alert('counter ended!');} // final action
});
myCounter.start();
}
function Countdown(options) {
var timer,
instance = this,
seconds = options.seconds || 10,
updateStatus = options.onUpdateStatus || function () {},
counterEnd = options.onCounterEnd || function () {};
function decrementCounter() {
updateStatus(seconds);
if (seconds === 0) {
counterEnd();
instance.stop();
}
seconds--;
}
this.start = function () {
clearInterval(timer);
timer = 0;
seconds = options.seconds;
timer = setInterval(decrementCounter, 1000);
};
this.stop = function () {
clearInterval(timer);
};
}
Instead of declare your variable in the loop, maybe should you declare it before, and manipulate it during your loop.
var myCounter = null;
function triggerEvery60Sec(){
myCounter = new Countdown({
seconds:5, // number of seconds to count down
onUpdateStatus: function(sec){console.log(sec);}, // callback for each second
onCounterEnd: function(){ alert('counter ended!');} // final action
});
myCounter.start();
}

Stop countdown on click

I want my countdown to stop on the click of a submit button, i searched in some pages,
but I didn't found anything.
Here is the code i want to stop on click
function countDown (count) {
if (count > 0) {
var d = document.getElementById("countDiv");
d.innerHTML = count;
setTimeout (function() { countDown(count-1); }, 1000);
document.getElementById('tiempo').value = count;
}
else
document.location = "timeover.php";
}
document.getElementById("palabra").focus();
countDown(5);
</script>
You have to save reference to timeout (actually return value of timeout will be number) and use it to cancel timeout.
var timeout = window.setTimeout(function () {
// do something
}, 1000);
// clear timeout
window.clearTimeout(timeout);
You probably got the idea. By the way, you should probably look at setInterval method since it would be better in this situation. Interval will "tick" as long until you cancel it.
Try something like this:
var stopped = false;
function countDown (count) {
if (count > 0) {
var d = document.getElementById("countDiv");
d.innerHTML = count;
document.getElementById('tiempo').value = count;
if (!stopped) {
setTimeout (function() { countDown(count-1); }, 1000);
}
}
else
document.location = "timeover.php";
}
document.getElementById("palabra").focus();
document.getElementById("mySubmitId").onclick = function () {
stopped = true;
};
countDown(5);

jQuery reset setInterval timer

My Jquery:
function myTimer() {
var sec = 15
var timer = setInterval(function() {
$('#timer').text(sec--);
if (sec == -1) {
clearInterval(timer);
alert('done');
}
} , 1000);
}
$("#knap").click(function() {
myTimer();
});
$("#reset").click(function() {
// set timer to 15 sec again..
});
I want the timer to be reset when clicked on #reset.
You need to leave your "timer" variable in a scope that is available the next time you call the myTimer function so you can clear the existing interval and reset it with a new interval. Try:
var timer;
functionn myTimer() {
var sec = 15
clearInterval(timer);
timer = setInterval(function() {
$('#timer').text(sec--);
if (sec == -1) {
clearInterval(timer);
alert('done');
}
} , 1000);
}
$("#knap").click(function() {
myTimer();
});
$("#reset").click(function() {
myTimer();
});
or you could do something along these lines:
var myTimer = function(){
var that = this,
time = 15,
timer;
that.set = function() {
console.log('setting up timer');
timer = setInterval(function(){
console.log('running time: ' + time);
},1000);
}
that.reset = function(){
console.log('clearing timer');
clearInterval(timer);
}
return that;
}();
and run when you need to:
myTimer.set();
myTimer.reset();
Clear the timer every time it's initalized, that way all you have to do is call the function again to reset the timer :
var timer;
function myTimer(sec) {
if (timer) clearInterval(timer);
timer = setInterval(function() {
$('#timer').text(sec--);
if (sec == -1) {
clearInterval(timer);
alert('done');
}
}, 1000);
}
$("#knap, #reset").click(function() {
myTimer(15);
});
FIDDLE
You could re-write your myTimer() function like so:
function myTimer() {
var sec, timer = null;
myTimer = function() {
sec = 15;
clearInterval( timer );
timer = setInterval(function() {
$('#timer').text(sec--);
if (sec == -1) {
clearInterval(timer);
alert('done');
}
} , 1000);
};
myTimer();
}
Now, whenever you call myTimer(), the setInterval gets reset.
Here's an approach that is more in tune with the way JS was designed (as a functional language for those who still don't know). Rather than relying on a global variable, use a closure:
$("#knap").click(function start()//named callback to bind && unbind:
{
$(this).unbind('click');//no need to start when started
$("#reset").unbind('click').click((function(timer)
{//timer is in scope thanks to closure
return function()
{//resets timer
clearInterval(timer);
timer = null;
$('#knap').click(start);//bind the start again
//alternatively, you could change the start button to a reset button on click and vice versa
}
})(setInterval((function(sec)
{
return function()
{
$('#timer').text(sec--);
if (sec === -1)
{
$('#reset').click();//stops interval
$('#reset').unbind('click');//no more need for the event
alert('done');
}//here's the interval counter: 15, passed as argument to closure
})(15),1000)));//set interval returns timer id, passed as argument to closure
});
Now I will admit this is rather messy (and untested) but this way there reset event is only available when it's necessary, and you're not using any globals. But crucially, this is where JS's power lies: functions as 1st class objects, passing them as arguments and return values... just go function-crazy :)
I've set up a working Fiddle, too
You could also use a jQuery timer plugin, then you don't need to pass around the Variable.
Plugin: http://archive.plugins.jquery.com/project/timers
Example for the plugin: http://blog.agrafix.net/2011/10/javascript-timers-mit-jquery/

Categories

Resources