The changes to asynchronous testing in Jasmine 2.0 are great in many ways. However, I'm not sure I fully understand how to test asynchronous code when I have no way to bind a callback to the async methods.
How do I test against an unknown number of async events in Jasmine 2.0? Or parallel async events which do not provide a callback call.
In 1.3 I would do this:
describe("my spec", function () {
it("should check the state of a variable after unknown number of async events", function () {
// This will execute several async functions in parallel (more than 1).
// Once they are all complete the 'window.done' variable will be set to "true".
// This method does not provide a callback.
fire_parallel_async_methods();
waitsFor(function () {
// I know that once this condition is met,
// all the above async calls are done
return window.done === true;
});
runs(function () {
// Now I can run the rest of my unit tests
});
});
});
Is Tony's answer in Jasmine 2.0: refactoring out 1.3's runs() and waitsFor() the only solution?
Another use case is for event validation. For example:
describe("my spec", function () {
it("should make sure event is fired", function () {
// This element has an event binding on 'click' which changes its class.
// In this test I want to check to make sure the event does the right thing.
var $element = $('.some-element');
// Simulate a click
$element.simulate('click');
// or $element.click();
waitsFor(function () {
// Once the event is done, the element should have a new 'after-event' class
return $element.hasClass('after-event');
});
});
});
In this example, I have no way to access the event's binding, so I can't attach a callback to it. How would I validate this in Jasmine 2.0?
I was able to find a workaround using timeouts, which mimics waitsFor() behaviour:
describe("my spec", function () {
it("should make sure event is fired", function (done) {
// This element has an event binding on 'click' which changes its class.
// In this test I want to check to make sure the event does the right thing.
var $element = $('.some-element');
// Simulate a click
$element.simulate('click');
// or $element.click();
// Set a timeout to wait for the async event to go through.
// Pick a time here that will be enough. It's a little messy, but it works for cases
// where you can't attach a callback. The hardest part is figuring out how long to set
// the timeout for.
setTimeout(function () {
// Do your test here
expect($element).toHaveClass('after-event');
// Tell Jasmine the test is finished
done();
}, 500);
});
});
Related
I am having trouble trying to get underscore.debounce() to work. I am attaching a keydown event listener on an input field. I will perform some actions, then call debounce() which is not being called. I am wondering why it is not working?
I have provided two samples. The first one where I have not attached _.debounce() as inline is not working. The second one where I have attached _.debounce() as inline is working. I do not understand why the non-inline solution is working?
// This example does not ever call _.debounce()
$('input').on('keydown', onKeyDown);
function onKeyDown() {
console.log('performing some actions...');
_.debounce(function() {
console.log('debouncing'); // never called
}, 500);
}
// This example does call _.debounce()
$('input').on('keydown', _.debounce(function() {
console.log('debounce');
}, 500));
Debounce returns a function that will need to be invoked, in this case you are creating a function but never invoking it. Try this:
// This example does not ever call _.debounce()
var debounced = _.debounce(debounceStuff, 500);
$('input').on('keydown', onKeyDown);
function onKeyDown() {
console.log('performing some actions...');
debounced();
}
function debounceStuff() {
console.log('debouncing');
}
I currently am writing functional tests in Intern and have run across a small issue.
During the before portion of my test suite, I make an ajax call to an API to retrieve a variable's value. This variable being set is critical to the next step in the functional test, and therefore I want to halt the test until the variable is returned from the ajax call.
I read about Leadfoot's pollUntil() function and it sounded like it did what I needed to do. I wrote the following code:
var valueThatChanges = 0;
// ... (some functional test setup stuff)
//Ajax call that sets value of valueThatChanges
.then(function() {
return ajaxCall(valueThatChanges);
})
//valueThatChanges is initially 0 before/during ajax call
//Is set to a randomly generated value that is non-zero after response recieved
.then(pollUntil(function(valueThatChanges) {
return valueThatChanges !== 0 ? true : null;
},[valueThatChanges], 30000, 100))
.then(function() { //On success
console.log('Value is no longer zero.')
}, function(error) { //On failure/timeout
console.log(error)
})
});
However this does not work as the function enters the success callback instantly despite the value of valueThatChanges still being 0.
I understand that pollUntil() may not designed to handle situations like this (since I am not directly dealing with DOM elements in the pollUntil), but I am not sure why it does not work for this specific scenario.
It seems as though pollUntil() is not passing the updated variable on each call of it's polling function.
Can pollUntil() handle triggering an event on a change of variable value?
The general use case for pollUntil is a situation where you need to wait for something to happen in the remote browser. For example, pollUntil is often used to wait for a functional test page to fully initialize:
// ---------------------
// functional test (in Node.js)
this.remote.get('testpage.html')
.then(pollUntil('return window.pageIsReady ? true : null'))
// rest of test
// ---------------------
// remote test page (in the browser)
<script>
var pageIsReady = false;
require( ..., function ( ... ) {
// do setup stuff
pageIsReady = true;
});
</script>
If you're doing some bit of async stuff in your test setup that doesn't involve the browser, return a Promise from the before function in your test suite that will resolve when the async action is complete.
var valueThatChanges;
registerSuite({
before: function () {
return new Promise(function (resolve) {
// Assuming ajaxCall calls a callback when it's finished:
ajaxCall(function (newValue) {
valueThatChanges = newValue;
resolve();
});
});
},
test1: function () {
return this.remote
// rest of test
},
// ...
});
Why does the default function for my event not execute when I specify it with defaultFn?
var node = Y.one(".foo");
node.publish("myEvent", {
defaultFn: function () {
//I don't understand why this doesn't execute
//I expect it to execute after my on listener
//and before my after listener
Y.log("In default function");
}
});
node.before("myEvent", function () {
Y.log("In before listener");
});
node.on("myEvent", function () {
Y.log("In on listener");
});
node.after("myEvent", function () {
Y.log("In after listener");
});
node.fire("myEvent");
JSFiddle: http://jsfiddle.net/steaks/rUacD/
Your jsfiddle shows you are loading only node. To have events, you have to load one of the event modules. As it happens, your code fails at the call to publish, the first method that event provides that it finds.
In general, check the API docs for the methods that fail and see which module provides them ('Inherited from' right below the heading for the method) and make sure you have the corresponding module loaded.
--
Updated according to newer JSFiddle:
Add emitFacade: true to the configuration of the published event. YUI does this automatically for classes inheriting from Base but not for others. For Node instances, you have to add that option explicitly.
New to unit testing in general and Jasmine in particular.
I've set a variable in a beforeEach() callback, but it doesn't seem to work on the second test. It's supposed to fire initialization stuff in advance of every test within its context, right? I'm sure my spyOn() call is to blame, but I don't know how to fix it.
Comments explain the passes and fails:
describe("Test suite for my library", function () {
var html,
body,
play,
...
// custom matcher...
beforeEach(function () {
this.addMatchers({
toBeInstanceOf : function (constructr) {
return this.actual instanceof constructr;
});
});
});
describe("Within the Button object", function () {
beforeEach(function () {
play = new Button("play", false);
});
describe("play", function () {
// This test passes, as expected...
it("should be an instance of the Button object", function () {
expect(play).toBeInstanceOf(Button);
});
});
describe("play.name", function () {
// This test failed with the message
// "Expected spy Button to have been called
// with [ 'play', false ] but it was never called."
it("should be the first argument passed to the Button constructor", function () {
spyOn(window, "Button");
play = new Button("play", false); // ...until I added this line. Now it passes.
expect(window.Button).toHaveBeenCalledWith("play", false);
});
// This test passes, even if the one above fails.
it("should be 'play'", function () {
expect(play.name).toBe("play");
});
});
});
});
The documentation explains the usage, but not the context, of spyOn(), so I can't tell if I've created a bug or if I'm unknowingly taking advantage of a feature.
I can post the constructor if anyone thinks it makes any difference in the diagnosis, but I can assure you it's dead simple.
I'm sure it's a straightforward fix using some basic unit testing concept I'm having to learn the hard way. Thanks in advance.
P.S. I realize what I'm testing for in that failing spec isn't what I've described. I'm working my way through the API guide, looking for a way to get to the arguments array within a function call, so I can do a specific test on arguments[0]. Hints are appreciated, but not necessary. I'll figure it out.
Short answer: No, Before each and spies are not incompatible
You must Spy before you call if you want the spy to know about the call. You can use spyOn(object, 'function').andCallThrough() if you do not wish to interfere with its default behavior.
Long answer: The way faking/mocking/stubbing/spying frameworks often work is by replacing the method you are calling with a method that the mocking framework can control. Any calls to that function before it is replaced with the spy cannot be observed. This is a good thing, though mildly inconvenient,
Its cause you spy on window.Button after you have called. Im not totally sure what spy does, but after all it displaced the function you spy on with another function where it can check the function was called and whats arguments was passed. When you create your Button before your start your test, the original window.button function called. Then you replaces the function with the spy and test that the spy was called, so your test must fail.
Seems either create your Button in the test itself or create your spy before you call new Button in your beforeEach function.
I have 3 asynchronous events which can only be run one after the other. When the first asynchronous event is completed, the second is run. When the second event is completed, the third is run. My code is as shown:
asynchronousEvent1(parameters1, function () { // Do stuff
asynchronousEvent2(parameters2, function () { // Do stuff
asynchronousEvent3(parameters3, function () { // Do stuff
});
});
});
This current format means that I need to have long sequences of functions nested within another. Is there some sort of an event handler I could use, for which the format of the code would be approximately:
asynchronousEvent1(parameters1, function () { /* Do stuff */ });
whenEvent1Completed(asynchronousEvent2(parameters2, function () { /* Do stuff */ });
whenEvent2Completed(asynchronousEvent3(parameters3, function () { /* Do stuff */ });
You could use deferred objects introduced in jQuery 1.5. Assuming your functions return deferred objects, like the one returned by $.ajax (or of course you can create your own):
asynchronousEvent1(parameters1).pipe(function() {
// do stuff
return asynchronousEvent2(parameters2);
}).pipe(function() {
// do stuff
return asynchronousEvent3(parameters3);
}).then(function() {
//do stuff
});
Have a look at the last example in deferred.pipe [docs].
I don't necessarily consider this to be an answer, but more of an idea. I don't know how in real life your code is laid out, but would there be the possibility of using an array loaded with the functions to call in their order. Then, it just checks for the next one in the list, and calls that? I don't know would work, but it's an idea.
JMax
I'm not sure I entirely understand what you're looking for.
You can, for example, define a function that handles the results of Event 1, and then simply pass a reference to that function instead of writing the literal at the spot where your chain is defined. If you use that pattern, you'd probably have to tweak how parameters are passed from one event to the second.
E.g.:
function handleEvent1() {
// do something
asynchronousEvent2(parameters2, handleEvent2);
}
function handleEvent2() {
// do something
asynchronousEvent3(parameters3, handleEvent3);
}
asyncronousEvent1(parameters1, handleEvent1);
In this example, none of these event handlers benefit from the same closure as they would in your original implementation, which means you'll need to work out some data visibility stuff.
set a value to true on each event callback and put condition for firing each dependent event.
$('blah').animate({},1000,function(){animated = true}
if(animated){$('blahblah').animate()...}