Reputation: 13334
In this post I was asking how to check with qUnit
whether an image was properly loaded. The solution was to use asyncTest
since the error
event handler was asynchronous.
Now I'm trying to re-use this code to check multiple URLs
by combining it with a for
loop but this is not going well at all.
1st attempt: for
loop inside asyncTest
//stop(); // no difference
asyncTest('image',function() {
//stop(); // no difference
var urls = ['a','b'];
for (var i in urls) {
//stop(); // no difference
var url = urls[i];
var test_image = $('#test-image');
test_image.error(function(e) {
ok(false,'Issue loading image '+url);
start();
});
test_image.load(function() {
ok(true,'Image properly loaded '+url);
start();
});
//stop(); // no difference
test_image.attr('src',url);
}
});
result: 1 test with 4 identical assertions (on last url)
2nd attempt: asyncTest
inside for
loop
var urls = ['c','d'];
for (var i in urls) {
var url = urls[i];
//stop(); // no difference
asyncTest('image-'+url,function() {
var test_image = $('#test-image');
test_image.error(function(e) {
console.log('ERROR',$(this).attr('src'));
ok(false,'Issue loading image '+url);
start();
});
test_image.load(function() {
console.log('OK',$(this).attr('src'));
ok(true,'Image properly loaded '+url);
start();
});
//stop(); // prevents tests from running
test_image.attr('src',url);
});
}
result: 2 separate tests, first with 1 assertion, last with as many assertions as iterations in for loop, and always only last url checked.
How can I combine asyncTest
with a for loop in order to have 1 test+assertion per iteration (with iterated value used for assertion)?
Upvotes: 0
Views: 855
Reputation: 590
The reason why this happens is that JavaScript has something called Closure which makes the var url = urls[i];
change values for every callback associated with .load()
, too, thus making your errors report an incorrect URL.
To work around closures, you can create an anonymous function and then immediately execute it. An even better solution could be to create a separate function in which you pass your URL as an argument and it will test for every image separately.
I guess you also don't need to actually show the image on page but rather just check whether we were able to load it. Thus we can create dynamic images in code and not apply them to any element.
Here's a working code, fiddle: http://jsfiddle.net/VesQ/JWBhD/1/
var urls = ['http://jquery.com/favicon.ico','http://vesq.net/favicon.ico', 'http://example.com/thisDoesNotExist.jpg'];
test('image', urls.length, function() {
for (var i = 0; i < urls.length; i++) {
var url = urls[i];
stop();
imageAsyncTest(url);
}
});
function imageAsyncTest(url) {
// Create a new dynamic image
var img = new Image();
// Turn it into a jQuery object
var $img = $(img);
// Hook the tests
$img.error(function() {
ok(false,'Issue loading image '+url);
start();
});
$img.load(function() {
ok(true,'Image properly loaded '+url);
start();
});
// Load the image
$img.attr('src', url);
}
EDIT: Forgive me, didn't read the bold part at the bottom of your question. I will edit this code shortly.
EDIT2: Ok, after studying QUnit API a bit more, I believe that the second parameter in asyncTest
, called expected
, is a number stating how many assertion checks there should be. So I guess that the code should work now correctly.
EDIT3: Ok, now that I was able test it I found out that asyncTest()
isn't what we need after all. We should combine test()
alongside with stop()
and start()
to combine these to a single test. I created a working fiddle and updated code.
Upvotes: 2