Max
Max

Reputation: 13334

Using asyncTest with a for loop

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)

enter image description here

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);
    });
}

enter image description here

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

Answers (1)

valscion
valscion

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

Related Questions