0

So what I want to do is create a casperJS function which allows us to repeat a step X times, by refreshing the page first, when this step function reaches the timeout.

For unreliable test due to a specific page bug/freeze at the moment and reduce the percentage of false negative.

I have just a problem, I don't know how to break this loop, because I'm in IIFE scope, see following code :

var echoTest = function(){
    casper.echo('Hi');
};
var trueFunction = function(){
    return true;
};

var verifyFailedTest = function(number, trueReturn, thenFunction){
    var i = 0;
    //outer:       <-------
    for (; i <= number; i++){   // <------ how to break this loop in my function then()
        //IIFE
        (function(index){
            if (index < number-1){
                //Execute 'number-1' times the then() step (reload the page each time) if timeout or until trueReturn returns true
                casper.then(function(){
                    casper.waitFor(function checkReturnTrue(){
                            return trueReturn();
                        }
                        , function then() {
                            thenFunction();
                            //break outer; break; return false;    <------ here where I want to break the loop
                        }
                        , function timeout() { 
                            casper.reload();
                        });
                });
            }
            //last execution, will return the normal error if it fails each time
            else if (index === number){
                casper.then(function(){
                    casper.waitFor(function checkReturnTrue(){
                            return trueReturn();
                        }
                        , function then() {
                            console.log('else');
                            thenFunction();
                        });
                });
            }
            else{console.log('verifyFailedTest() bug');}
        })(i);
    }
};

I tried with label, but I got a syntax error.

Execution :

casper.test.begin('\n*************** Suite of planned test : scenario 1 **************\n', 1, function suite(test) {
    casper.start('https://www.google.fr/', function() {
        verifyFailedTest(3, trueFunction, echoTest);
    });

    casper.run(function() {
        test.done();
    });
});

});

Fanch
  • 3,235
  • 1
  • 18
  • 50
  • Any reason not to use promises? I see you're using `then` already, this looks like a simple promise retry pattern. – Benjamin Gruenbaum May 27 '14 at 14:54
  • This then() comes from the [CasperJS API](http://casperjs.org/) which uses the promise pattern. As promised pattern is not mastered by everyone (not me either :p ), and CasperJS can be used without node, I would prefer to do it in native js. – Fanch May 27 '14 at 15:10
  • 1
    You cannot break this, because the loop is long executed when the `then` blocks are beginning execution. – Artjom B. May 27 '14 at 15:41
  • Yep, I was thinking about it. So I can't do it with a loop. Do you have an idea how to do it? With `repeat()` or something. Because `onWaitTimeout` add a failure and I don't want one. – Fanch May 27 '14 at 15:55

2 Answers2

1

I think can do this without a for loop, by clustering your code into parts and do this recursively:

var verifyFailedTest = function(number, repeatStep, trueReturn){
    var index = 0;
    function intermediate(){
        casper.then(function(){
            repeatStep();
            casper.waitFor(function checkReturnTrue(){
                    return trueReturn();
                }
                , function then() {
                    this.test.pass("Test passes after " + (index+1) + " try");
                }
                , function timeout() { 
                    casper.reload();
                    if (index < number-1) {
                        intermediate();
                    } else {
                        lastTry();
                    }
                    index++;
                });
        });
    }
    function lastTry(){
        casper.then(function(){
            repeatStep();
            casper.waitFor(function checkReturnTrue(){
                    return trueReturn();
                }
                , function then() {
                    this.test.pass("Test passes after " + (index+1) + " try");
                });
        });
    }
    intermediate();
};

You'll have an error only after the number'th try.

But if you want to use your IIFE, the following might work by redefining thenFunction and skipping then block after you know that it is unnecessary (doBreak === true):

var verifyFailedTest = function(number, trueReturn, thenFunction){
    var i = 0, doBreak = false;
    var oldThenFunction = thenFunction;
    thenFunction = function(){
        doBreak = true;
        oldThenFunction();
    };
    for (; i <= number; i++){
        if (doBreak) {
            break;
        }
        // your IIFE here
        (function(index){
            if (index < number-1){
                //Execute 'number-1' times the then() step (reload the page each time) if timeout or until trueReturn returns true
                casper.then(function(){
                    if (doBreak) { return; }
                    casper.waitFor(...);
                });
            }
            //last execution, will return the normal error if it fails each time
            else if (index === number){
                casper.then(function(){
                    if (doBreak) { return; }
                    casper.waitFor(...);
                });
            }
            else{console.log('verifyFailedTest() bug');}
        })(i);
    }
};
Artjom B.
  • 58,311
  • 24
  • 111
  • 196
  • Nop, doBreak remains false in the `verifyFailedTest()` scope. – Fanch May 27 '14 at 15:34
  • @Fanch You can either nest the steps by giving up IIFE or use your IIFE but skip later steps when it succeeded. See my edit. – Artjom B. May 27 '14 at 15:58
  • Ha yes, you're right, I could also use `skip()` method. Thx. Recursively is the cleanest way :p Don't need the timeout() method for the last try, casper defaut error is ok. – Fanch May 27 '14 at 16:11
  • @Fanch Feel free to edit according to your needs and obviously when I made an error. :) – Artjom B. May 27 '14 at 16:25
  • Thx, you can delete the thenFunction argument too. I just tried it with the `uploadFile` function (for an Image) in slimerJS -which seems a little buggy- and it works well. Ty again :) – Fanch Jun 25 '14 at 15:48
0

Use CasperJS's repeat(int times, Function then) function.

Geremia
  • 2,736
  • 25
  • 31