ziggy
ziggy

Reputation: 1

CasperJS for loop produces the same result for each iteration

I have the following code:

casper.then(function(){

    for (siteID = 1 ; siteID < 10; siteID++) {

        casper.then(function(){

            this.fill('form#form1', {'txtSiteName' : siteID }, true);

        });

        casper.then(function(){

            this.click('#BtnSiteSearch');
            this.wait('500');

        });

        casper.then(function(){

            this.echo("Longitude: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(2) > td:nth-child(2)'));
            this.echo("Latitude: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(3) > td:nth-child(2)'));
            this.echo("City: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(5) > td:nth-child(2)'));
            this.echo("Area: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(7) > td:nth-child(2)'));
            this.echo("Address: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(9) > td:nth-child(2)'));
            this.echo("Access: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(10) > td:nth-child(2)'));
            this.echo("H&S: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(13) > td:nth-child(2)'));
            this.echo("Engineers: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(14) > td:nth-child(2)'));
            this.echo("Owner: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(8) > td:nth-child(2)'));

            this.capture('test' + siteID + '.png');

        });

    }

});

My problem is that the for loop runs and increment to that last number in the for loop. Then the code runs 10x on the last number.

I believe it's something to do with Synchronous and Asynchronous but if I am honest I don't know how to work around the issue.

Upvotes: 0

Views: 293

Answers (2)

Amine Mohamed
Amine Mohamed

Reputation: 36

I suggest you to use this code:

var casper = require('casper').create({
    verbose: true,
    logLevel: 'debug',
    pageSettings: {
        loadImages: false, // The WebPage instance used by Casper will
        loadPlugins: false, // use these settings
        userAgent: 'Mozilla/5.0 (Macintosh Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4'
    }
});

casper.start();

for (siteID = 1 ; siteID < 10; siteID++) {
    casper.wait(100);
    simpleFunction(siteID)
}

function simpleFunction(siteID){
    casper.then(function(){
        casper.echo(siteID);
    });

    casper.then(function(){

        this.fill('form#form1', {'txtSiteName' : siteID }, true);

    });

    casper.then(function(){

        this.click('#BtnSiteSearch');
        this.wait('500');

    });

    casper.then(function(){

        this.echo("Longitude: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(2) > td:nth-child(2)'));
        this.echo("Latitude: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(3) > td:nth-child(2)'));
        this.echo("City: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(5) > td:nth-child(2)'));
        this.echo("Area: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(7) > td:nth-child(2)'));
        this.echo("Address: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(9) > td:nth-child(2)'));
        this.echo("Access: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(10) > td:nth-child(2)'));
        this.echo("H&S: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(13) > td:nth-child(2)'));
        this.echo("Engineers: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(14) > td:nth-child(2)'));
        this.echo("Owner: " + this.fetchText('#pnlSiteDetail > fieldset > table > tbody > tr:nth-child(8) > td:nth-child(2)'));

        this.capture('test' + siteID + '.png');

    });

}

casper.run();

Upvotes: 0

user3743222
user3743222

Reputation: 18665

I am not an expert with casper, but apparently this is a common JavaScript mistake that you often find in every book which explains closures. The anonymous function in the then clause is executed at a later point, the loop is executed straight away, so when the anonymous function is executed, the loop variable is already at its last value, and it is that value which is picked up by your anonymous function.

The common trick recommended against that is to pass the loop variable in a function for immediate evaluation :

for (siteID = 1 ; siteID < 10; siteID++) {

    (function (siteID) {
        casper.then(function(){

            this.fill('form#form1', {'txtSiteName' : siteID }, true);

        })(siteID);
    });

}

In your particular case, I would however check whether the this variable is correctly bound (I guess this is casper is binding it correctly, right?).

Upvotes: 1

Related Questions