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

Global/Local variables not changing from within $browser.findElement...getText()


#1

Hello,

I am trying to read a page for specific text and based on that return a value to be used further in the script.

I have the following code:
/**

// Local variables
var Answer = “test”;

// Functions
var FindAnswer = function(Indent, aPromise) {
var QnA = “test”;
var pageText = aPromise.getText()
.then(function(body) {
if (body.indexOf(“About”) != -1) {
this.QnA = “A1”;
console.log(“FOund Search in text”);
Answer = “testing OK”;
}
pageText = “inside bogus”;
return pageText;
});

	console.log(Indent + "outside                  The Answer is: " + QnA);
	
	return pageText;
};

// Begin code
console.log("------------- Initialize -------------");
$browser.get(“https://www.google.com”).then(function(){
console.log("------------- Sign In Page Initial -------------");
console.log("----------------------------------------");
var tempAnswer = FindAnswer(" “, $browser.findElement($driver.By.tagName(“html”)));
console.log(” *** " + tempAnswer + " ***");
console.log(" *** " + Answer + " ***");
console.log("----------------------------------------");
return $browser.findElement($driver.By.css("[name$=q]")).sendKeys(Answer);

})

// End code

And it provides this output:
------------- Initialize -------------
------------- Sign In Page Initial -------------

 outside                             The Answer is: test

*** ManagedPromise::191 {[[PromiseStatus]]: “pending”} ***
*** test ***

FOund Search in text

With “test” being “typed” instead of “testing OK”.

I am new to Selenium and JavaScript so I am not sure what I am doing wrong. Any help is appreciated.

Thanks,
Rick


#2

Hi, @Rick.Bullard: Most Selenium functions (such as getText()) return a promise, not a value. You must provide a function for getText() to call when it completes; the value of the found text will be passed to the function as a parameter:

return $browser.findElement($driver.By.css('h1')).then(
  function(element) {
    return element.getText().then(
      function(text) {
        // do something with text here
      });
  });

#3

I have tried that. I cannot get a string/value out of the “//do something here” section. Which you can clearly see in this snippet:
var pageText = aPromise.getText()
.then(function(body) {
if (body.indexOf(“About”) != -1) {
this.QnA = “A1”;
console.log(“FOund Search in text”);
Answer = “testing OK”;
}

However neither QnA or Answer have those set values/strings when outside that set of code. And that’s where I need that data to be.

Thanks,
Rick


#4

This line of code won’t work:

var pageText = aPromise.getText()

getText() does not return a value, so pageText will not receive anything.

Also, node.js is asynchronous; code does not execute sequentially. This won’t work:

var pageText, QnA, Answer;

return $browser.findElement($driver.By.tagName('body')).then(
  function(element) {
    return element.getText().then(
      function(text) {
        // Set global pageText variable
        pageText = text;
      });
  });

// This code will likely run BEFORE the above code has completed!
if (pageText.indexOf("About") == -1) {
  QnA = “A1”;
  console.log(“Found search in text”);
  Answer = “testing OK”;
}

To ensure that code executes in a specific sequence (in this example, to ensure that the pageText variable is set before you try to read it), you must use then() to chain code blocks together.

That being the case, global variables don’t really make sense. Sure, you can declare a global variable and set it inside a function. But the code that uses the variable must be part of the promise chain; the value you want is probably passed to the function already (see the getText() example above), so there’s no need to use a global variable.


#5

OK, I think I understand where you are going with this.

Let me explain my scenario and maybe you can help me figure out what I am doing wrong. As I am building a synthetic transaction I need to handle multiple paths with each one possibly leading to a single page. In the other programming languages I would handle this as follows:

//declare global variables
var globalVar = "test";

// Common function
function getText(passedInput) {
    if (passedInput == Scenario1) {
        set globalVar = 'S1';
    }
    if (passedInput == Scenario2) {
        set globalVar = 'S2';
    }
    if (passedInput == Scenario3) {
        set globalVar = 'S3';
    }
    if (passedInput == Scenario4) {
        set globalVar = 'S4';
    }
}

// begin code
var getURL = code.to.getURL(www.example.com);
if (getURL == Test1) {
    getText(getURL);
    getURL.sendKeys(globalVar);
}
if (getURL == Test2) {
    getText(getURL);
    getURL.sendKeys(globalVar);
}
if (getURL == Test3) {
    getText(getURL);
    getURL.sendKeys(globalVar);
}

// continue testing
//logout

Obviously there’s a bit more to each scenario and the common function, but I think this gets the basic point across. I really need a way to get that globalVar data back out of any method to verify text on a page.

Thanks,
Rick


#6

Ah, sorry, I didn’t understand that getText() is your function! I thought you were referring to Selenium’s element.getText() function. Let’s use a different name for your function to avoid confusion. :slightly_smiling_face:

So, if I understand correctly, you want to do this:

// Navigate to a URL
// Locate an element on the page
// Get the text of that element
// Based on the text of the element, set a variable to some value
// Locate another element, and input the value of the variable

Here is a working example. (You would replace the getAnswer() function with your if (passedInput == Scenario1)… code):

var assert = require('assert');
var By = $driver.By;

// Global variables
var answer;
var capitals = {};
capitals['Alabama'] = 'Montgomery';
capitals['Alaska'] = 'Juneau';
capitals['Arizona'] = 'Phoenix';
capitals['Arkansas'] = 'Little Rock';
capitals['California'] = 'Sacramento';
capitals['Colorado'] = 'Denver';
capitals['Connecticut'] = 'Hartford';
capitals['Delaware'] = 'Dover';
capitals['Florida'] = 'Tallahassee';
capitals['Georgia'] = 'Atlanta';
capitals['Hawaii'] = 'Honolulu';
capitals['Idaho'] = 'Boise';
capitals['Illinois'] = 'Springfield';
capitals['Indiana'] = 'Indianapolis';
capitals['Iowa'] = 'Des Moines';
capitals['Kansas'] = 'Topeka';
capitals['Kentucky'] = 'Frankfort';
capitals['Louisiana'] = 'Baton Rouge';
capitals['Maine'] = 'Augusta';
capitals['Maryland'] = 'Annapolis';
capitals['Massachusetts'] = 'Boston';
capitals['Michigan'] = 'Lansing';
capitals['Minnesota'] = 'Saint Paul';
capitals['Mississippi'] = 'Jackson';
capitals['Missouri'] = 'Jefferson City';
capitals['Montana'] = 'Helena';
capitals['Nebraska'] = 'Lincoln';
capitals['Nevada'] = 'Carson City';
capitals['New Hampshire'] = 'Concord';
capitals['New Jersey'] = 'Trenton';
capitals['New Mexico'] = 'Santa Fe';
capitals['New York'] = 'Albany';
capitals['North Carolina'] = 'Raleigh';
capitals['North Dakota'] = 'Bismarck';
capitals['Ohio'] = 'Columbus';
capitals['Oklahoma'] = 'Oklahoma City';
capitals['Oregon'] = 'Salem';
capitals['Pennsylvania'] = 'Harrisburg';
capitals['Rhode Island'] = 'Providence';
capitals['South Carolina'] = 'Columbia';
capitals['South Dakota'] = 'Pierre';
capitals['Tennessee'] = 'Nashville';
capitals['Texas'] = 'Austin';
capitals['Utah'] = 'Salt Lake City';
capitals['Vermont'] = 'Montpelier';
capitals['Virginia'] = 'Richmond';
capitals['Washington'] = 'Olympia';
capitals['West Virginia'] = 'Charleston';
capitals['Wisconsin'] = 'Madison';
capitals['Wyoming'] = 'Cheyenne';

// Navigate to a URL
$browser.get('https://www.geographyquiz.org/state-capitals-quiz-2/').then(
  function(){
    // Locate an element on the page
    return $browser.findElement(By.css('div.wpProQuiz_question_text strong')).then(
      function(element){
        // Get the text of that element
        return element.getText().then(
          function(text){
            // Based on the text of the element, set a variable to some value
            answer = getAnswer(text);
          });
      });
  }).then(
    function() {
      // Locate another element, and input the value of the variable
      return $browser.findElement(By.css('input.wpProQuiz_questionInput')).sendKeys(answer);
    });

function getAnswer(question){
  // Extract State name from question
  var stateName = question.match('^What is the capital of (.+[^\?])?')[1];
  return capitals[stateName];
}

#7

BTW, a cool way to write your common function in JavaScript is to create an object that maps inputs to responses:

function getAnswer(input) {
  var responses = {
    'scenario1' : 'S1',
    'scenario2' : 'S2',
    'scenario3' : 'S3',
    'scenario4' : 'S4'
  }
  return responses[input];
}

Then call it like this:

answer = getAnswer('scenario3');

#8

Thank you for the point in the right direction.

It also helps to have a “.then” in between “return $browser” statements. :slight_smile:

Rick