Integrating jQuery With Selenium
When testing JavaScript-heavy websites, at some point you may reach Selenium limits. A simple use case will fail. You will get ElementNotVisibleException
, even though you can clearly see that element. Other times the same selector will return different results depending on the type of the browser. You can lose a lot of time searching for workarounds and hacks. Fortunately, a simple solution exists...
<p>…but first let me introduce you to a new concept.</p>
JavaScript in Selenium tests
Did you know you can execute JavaScript code inside a Selenium test? Here is how you can accomplish this using the WebDriver
object:
The result is this pop-up:
You can go further and return a JavaScript object. It will then be transformed into a Java WebElement
object, on which you can execute standard Selenium methods. If on a page there was a DIV
element with ID equals "example":
Then you could fetch that element with this piece of code:
jQuery to reduce verbosity
Using pure JavaScript alone may be very verbose. jQuery can help here with its concise and elegant syntax. With jQuery you can:
- use a great deal of selectors that work pretty much the same on every browser
- use jQuery functions for interaction with a page (for example to do double click use the
.dblclick()
function) - easily bypass any Selenium bug by putting JavaScript code in your tests
Example scenario
Assuming we have a page for editing a list of users which looks like this:
...with HTML
code looking like this:
Lets try to test the following scenario:
- Web browser is opened.
- Page with a list of users is shown.
- User 'Bob' is removed from the list by clicking the 'Remove' button in front of his name.
selenium3
package). This short video demonstrates what we are trying to accomplish:
Clicking a button with jQuery
First we should come up with a proper jQuery selector:
Here is an explanation how this selector works:
To click the button that is returned as a result of our selector we can use this piece of code:
If we want to do the clicking part on the Selenium side we should write this instead:
The jQuery get
method is used to unwrap the jQuery decorator object and return the native DOM object. Without parameters this method returns a list of unwrapped objects. Only one BUTTON
is expected to be returned, so it is more appropriate to use the get
method with an integer parameter. This parameter specifies which element from the list should be returned. In our case it is the first element, so we can use the method call: .get(0)
.
jQuery selectors using the Selenium
class
If you want to use the jQuery selectors alone, a sensible solution is to use the com.thoughtworks.selenium.Selenium
class. It provides lots of helper methods for interacting with a website. Creating the Selenium
object is as simple as wrapping the WebDriver
object:
Again, if we want to remove the user named Bob, we should prepend the previous selector with the type "css=" and put the result as a parameter to the click
method of the Selenium
object:
Things to consider
We reached the outcome we wanted, but there are still some points we should consider:
- What to do if we are not using jQuery on our website and are unable to use it? (we are either constrained by requirements or have no access to the sources)
- What are the drawbacks of this technique?
Loading jQuery from within a test
If your site does not use jQuery and you do not want or cannot put the appropriate script tag, you can still use it by:
- loading the contents of the jQuery code into a
String
from a JavaScript file (jquery.js
,jquery.min.js
or similar) - ...and executing this
String
as JavaScript code using theWebDriver
object
String
you can use the Guava library. In case you were not using it already, here is the Maven dependency:
To fetch the contents of a file the com.google.common.io.Resources
class proves to be useful. Here is how you can use it to load jQuery from within a test:
Avoid the side effects
Using jQuery with Selenium is not always a bed of roses. It can significantly simplify your tests or solve your problem, but you should take into consideration the impact of injecting JavaScript code into a tested website. When using this technique think carefully whether it:
- changes the website's flow
- may hide a bug
- enables access to an element that is otherwise not visible
- tides your test with the implementation of the website
Final thoughts
You have aquired a new tool in your toolbox. It can improve the development of Selenium tests. On the other hand it should not be overused. Understand the potential side effects and try to avoid them.