2

I need a repetitive block like while() that verifies a condition before being executed. My code is below, but the while doesn't work...

var foundPersonen = true;

      while (foundPersonen) {
        detailPage.getAllPersonen().then(function(value) {
          if (value.length == 0) {
            foundPersonen = true;
            remoteControl(Keys.HK_BACK);
            remoteControl(Keys.HK_P_up);
            remoteControl(Keys.HK_INFO, 1, 3000);
          } 
          else {
            foundPersonen = false;
          }
        });
      }

How can I replace the while but still have the same result I need?

oc.bara
  • 81
  • 2
  • 6
  • What language is this? It seems to be C#. It is a bit unclear what the problem is; what exactly do you mean by 'the while doesn't work'? – Codor Mar 29 '16 at 15:04
  • It is javascript - protractor tool. I think that protractor doesn't have while loop, so it needs something similar to solve my problem. I want to repeat that block until my boolean condition becomes false and then stop. If I use this while, my test doesn't even start, I'm getting the browser but the page doesn't load and then it fails with a strange message: <--- Last few GCs ---> 189098 ms: Mark-sweep 1270.6 (1457.6) -> 1270.6 (1457.6) MB, 2569.1 / 0 ms [al location failure] [GC in old space requested]. 192186 ms: Mark-sweep 1270.6 (1457.6) -> 1270.6 (1457.6) MB, 3087.6 / 0 ms [ – oc.bara Mar 29 '16 at 15:16

3 Answers3

2

I agree at least partially with alecxe. Some "wait" order should fix that. I just would like to explain my thought, hoping that it will be useful for you... Because I have spent a lot of time on this kind of problem^^.

The big point to me is that Protractor runs everything asynchronously. When you run your test, Protractor basically runs every part of your code it can, i.e. until it encounters a promise. When it encounters a promise, Protractor could do two things, depending whether you have set browser.ignoreSynchronization = true; (this is my case)

  1. If it's true, Protractor creates a new thread and wait for the promise to be resolved, but in the "main thread" Protractor continues to execute your code. If you want Protractor to wait for something, you will have to write it explicitly.
  2. If it's false (this is the case by default), Protractor will add a browser.waitForAngular before continuing. But of course you can always add explicit waiting orders in your code, and you might want to do it in some cases to get a more stable code.

If you want more information about this, read this post

    var foundPersonen = true;
        while (foundPersonen){
           detailPage.getAllPersonen().then(function(value) {
           if (value.length == 0) {
              foundPersonen = true;
              remoteControl(Keys.HK_BACK);
              remoteControl(Keys.HK_P_up);
              remoteControl(Keys.HK_INFO, 1, 3000);
           } 
           else {
              foundPersonen = false;
           }            
       }

In my case (browser.ignoreSynchronization = true;), this is what happens :

  1. allocate one bit of memory for a boolean and set the value to 1;
  2. evaluate the bit
  3. If it is 1

    Create a thread. In this thread, create a promise and wait for it to be resolved, then do something with the value of the promise

    In the main thread, return to step 2

  4. if it is 0, continue

This interpretation leads to a simple prediction. As the code that sets the value of the boolean to 0 is treated after the promise is resolved, this piece of code will create promises as fast as it can until one of these promises will be resolved and set the boolean to false.

The result of this ? Your code will reach the maximum of memory before the first promise will be resolved. --> You will receive some exception related to the allocation of memory.

I tested that with this code:

    return scenariiSteps.AtlasLogin("my", "credentials")
    .then(function () {

        var foundDialogs = element.all(by.xpath("//div[@dialog-id]"));
        var foundDialogsZero = true;
        while (foundDialogs) {
            foundDialogs.count().then(function (value) {
                if (value == 0) {
                    foundDialogsZero = true;
                    console.log("0, man")
                }
                else {
                    console.log("Found something!")
                    foundDialogsZero = false;
                }
            });
        }
    });

What this code do is

  1. Login
  2. Allocate memory for some object (it will stock the list of the dialogs in the page of my app)
  3. Allocate one bit of memory for a boolean and set it to false.
  4. Evaluate the bit
  5. if it is 1

    create a promise and wait for it to be resolved, then do something with the value of the promise

    return to step 4

And, to be sure of my interpretation, please note that my app contains 2 dialogs as soon as the user is logged in.

As I thought, I received FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory

"Ok, thank you for that long explanation, but... What should I do now ?"

Well basically you have to tell to Protractor to wait for some condition before performing the action you want. The best way to do it depends on your requirements and your environment. For instance, I don't think the solution of alecxe would fix the problem in my environment.

It would be useful to know a bit more about what you want to do if you want more help.

Community
  • 1
  • 1
  • ok thanks a lot... here is what I want to do: I have a TV page -> choose to go to a channel. Once there, get all elements by my specific css. If there is at least one element with that css, do something, if not, go back to main menu from previous page and move to another channel. – oc.bara Mar 30 '16 at 11:26
  • Ok I just can't find a proper way to write code in a comment, but... What do you think about this? I like recursive functions, but you have to be absolutely sure that there is at least one "good" channel of course. However, you can still add some condition inside evaluteChannel. `var evaluateChannel = function(){` `(go to some channel)` `element.all(by.css('identifier')).count().then(function(value){` `if(value === 0){` `evaluateChannel();` `}` `else {` `console.log("Yihaaaa")` `}` `})` `}` – Stéphane Vercouillie Apr 01 '16 at 08:04
1

Yeah, since protractor keep adding everything on to controlflow, blocks like while do not work as expected. Try calling it recursively in a function.

function keepChecking(){
    while (foundPersonen) {
        detailPage.getAllPersonen().then(function(value) {
            if (value.length == 0) {
                foundPersonen = true;
                remoteControl(Keys.HK_BACK);
                remoteControl(Keys.HK_P_up);
                remoteControl(Keys.HK_INFO, 1, 3000);
                keepchecking();
          } 
          else {
            foundPersonen = false;
          }
        });
      }
}
keepchecking();
doppelgreener
  • 4,809
  • 10
  • 46
  • 63
picstand
  • 141
  • 2
  • 13
0

I think you can solve it with browser.wait():

browser.wait(function () {
    return detailPage.getAllPersonen().count().then(function (count) {
        if (count == 0) {
            remoteControl(Keys.HK_BACK);
            remoteControl(Keys.HK_P_up);
            remoteControl(Keys.HK_INFO, 1, 3000);
            return false;  
        }
        else {
            return true;
        }
    }
}, 10000);

This would execute the condition function up to 10 seconds while the count is 0. If it is 0, it executes your remote control functions. Please test.

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • Thanks but this doesn't solve my problem. I need to repeat that block from (count == 0), all the actions from there, until (count != 0). – oc.bara Mar 30 '16 at 09:01
  • @oc.bara `browser.wait()` would continuously execute the function until it evaluates to true or the timeout happens. What happens if you try that? – alecxe Mar 30 '16 at 12:30