5

I need to make a loop of 3 times and 2 seconds in between each iteration. I tried these 3 options:

Option 1

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

casper.start("http://google.com");

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

casper.thenEvaluate(function() {
    var x = 0;
    var intervalID = setInterval(function () {

       console.log("Using setInternal " + x);

       if (++x === 3) {
           window.clearInterval(intervalID);
       }
    }, 2000);

});

casper.run();

Observation: Nothing appeared because the script ended right away before the first setInterval being called.

Option 2

Replaced thenEvaluate() with then() below

for (i=0; i<3; i++) {
    this.wait(2000);
    this.echo('Using this.wait ' + i);
}

Observation: It outputs 3 times right away and then a long wait since this.wait() is async. This is not what I want because I want a delay in between.

Option 3 Replace the part in then() with this below. I was thinking about doing a recursive call to waitFunc() after each wait() being called.

var count = 0;
var waitFunc = function() {
    this.wait(2000, function() {
        if (count < 3) {
            casper.echo('Using this.wait ' + count);
            count++;
            waitFunc();
        }
    });

};

Observation: Nothing printed out on the screen.

So my question is: How to make this.wait or setInterval works in a loop of 3 times like this case?

HP.
  • 19,226
  • 53
  • 154
  • 253

1 Answers1

14

Here's a sample implementation to solve your problem:

var casper = require('casper').create();
var last, list = [0, 1, 2, 3];

casper.start("http://google.fr/", function() {
    this.echo('google');
});

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

casper.thenEvaluate(function() {
    window.x = 0;
    var intervalID = setInterval(function() {
       console.log("Using setInternal " + window.x);
       if (++window.x === 3) {
           window.clearInterval(intervalID);
       }
    }, 500);
});

casper.each(list, function(self, i) {
    self.wait(500, function() {
        last = i;
        this.echo('Using this.wait ' + i);
    });
});

casper.waitFor(function() {
    return last === list[list.length - 1] && 3 === this.getGlobal('x');
}, function() {
    this.echo('All done.').exit();
});

casper.run(function() {});

Sample output:

$ casperjs test.js
google
remote message caught: Using setInternal 0
Using this.wait 0
remote message caught: Using setInternal 1
Using this.wait 1
remote message caught: Using setInternal 2
Using this.wait 2
Using this.wait 3
All done.
$
NiKo
  • 11,215
  • 6
  • 46
  • 56
  • It works. But can you explain the use of casper.each vs. for loop? Why self.wait() works in this case. Using for loop will execute all this.echo() then the long wait. – HP. Nov 27 '12 at 23:49
  • 1
    It's because of how javascript scoping works. A standard `for` loop will always have the latest value of `i` set, that's why you generally have to use an [IIFE](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) (`Casper.each` wraps the loop within an IIFE). – NiKo Nov 28 '12 at 18:10
  • 1
    Ah, based on the link, this works too: casper.then(function() { for (i=0; i<=3; i++) { this.wait(2000, (function(j) { return function() { this.echo('Test ' + j); }; })(i)); } }); – HP. Nov 29 '12 at 00:07
  • Yeah sure, as I said `Casper.each()` just uses an IIFE internally :) – NiKo Nov 29 '12 at 16:23