Search code examples
javascriptjqueryphantomjscasperjs

How would you cycle through each image and check it for an error in a casperjs script?


How would you cycle through every image on a given page and check to see if it was loaded or errored out?

The following are not seeming to work in the phantomjs/casperjs setup yet cycling through and grabbing the src is working.

.load()

and

.error()

If the above does work, could someone show a proper usage that would work in a casperjs script?

The code I used looked similar to the following:

var call_to_page = this.evaluate(function() {
    var fail_amount = 0;
    var pass_amount = 0;
    var pass_img_src = [];
    var fail_img_src = [];
    var img_src = [];
        $("img").each(function(){
            $(this).load(function(){
               pass_amount++;
               pass_img_src.push($(this).attr("src")); 
            }).error(function(){
               fail_amount++; 
               fail_img_src.push($(this).attr("src"));
            });
            img_src.push($(this).attr("src"));
        });
    return [img_src, fail_amount, fail_img_src, pass_amount, pass_img_src];
});

Any help as to why the above code doesnt work for me would be great. The page is properly being arrived upon and I am able to mess with the dom, just not .load or .error. Im thinking its due to the images being done loaded, so Im still looking for alternatives.


Solution

  • CasperJS provides the resourceExists function which can be used to check if a particular ressource was loaded. The ressource is passed into a function, so custom constraints can be raised.

    casper.then(function(){
        var fail_amount = 0;
        var pass_amount = 0;
        var pass_img_src = [];
        var fail_img_src = [];
    
        var elements = this.getElementsInfo("img");
        elements.forEach(function(img){
            if (img && img.attributes && casper.resourceExists(function(resource){
                return resource.url.match(img.attributes.src) && 
                       resource.status >= 200 && 
                       resource.status < 400;
            })) {
                pass_amount++;
                pass_img_src.push(img.attributes.src);
            } else {
                fail_amount++;
                fail_img_src.push(img.attributes.src);
            }
        });
        this.echo(JSON.stringify([fail_amount, fail_img_src, pass_amount, pass_img_src], undefined, 4));
    });
    

    This can be done after the page is loaded. So there is no need to preemptively add some code into the page context.

    In turn, the problem with you code may be that the callbacks never fire because the images are already loaded of already timed out. So there is no new information.

    If you're not sure what kind of errors are counted, you can use a custom resources detection for all available types or errors.

    var resources = []; // a resource contains at least 'url', 'status'
    casper.on("resource.received", function(resource){
        if (resource.stage == "end") {
            if (resource.status < 200 || resource.status >= 400) {
                resource.errorCode = resource.status;
                resource.errorString = resource.statusText;
            }
            resources.push(resource);
        }
    });
    casper.on("resource.timeout", function(request){
        request.status = -1;
        resources.push(request);
    });
    casper.on("resource.error", function(resourceError){
        resourceError.status = -2;
        resources.push(resourceError);
    });
    function resourceExists(url){
        return resources.filter(function(res){
            return res.url.indexOf(url) !== -1;
        }).length > 0;
    }
    casper.start(url, function(){
        var elements = this.getElementsInfo("img");
        elements.forEach(function(img){
            if (img && img.attributes && resourceExists(img.attributes.src) && !resourceExists(img.attributes.src).errorCode) {
                // pass
            } else {
                // fail
            }
        }); 
    });