How to execute JavaScript code in Selenium WebDriver

javascript

 

WebDriver tests need to be executed in multiple browsers.

And sometimes, you get different results.

A button can be clicked correctly in Firefox but not in Chrome.

What do you do in this case?

Changing the locator may work.

Executing JavaScript may work as well.

Let’s investigate Javascript in this article.

What can you do with Javascript?

You can do with Javascript pretty much everything you can do through the WebDriver library:

  • click an element
  • type a keyword in a textbox
  • select an option from a listbox
  • get the value of an element
  • find an element

But Javascript allows you also to do other things such as modify web elements by changing their color, or font size.

Or even removing them from the  page.

How to … in Javascript

Lets start with a simple example:

public class TestClass {

WebDriver driver;
By searchTextBoxLocator = By.id("globalQuery");
By searchButtonLocator = By.xpath("//input[@class='search_button']");
By firstResultLocator = By.xpath("(//a[@testid='bib_link'])[1]");
By resultTitleLocator = By.id("item_bib_title");

@Before
public void setUp() {
  System.setProperty("webdriver.chrome.driver",
     "C:\\Selenium\\BrowserDrivers\\chromedriver.exe");

  driver = new ChromeDriver();
}

@After
public void tearDown() {
  driver.quit();
}

@Test
public void testWithSelenium()
{
   driver.get("http://www.vpl.ca");

   WebElement searchField;
   searchField = driver.findElement(searchTextBoxLocator);
   searchField.click();
   searchField.sendKeys("java");

   WebElement searchButton;
   searchButton = driver.findElement(searchButtonLocator);
   searchButton.click();

   delay(5);

   WebElement searchResultLink;
   searchResultLink = driver.findElement(firstResultLocator);
   searchResultLink.click();

   delay(5);

   WebElement bookTitleElement;
   bookTitleElement = driver.findElement(resultTitleLocator);
   String bookTitleValue;
   bookTitleValue = bookTitleElement.getText();
   assertTrue(bookTitleElement.isDisplayed() == true);
   assertTrue(bookTitleValue.length() > 0);

}

 

The test script does the following:

  1. open the site
  2. execute a search
  3. click on the 1st result from the results page
  4. check if the book element is displayed in the details page
  5. check if the book value is not empty on the details page

 

Lets re-write it and use Javascript instead of WebDriver methods:

public class TestClass {

WebDriver driver;
JavascriptExecutor jsExecutor;

@Before
public void setUp() {
  System.setProperty("webdriver.chrome.driver",
     "C:\\Selenium\\BrowserDrivers\\chromedriver.exe");

  driver = new ChromeDriver();
  jsExecutor = (JavascriptExecutor) driver;
}

@After
public void tearDown() {
  driver.quit();
}

@Test
public void testWithJavaScript()  {

  driver.get("http://www.vpl.ca");

  //type a keyword in the search text box
  String typeKeywordJS = 
  "document.getElementById('globalQuery').value='java'";
  jsExecutor.executeScript(typeKeywordJS);

  //click the search button
  String clickSearchJS = 
  "document.querySelector(\"[class='search_button']\")" +
  ".click()";
  jsExecutor.executeScript(clickSearchJS);

  delay(5);


  //click the 1st result from the results page
  String clickResultJS = 
  "document.querySelector(\"a[testid='bib_link']\")" + 
  ".click()";
  jsExecutor.executeScript(clickResultJS);

  delay(5);


  //gets the book title value from the details page
  String getTitleJS = "function getTitle() {" +
  "var title=document.getElementById('item_bib_title')" +
  ".innerHTML;"+
  "return title; }; "+
  "return getTitle()";

  String bookTitleValue = 
  (String)jsExecutor.executeScript(getTitleJS);

  System.out.println(bookTitleValue.trim());
  assertTrue(bookTitleValue.length() > 0);


  //gets the book element from the details page
  String getTitleElementJS = "function getTitleElement(){"+
  "var title = document.getElementById('item_bib_title');"+
  "return title; };"+
  "return getTitleElement()";

  WebElement bookTitleElement = (WebElement)jsExecutor
       .executeScript(getTitleElementJS);

  assertTrue(bookTitleElement.isDisplayed() == true);
  System.out.println(bookTitleElement.getText());
  System.out.println(bookTitleElement.getTagName());

}

 

How easy was this?

Every time I execute a Javascript query, 2 things are needed

  • prepare the Javascript query in a String variable
  • execute it with a Javascript Executor

The Javascript queries that interact with a web element are very simple.

But if the Javascript query returns a value, the query should include a return statement:

String getTitleElementJS = "function getTitleElement(){"+
" var title = document.getElementById('item_bib_title');"+
" return title; }; "+
" return getTitleElement()";

When executing the query, its result should be casted to the type of expected result.

The previous query returns an element so the result of the executeScript() method is casted with (WebElement):

WebElement bookTitleElement = 
(WebElement)jsExecutor.executeScript(getTitleElementJS);

What else can we do with Javascript?

 

  • highlight elements:
String jsQuery = 
String.format("%s.style.backgroundColor='red'", locator);
jsExecutor.executeScript(jsQuery);

 

  • wait until the whole page is loaded:
private void waitUntilPageLoaded() {
  Boolean isLoaded = false;
  while (!isLoaded) {
    isLoaded = isPageLoaded();
    delay(1);
  }
}

private Boolean isPageLoaded() {
  String jsQuery = "function pageLoaded() "
  + "{var loadingStatus=(document.readyState=='complete');
  + "return loadingStatus;};"
  + "return pageLoaded()";

  return (Boolean)jsExecutor.executeScript(jsQuery);
}
  • zoom in the page:
String zoomInJS = "document.body.style.zoom='50%'";
jsExecutor.executeScript(zoomInJS);

 

  • scroll until an element is in view:
String scrollToElementJS = "element = document.getElementById("divId");
element.scrollIntoView(true);";
jsExecutor.executeScript(scrollToElementJS);

 

We can do many things with JavaScript if they cannot be done with the Selenium WebDriver framework.

Your automation project should have Javascript methods for common ways of interacting with web element:

  1. find element
  2. type text into textbox
  3. click element
  4. get the value of an element
  5. highlight an element

 

See below the initial Selenium code updated for Javascript methods:

String searchKeywordJSLocator = 
"document.getElementById('globalQuery')";

String searchButtonJSLocator = 
"document.querySelector(\"[class='search_button']\")";

String firstResultJSLocator = 
"document.querySelector(\"a[testid='bib_link']\")";

String resultTitleJSLocator = 
"document.getElementById('item_bib_title')";

@Test
public void testWithJavaScript()  {

  driver.get("http://www.vpl.ca");

  waitUntilPageLoaded();

  highlightElement(searchKeywordJSLocator);
  typeJS(searchKeywordJSLocator, "java");

  highlightElement(searchButtonJSLocator);
  clickJS(searchButtonJSLocator);

  waitUntilPageLoaded();

  highlightElement(firstResultJSLocator);
  clickJS(firstResultJSLocator);

  waitUntilPageLoaded();

  String bookTitleValue = getValueJS(resultTitleJSLocator);
  assertTrue(bookTitleValue.length() > 0);

  highlightElement(resultTitleJSLocator);

  WebElement bookTitleElement = 
  getElementJS(resultTitleJSLocator);

  assertTrue(bookTitleElement.isDisplayed() == true);

}

private void highlightElement(String locator) {
  String jsQuery = 
  String.format("%s.style.backgroundColor='red'", locator);

  jsExecutor.executeScript(jsQuery);
}

private void typeJS(String locator, String keyword) {
  String jsQuery = 
    String.format("%s.value='%s'", locator, keyword);

  jsExecutor.executeScript(jsQuery);
}

private void clickJS(String locator) {
  String jsQuery = String.format("%s.click()", locator);
  jsExecutor.executeScript(jsQuery);
}

private String getValueJS(String locator) {

  String jsQuery = 
      String.format("function getValue() " +
      "{var value=%s.innerHTML;return value;};" +
      "return getValue()", locator);

  return (String) jsExecutor
         .executeScript(jsQuery);

}

private WebElement getElementJS(String locator) {

  String jsQuery = 
    String.format("function getElement()" +
          "{var element = %s; return element; }; " +
          "return getElement()", locator);

  WebElement element = 
    (WebElement) jsExecutor.executeScript(jsQuery);

  return element;
}

private void delay(int seconds) {
   Thread.sleep(seconds * 1000);
}

private void waitUntilPageLoaded() {
  Boolean isLoaded = false;
  while (!isLoaded) {
    isLoaded = isPageLoaded();
    delay(1);
  }
}

private Boolean isPageLoaded() {
   String jsQuery = "function pageLoaded() "
                       + "{var loadingStatus = "
                       + (document.readyState == 'complete');"
                       + "return loadingStatus; }; "
                       + "return pageLoaded()";

    return (Boolean)jsExecutor
        .executeScript(jsQuery);
 }
}

 

Advertisement

One Comment

  1. Thank you for the above topic. I am using the ExecuteScript(“document.querySelectorAll(‘#’)”) method in my C# code. Here, I am trying to get all the elements in the page. When I debug the program the above script stores Element Ids. Is this the expected result? What I would like to see is all the elements in the page, the same output as I see for the document.querySelectorAll(“”) in Console window in Chrome. Could you please help? Thank you.

    Like

    Reply

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s