Your data. Anywhere you go.

New Relic for iOS or Android


Download on the App Store    Android App on Google play


New Relic Insights App for iOS


Download on the App Store


Learn more

Close icon

WebElement functions don't seem to execute in a for loop

synthetics

#1

My synthetic script uses the WebElement function getAttribute to read an element’s style and check if a value is present. Unfortunately, for some reason, the getAttribute function just doesn’t seem to execute. I have tried just executing it in the main test function, and I have tried to run it in a separate function, but no luck. I have tried adding console log printouts around it and inside it and the ones outside the getAttribute invocation appear in the console log, but not the ones inside the getAttribute invocation. The method:

function elementStyleIsNotDisplayNone(element) { //element is definitely a web element
  var isNotNone = false;
  console.log("Executing elementStyleIsNotDisplayNone"); //This appears in the script log
  element.getAttribute("style").then(function(style){
  //None of the following console.logs appear in the script log
    if(style!=null){
      console.log("Style: " + style);
      if((style==="display: none;")===false){
        isNotNone = true;
      }
    }
    else{
      console.log("Style is null");
    }
  });

  return isNotNone;
}

Am I invoking it wrong or is something else wrong?

EDIT: In case it helps: the element whose style is being checked is an “li” element from a “ul” list.

EDIT: I’ve tried altering the method to read the element’s class instead, just as a test; same result

EDIT: I have now also tried to have the element invoke isDisplayed() and isEnabled(); they also don’t run. The elements are handled as part of a for loop that checks each “li” element; could that affect it somehow?


#2

Hello @jonathan.pierre, How have you constructed the for loop to iterative over each element? Considering how Node.js handles promises, this may affect what you are trying to achieve. Below you’ll see an example script which uses the forEach method to iterate over each element and checks if the attribute style is display: none;.

var assert = require('assert');

$browser.get('http://www.example.com').then(function(){
  return $browser.findElements($driver.By.className('my-label')).then(function(elements){
    console.log(elements.length)
    elements.forEach(function(element){
      element.getAttribute('style').then(function(style){
        console.log(style)
        if (style == 'display: none;'){
          console.log("It's not displayed!")
        }
      })
    })
  });
});

#3

Hello @abloomer ,

Yes, that is pretty much what I have done.

My $browser call for finding the listed elements doesn’t begin with “return”, but I’ve checked after test runs and the search does find the correct number of elements. After that, I make a forEach call like you do here, but nothing after my equivalent of your “elements.forEach(function(element){” line, except for local console.logs, executes. My forEach also does waits for isDisplayed() and isEnabled() (the search is preceded by entering search criteria into a text field, which hides the listed elements whose names do not match the search and leaves the rest visible), and those functions do not execute either; I know because there are console.logs in those wait functions that are not printed in the log. However, a single console.log in the element forEach() before the functions using the element in the loop does print out in the log. The forEach() code:

allReadNameElements.forEach(function(element){
                                var nameIsVisible = false;
                                console.log("Loop iteration") //This prints in the log
                                var nameElementIsDisplayed = false;

                                var nameElementIsEnabled = false;
                            
                            element.isDisplayed().then(function(eIsDisplayed){
                              //This function does not execute
                              console.log("Checking if element is displayed");
                              nameElementIsDisplayed = eIsDisplayed;
                              console.log("Element is displayed: " + nameElementIsDisplayed);
                            }).then(function(){
                              //Nor this
                                element.isEnabled().then(function(eIsEnabled){
                                console.log("Checking if element is enabled");
                                nameElementIsEnabled = eIsEnabled;
                                console.log("Element is enabled: " + nameElementIsEnabled);
                              });
                            }).then(function(){
                              //This doesn't seem to execute (no printouts in the log seen)
                              if(nameElementIsDisplayed && nameElementIsEnabled){
                                console.log("Should get style")
                                //This is what the function in my original comment did; I'm reintroducing it to 
                                //the main code
                                element.getAttribute("style").then(function(style){
                                  console.log("Obtaining style from listing");
                                  if(style!=null){
                                      console.log("Read style: " + style);
                                    if((style==="display: none;")===false){
                                      nameIsVisible = true;
                                    }
                                  }
                                  else{
                                    console.log("Style is null")
                                  }
                                });
                              }
                            }).then(function(){
                              //This definitely doesn't execute
                              console.log("Name is visible: " + nameIsVisible);
                              if(nameIsVisible){
                                //If the element is displayed, it is pushed to another array, which will
                                //loop to match text in the element to a string and check a box in it
                                //if the text is a match
                                displayedNameElements.push(element);
                              }
                            });
                          });

It has occurred to me that I can just skip that second loop and check the element text in the if(nameIsVisible) section, but all the same I need the function calls related to the listing element function calls to work.

If it helps, this forEach() is executed as part of another forEach() that loops through an array of strings (the search criteria mentioned in the code comments).


#4

Hello @jonathan.pierre, thanks for following up with that extra detail. Could you please send me a link to your Synthetics script so I can take a closer look? Only New Relic employees and authorised users of your account will be able to access it.


#5

Hello @abloomer,

Not sure I can now; I’ve revised the code so it no longer uses the forEach() loop to check the elements; instead it finds them using the text in another element within the “li” element and waits for them to become displayed. I did keep the forEach() section as a comment block, though, and I saved a copy of the code before the fix as a text file that I can send you


#6

Hey @jonathan.pierre - Let us know if you can get that copy of the code uploaded here.
I would like to note that helping to write Synthetics scripts is a little beyond the scope of our Support Team - But if you can share the code we can certainly help you review it and where we see the opportunity, we’ll give you pointers in the right direction.
Thanks in advance for that code. :smiley:


#7

I sent the code as an attachment to the response to the email I got regarding this last comment; did you get it?


#8

Hi @jonathan.pierre - I do not see that code - could you DM it to me here in the Explorers Hub?


#9

I messaged you the code; did you get it?


#10

Hmm - @jonathan.pierre - it looks like I did, however I had not seen a notification for that. I’m sorry - I’ll take a look at the code you sent. :slight_smile:


#11

Hey @jonathan.pierre - I’m afraid that script has not helped much.

Typically when trying to troubleshoot scripts I would try to validate them and use a process of elimination to add & remove sections that may be causing the failure.

I’m afraid with your script including secure credentials - I have no ability to validate it successfully.

With all that said - Synthetics is just a Chrome browser & Selenium WebDriver.js JavaScript environment. It should work with all default JS functionality.

Looking at your account and the monitor failures listed there - I see that there are a lot of Task Timed Out
It’s important to remember that scripts have a non-configurable timeout of 180 seconds. And the docker container the script runs on will auto-shutdown after 4 minutes, to ensure no containers get stuck. Alongside that there is a default pageLoadTimeout of 60s, which is configurable up to 180 seconds.

I would ensure you are using waitForAndFindElement rather than findElement - to ensure your script is given time to find the elements it needs to interact with, as well as watching out for your script running over the time limits. Noting that your script is rather lengthy, timeouts seem like the biggest risk.


#12

Hey, @RyanVeitch

Thanks for the help and the feedback anyway. I’ve updated the script to use waitForAndFindElement instead of findElement where possible, though (at least most of) the TimeoutErrors I’ve seen that occurred for the script I sent are for the page failing to load in time (it’s set to a time limit of one minute before the URL is opened).


#13

Have you tried boosting your pageLoadTimeout above 60s? It can be a max 180s, I’m curious if that has any effect in the scripts success. @jonathan.pierre


#14

Hi again, @RyanVeitch ,

Sure, I’ll try setting it to 120 seconds. Thanks for the tip.


#15

No worries - let us know how it goes.