Testing Ajax calls in Prototype
If you're doing any kind of unit testing of Ajax behavior, you'll most likely come upon one minor annoyance. If you test your UI expectations in the context that fires the request, the callback won't have completed yet, and the elements you're setting or creating won't be set up. On the other hand, if you test your expectation in the context that receives the response, the test runner thread will have ended long ago, and any failures won't be caught and reported.
What you really want to do is disable asynchronous callback behavior for your test runs, but unfortunately there is no global configuration parameter for Prototype that controls that.
A little metaprogramming to the rescue.
Simply add the following to the top of your JSSpec test runner to override asynchronous behavior for your tests:
(function () {
var $$setOptions = Ajax.Base.prototype.setOptions;
Ajax.Base.prototype.setOptions = function (options) {
$$setOptions.call(this, options);
this.options.asynchronous = false;
};
})();
(
s/setOptions/initialize/g if you're using the latest and greatest Prototype 1.6.)Just fire the events that cause Ajax requests and test your expectations afterward.
One more thing:
If your Ajax response contains
<script> elements, Prototype will kindly extract and execute them for you, provided that you pass evalScripts: true as one of your Ajax options. However, what you may not expect is that it executes them in a deferred callback using the browser's setTimeout call. I initially set out to patch Element.Methods.update, which handles the deferred evaluation behavior, in much the same way as I did setOptions, when it occurred to me that a more general solution would be more helpful for testing. Why not just patch setTimeout and setInterval so that they behave synchronously?window.setTimeout = window.setInterval = function (f, timeout) {
typeof f === 'string'? eval(f): f();
}
(Again, do this in your test harness, not in your production code!)
Obviously, you're going to completely lose your desired timing behaviors, but if you're trying to test elaborate timing schemes in JSSpec or JSUnit, you're pretty much screwed anyway. But let me know if you find any neat tricks to accomplish that.
Labels: ajax, javascript, testing


2 Comments:
Hi, When you say 'add the following to the top of your JSSpec test runner', what location were you talking about?
OR, how do u call that JS method from a java test class?
A JSSpec runner is just an HTML document that contains the definitions of your specs. (See the JSSpec User Guide for more information on creating your specs.) You can put the code anywhere in this document - your specs won't run until the window's onload event is fired.
Not sure what you were asking about a Java test class - JSSpec is for running JavaScript behavior tests, not Java tests. There's no Java involved anywhere in these code samples.
Post a Comment
<< Home