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?
Related
I have a log service that wraps console.log. I'm having difficulty testing it because console.log is async. I override console.log, but I'm still having async issues. The console.log function is being called after my assert.
wrapper(msg) {
console.log.bind(console); //I am binding it because in my real code the console is looked up in a map.
console.log(msg);
}
test('log() can handle valid mask', function (assert) {
let passed = false;
subject = this.subject();
console.log = function() {
passed = true;
};
subject.wrapper('testing');
assert.equal(passed, true);
});
How do I get it to wait for console.log to run? I attempted using promises, but I had no luck with them.
You can use async from qunit
test('log() can handle valid mask', function (assert) {
let passed = false;
debugger;
console.log = function() {
setTimeout(function() {
passed = true;
}, 0);
};
var done1 = assert.async();
wrapper('testing');
setTimeout(function() {
assert.equal(passed, true);
done1();
}, 100);
});
http://jsbin.com/nozoruxori/edit?js,output
works fine
with Ember for async checking you can use andThen wrapper ( for async assertion )
also looks like console.log.bind(console); //I am binding it because in my real code the console is looked up in a map. miss something cause in this state it has no sense
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.
Overview
I've been using the Revealing Module Pattern for a few months and I'm looking for an alternative or variation on this pattern that will solve both issues I'm currently having with event handlers and testability. I know I could come up with some combination of what I have below to solve my problem, but I'm hoping to find a clean alternative that I could use consistently that addresses both of my current concerns.
Revealing Module Pattern
So in this example, I have no issues with event handlers, but I can't mock calls to functions
within functions to test in isolation:
var Lion = (function () {
// Reference to rawr works as expected when the click event is triggered
function watch() {
document.addEventListener('click', rawr);
}
function rawr() {
console.log('rawr');
}
function attack() {
console.log('attack');
}
/*
* Can't test goCrazy() in isolation. Mocking rawr() and attack()
* has no effect as demonstrated below.
*/
function goCrazy() {
rawr();
attack();
// Important "crazy" logic
}
return {
watch: watch,
rawr: rawr,
attack: attack,
goCrazy: goCrazy
};
}());
module.exports = Lion;
Example Test Case (Jasmine)
describe('Mock Check', function () {
it('should mock rawr() and attack() and test only goCrazy logic', function () {
var lion = require('Lion');
spyOn(lion, 'rawr').and.reutrnValue(true);
spyOn(lion, 'attack').and.reutrnValue(true);
var crazy = lion.goCrazy();
expect(lion.rawr).toHaveBeenCalled(); // <-- Fails
expect(lion.attack).toHaveBeenCalled(); // <-- Fails
// can't test goCrazy() logic in isolation :(
});
});
Same Module using this instead and invoked using new
In this example, I can successfully mock calls to functions within functions, but if I attempt to add an event handler, this becomes undefined when the event is triggered.
var Lion = function () {
// Reference to 'this' becomes undefined when event is triggered
this.watch = function () {
document.addEventListener('click', this.rawr);
}
this.rawr = function () {
console.log('rawr');
}
this.attack = function () {
console.log('attack');
}
/*
* Can successfully test goCrazy() in isolation by being able to mock
* rawr() and attack() as needed
*/
this.goCrazy = function () {
this.rawr();
this.attack();
// Important "crazy" logic
}
};
module.exports = Lion;
Example Test Case (Jasmine)
describe('Mock Check', function () {
it('should mock rawr() and attack() and test only goCrazy logic', function () {
var Lion = require('Lion');
var lion = new Lion();
spyOn(lion, 'rawr').and.reutrnValue(true);
spyOn(lion, 'attack').and.reutrnValue(true);
var crazy = lion.goCrazy();
expect(lion.rawr).toHaveBeenCalled(); // <-- Success
expect(lion.attack).toHaveBeenCalled(); // <-- Success
// testing goCrazy logic in isolation :)
});
});
Thanks for your time. If any clarification is necessary, let me know and I'll modify my post.
The actual problem here is that, the event handler loses the context of the current object. You can bind it like this
document.addEventListener('click', this.rawr.bind(this));
This will make sure that whenever the rawr is invoked, the this inside rawr corresponds to the lion object which you created.
Coming from the Java (OOP) world, I am used to classes, inheritance and multi threading. Now for my little walkabout in the JavaScript domain, I try to utilize these paradigms and patterns where applicable. Read: use prototypes ("classes" / objects) and WebWorkers for parallel execution. However, this one case does not work ...
HTML site starting a worker:
<html>
<head>
<script>
var worker = new Worker("worker.js");
worker.onmessage(event) {
// here be fancy script
}
worker.postMessage("run, worker, run!");
</script>
</head>
...
</html>
Worker called by HTML ("worker.js"):
self.loadScripts("handler.js");
var handler = null;
self.onmessage = function(event) {
if(!handler) {
handler = new Handler();
}
handler.compute();
}
The Handler as called by the worker ("handler.js"):
function Handler() {
}
Handler.prototype = {
compute: function() {
this.doSomething(); // <-- ERROR! "this" points to the worker context,
// not to the Handler instance. So "doSomething" is
// undefined. However, the following line would work:
// Handler.prototype.doSomething();
},
doSomething: function() {
// More code here
}
}
Is JavaScript prototyping and "inheritance" meant to work this way? Should I always use the prototype property instead of this? What if I want to access this.myProperty instead of a function?
Also: is there any reasonable way to bind this to the Handler instance in the constructor? At least the code is not cluttered with lengthy Handler.prototype references.
Thanks!
Thank you for your comments. Indeed, the context of this works as expected. The real code used a timeout callback:
Handler.prototype = {
compute: function() {
self.setTimeout(this.doSomething, 1000); // Here the this got lost
},
doSomething: function() {
// Code here
}
}
It seems this from a timeout call is referencing the worker context. To solve the issue, I just wrapped the callback in an anonymous function (referencing the caller as a variable, as jfriend00 suggested):
Handler.prototype = {
compute: function() {
var caller = this;
self.setTimeout(function() { // Wrap for great justice
caller.doSomething();
} , 1000);
}, doSomething: function() {
// Code here
}
}
Thanks again.
trying to use a throttling function created by Remy Sharp (http://remysharp.com/2010/07/21/throttling-function-calls/)... it works in the standard use like so:
$('.thing').click(throttle(function() {
console.log('api call');
}, 300);
Which is pretty neat, but I wanted to be able to throttle a specific part of code within a function, not on the entire click event, like so:
$('.thing').click(function() {
console.log('hello!');
throttle(function() {
console.log('api call');
}, 300);
});
But I don't quite understand why it doesn't work. The throttle code returns a function so if I proceed the throttle call with .apply(this, arguments); then type 'hello', the function is called 5 times rather than once as the timer within the throttling function isn't being overwritten.
Sifted through the jQuery click code but couldn't really find anything. I'm guessing jQuery creates one instance of it and then recalls the same instance so the same timer is there?
Does anyone understand this and why it happens like so?
You're doing it wrong ;-)
Here's the solution on jsbin: http://jsbin.com/elabul/edit
The throttle method returns a function that will throttle the number of times it's called. So you need to capture that bad boy in a variable and call it from inside your click handler, as such:
var inputThrottle = throttle(function () {
console.log('api call');
}, 250);
$('input').keyup(function () {
console.log('test');
inputThrottle();
});
you need to call returned from throttle function:
$('.thing').click(function() {
console.log('hello!');
(throttle(function() {
console.log('api call');
}, 500))();
});
Just calling throttle does nothing, you need to return the function as a function to the click handler:
$('.thing').click((function() {
console.log('hello!');
return throttle(function() {
console.log('api call');
}, 300);
}()));