Mark Mark - 24 days ago 7
Javascript Question

Returning links inside iframe using a function in CasperJS

I am trying to get the links from inside an iframe and return them as a function result, my simplified code looks something like this:

var casper = require("casper").create({
verbose: true,
logLevel: "debug",
webSecurityEnabled: false
});

var url = casper.cli.get(0);

casper.on('remote.message', function(msg) {
this.echo(msg);
})

casper.start(url, function () {
thelinks = getLinksFromIframes( casper );
console.log("doesn't work:" + thelinks);
});

function getLinksFromIframes( context ) {
var links = [];

var iframes = context.evaluate( function() {
var iframes = [];
[].forEach.call(document.querySelectorAll("iframe"), function(iframe, i) { iframes.push( i ); });
return iframes;
});

iframes.forEach( function( index ) {
context.withFrame(index, function() {
links = links.concat( this.getElementsAttribute( 'a', 'href' ) );
console.log("works: " + links);
});
});

return links;
}

casper.run(function() {
console.log('done');
this.exit();
});


The problem is that the function doesn't return anything, I can only read the links var inside
withFrame
, i know there are other ways to get the links, but the code is this way because it part of something more complex that will analyze nested iframes, and the amount of iframes inside iframes is unknown. Is there any way I could wait on
withFrame
or something that will allow me to return the links as the function result?

Answer

That's expected, because casper.withFrame is an asynchronous step function. Like all other functions that begin with either then or wait, it schedules a step in the CasperJS execution queue.

When those scheduled steps are executed (at the end of the current step, which is the then callback of casper.start in your case), getLinksFromIframes has long finished and returned an empty array.

Is there any way I could wait on withIframe or something that will allow me to return the links as the function result?

No, but you can use a callback:

function getLinksFromIframes( callback ) {
    var links = [];

    var iframes = this.evaluate( function() {
        var iframes = [];
        [].forEach.call(document.querySelectorAll("iframe"), function(iframe, i) { iframes.push( i ); });
        return iframes;
    });

    iframes.forEach( function( index ) {
        this.withFrame(index, function() {
            links = links.concat( this.getElementsAttribute( 'a', 'href' ) );
            console.log("works: " + links);
        });
    }, this);

    this.then(function(){
        callback.call(this, links);
    });
}

casper.start(url, function () {
    getLinksFromIframes.call(this, function(links){
        thelinks = links;
        console.log("Links: " + thelinks);
    });
})
.then(function(){
    console.log("Links later: " + thelinks);
})
.run();