What is JavascriptExecutor in Selenium?


In Selenium Webdriver, locators like ID, Name, XPath, CSS, etc. are used to identify and perform operations on a web page. And there are certain cases when these locators do not work. Here I am talking about some examples and these are from my first-hand experience. Let's get started-

Case 1:
In this case, we talk about elements that show up on UI and works fine when interacted manually but not using code. You cannot reach these elements in desired or conventional ways and performs actions on them using the locators in Selenium. Like, a click action on a radio button or a checkbox or a normal button. What you see in the below screenshot is one such button named Publish. This element is not interactable when we approach it with any kind of locator in Selenium. But manually it works as expected.






Well, that’s a different story of how this happened. This is a low priority issue because the element is behaving as expected when tested manually. So we are not bothered to debug and spend time on it. Sounds fair to me!

In such cases, JavaScriptExecutor comes handy and becomes a life saviour. You can use JavaScriptExecutor to perform the desired operation on a web element. And the good news is Selenium supports javascript executor

There is no need for an extra plugin or add-on. All you have to do is import (org.openqa.selenium.JavascriptExecutor) in the script to use JavaScriptExecutor.






JavaScriptExecutor provides two methods :

  • executescript()
  • executeAsyncScript()

These methods run javascript on the selected window or current page. Using these methods JSExecutor injects javascript into the browser for desired actions.

I will not go into how each of these methods works as there are 100's of posts out there, coping definition form the selenium doc!! some of them are 100% original too. But I prefer to read the one that has copied content....for FUN :D

Joke's apart, let's have a look at a simple example in the beginning.

Something similar to Publish button (I spoke it about in the beginning), I have a Save button next to it in my application which is not easy to locate using any of the available locators. The HTML for the save button looks like as shown below. 







But when we try to call a click action to save the form using btn_saveArticle.click() the code throws below exception -


org.openqa.selenium.ElementNotInteractableException: Element [button id="save-button" class="btn button" type="submit"] could not be scrolled into view

hmmmmmm....sounds familiar!!

To avoid such hurdles, executeScript() becomes really handy. Let us see the code below in the example below that will help us in clicking the Save button using one of these functions.

so we know the ID of the Save button from the available HTML and using it we will write a one-liner javascript and feed the executeScript() with it.

((JavascriptExecutor) driver).executeScript("document.getElementById('save-button').click();");

So what exactly happened here is pretty self-explanatory and straight forward. I tried to reach the button from the browser's Dev-tool Console window and ran javascript from the above line of code. It worked unlike my Selenium-Java code and hence I used it with executeScript() to call a Click action. 

That's a breather!!

Case 2:
In this case, we will see what happens when an element is perfectly visible in DOM when searched using XPath but when approached with an intent of performing an operation on it like a Click action, makes no change in UI, for 30% of the time. This makes the test flaky in nature. Although there are other measures that one can take to prevent such slips in code by using Action
class in selenium. But I am not a fan of Action class after I know that I can use something that is more firm and certain.

What you see in the below screenshot is a very notorious checkbox. It is as stubborn as my 3-year-old. Half of the time it doesn't listen to the click action and ignores it exactly when you need it to work especially when you are in public areas like Demos !!












So I try to take firm measures and gets inside the head of this issue and used the below line code -

((JavascriptExecutor)driver()).executeScript("arguments[0].click()",element);

What executeScript() the method does in this case
1.    Reference of the element as arguments[0] 
2.    Along with the method to be performed [in this case click()] and 
3.    The references of the element should be provided thereafter.
Similarly, an example of executeScript() with multiple arguments[] is as follows :

JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].setAttribute('style', arguments[1])", driver.findElement(By.xpath("//input[@type='file']")), "0");

Here in the above example :
  • driver.findElement(By.xpath("//input[@type='file']")is referred as arguments[0]
  • "0" is referred as arguments[1]

Have fun playing with the second example!!



executeAsyncScript() on the other hand will execute an asynchronous piece of JavaScript in the context of the currently selected component or element or window in Selenium. The JS so executed is single-threaded with a various callback function which runs synchronously. With Asynchronous script, your page renders more quickly. Instead of forcing users to wait for a script to download before the page renders. 

ThatIsSoMuchOfCopiedTextToRead!! Isn't it? 

So this we will understand in a different blog where we will talk about callback in javascript if it interests me to write another post. But for understanding, if there are function calls that are dependent then use them in a callback (hence they will be called in sequence) and separate the other function call with the sequence, flow to run them asynchronously.


Conclusion:
I do not see any difference in using both these functions interchangeably because I may not have reached that point in writing test automation where I have to dig more and make use of executeAsyncScript() for a specific occasion. But I prefer to use executeScript() over executeAsyncScript() because of it's simplicity obviously.

I hope this post of mine has helped you in desired ways. Please do write to me with your suggestions and comments to improve this article for the reader of this community :)

Until then - Chow


P.S. I am tired of formating this post !! The editor window here s***s 
Please, ignore the poor formatting :(

Comments

Popular posts from this blog

Frequent Test Automation Pitfalls

Anti-Patterns in Test Automation - Part 1

Exploratory testing Vs Documentation in Agile