CasperJs, how to repeat a step X times onWaitTimeout?
Asked Answered
F

2

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

});

Frasier answered 27/5, 2014 at 13:44 Comment(4)
Any reason not to use promises? I see you're using then already, this looks like a simple promise retry pattern.Thunder
This then() comes from the CasperJS API 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.Frasier
You cannot break this, because the loop is long executed when the then blocks are beginning execution.Creamer
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.Frasier
C
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);
    }
};
Creamer answered 27/5, 2014 at 15:11 Comment(5)
Nop, doBreak remains false in the verifyFailedTest() scope.Frasier
@Frasier You can either nest the steps by giving up IIFE or use your IIFE but skip later steps when it succeeded. See my edit.Creamer
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.Frasier
@Frasier Feel free to edit according to your needs and obviously when I made an error. :)Creamer
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 :)Frasier
L
0

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

Livonia answered 10/11, 2017 at 22:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.