0

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.

1

2 Answers 2

1

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?).

Sign up to request clarification or add additional context in comments.

1 Comment

Hi, I appreciate the time you've taken to help me. It has helped me understand what was happening and where I was going wrong. Following your post I have read a few posts on closure and this has helped me too. Many thanks.
0

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

4 Comments

simpleFunction() doesn't return anything, so casper.wait(100,simpleFunction(siteID)); doesn't make sense. This would be functionally equivalent to simpleFunction(siteID); casper.wait(100); which is fine. Also, please fix the indentation inside of the for-loop.
simpleFunction(siteID) is a function executed for each iteration for-loop so I have used casper.wait() to execute the function
Well, that reasoning would be correct if simpleFunction would be written something like this: function simpleFunction(siteID){ return function(){ casper.then(function(){...}); ... }}. simpleFunction is executed immediately when inside the loop and not scheduled to be executed later in casper.wait(). JavaScript supports passing functions, but if you want that, then you either can't call the function (omitting ()) or let the function return some anonymous function.
Thank you everybody for your assistance and guidance.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.