Skip to main content
Version: 10.2.4

Apply element selectors

Selectors (or Locators) are used to find and match the elements of a web page or desktop app that a robot needs to interact with. Using the right selector ensures the bots are faster, more reliable or has lower maintenance over releases. If you’re fortunate enough to be working with unique IDs and Classes, then you’re usually all set. It can be a real challenge to verify that you have the right selectors to accomplish what you want.

This tutorial explains different selectors, how, when and ideal strategies to use these selectors.

Web selectors​

ID selector​

WEB

IDs are the most preferred way to locate elements on a page, as each ID is supposed to be unique which makes IDs a very fast and reliable way to locate elements.

With this strategy, the first element with the ID attribute value matching the selector will be returned. If no element has a matching ID attribute value, NoSuchElementException is raised.

Example: if an element is given like this:

<form name="loginForm">
Login Username:
<input id="username" type="text" name="login" />
Password:
<input id="password" type="password" name="pass" />
<input type="submit" name="signin" value="SignIn" />
</form>

You can easily choose the element with the help of ID selector from the above example:

  • id = username
  • id = password
def elementUser = $(byId('username'))

elementUser.val('my_login')
$(byId('password')).sendKeys('secure_pass').pressEnter()

Even though this is a great selector, obviously it is not realistic for all objects on a page to have IDs. In some cases, developers make it having non-unique IDs on a page or auto-generate the iIDs, in both cases it should be avoided.

Name selector​

WEB

This is also an efficient way to locate an element with name attribute, after IDs give it your second preference but likewise IDs, name attributes don’t have to be unique.

With this strategy, the first element with the name attribute value matching the selector will be returned. If no element has a matching name attribute, NoSuchElementException is raised.

def elementUser = $(byName('login'))

elementUser.setValue('my_login')
$(byName('pass')).sendKeys('secure_pass').pressEnter()

Text selector​

WEB

You can find elements by their inner text using the following selectors.

  • byText returns all elements with given text (exact match).
  • withText returns all elements containing given text (substring).
  • byLinkText returns all anchor <a> elements with given text (exact match).
  • byPartialLinkText returns all anchor <a> elements containing given text (substring).

Sample HTML element

<a href="link.html">Name of the Link</a>
<button>Order now!</button>

To click this hyperlink or button using the tag’s text, you can use the following text selectors:

def spanElement1 = $(byText('Order now!'))
def spanElement2 = $(withText('Order'))

def linkElement1 = $(byLinkText('Name of the Link'))
def linkElement2 = $(byPartialLinkText('Name of'))

Tag and attribute selectors​

WEB

Let's automate the following form using tag and attribute selectors:

<p><abbr title="World Health Organization">WHO</abbr> was founded in 1948.</p>
<form name="loginForm">
Login Username:
<input id="username" type="text" name="login" class="login" />
Password:
<input id="password" type="password" name="pass" />
<input type="submit" name="signin" value="SignIn" />
</form>

You can use the following selectors:

  • byTitle
  • byValue
  • byTagName
  • byClassName
  • byAttribute
  • by('attribute-name', 'attribute-value')
$(byTitle('World Health Organization')).getText()
$(byValue('SignIn')).click()
$(byTagName('p')).getText()
$(byClassName('login')).sendKeys('username')
$(byAttribute('type','text')).sendKeys('username')
$(by('value','SignIn')).click()

CSS selector​

WEB and DESKTOP

Let's automate the following form using CSS selectors:

<form name="loginForm">
Login Username:
<input id="username" type="text" name="login" />
Password:
<input id="password" type="password" name="pass" />
<input type="submit" name="signin" value="SignIn" />
</form>

You can use both $() and $(byCssSelector) selectors that are equivalent.

$('#password').sendKeys('secure_pass').pressEnter()
$(byCssSelector('form input:first-child')).sendKeys('my_login')

XPath selector​

WEB and DESKTOP

While DOM is the recognized standard for navigation through an HTML element tree, XPath is the standard navigation tool for XML; and an HTML document is also an XML document (xHTML).

Example: to select the username from the above example you can use the following ways:

$(byXpath("//*[@id='username']"))
$(byXpath("//input[@id='username']"))
$(byXpath("//form[@name='loginForm']/input[1]"))
$(byXpath("//*[@name='loginForm']/input[1]"))

Desktop selectors​

The following selectors are available for Desktop driver:

\$ Or byCssSelector​

Example: CSS Selectors

\$ Or object selector​

Example: Object Selectors

byXpath​

Example: Automating SwingSet App

byImage​

Example: Surface-based Robotics driver

FindElement (\$) and FindElements (\$\$) commands​

The difference between findElement() and findElements() method is the first returns an uiElement object otherwise it throws an exception and the latter returns a list of uiElements, it can return an empty list if no elements match the query.

findElement(): \$()​

  • On Zero match: throws NoSuchElementException
  • On One match: returns uiElement
  • On One+ match: returns the first uiElement matching the specified selector

findElements(): \$\$()​

  • On Zero match: returns an empty list
  • On One match: returns a list of one uiElement only
  • On One+ match: returns a list with all matching instances
Expand to see the example with findElements
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://web-harvest.sourceforge.net/schema/1.0/config" scriptlang="groovy">
<robotics-flow>
<robot name="robotDriver" driver="internet explorer" close-on-completion="true" start-in-private="true">
<script><![CDATA[
timeouts(15000)
open("https://rpa-tutorial.s3.amazonaws.com/trainings/iframe/form.html")

def inputList = $$('input')
log.warn('Number of form inputs on a page: ' + inputList.size())
log.warn('ID of the 12th input: ' + inputList.get(11).getAttribute('id'))

inputList.each {
executeScript('alert(arguments[0])', it.getAttribute('name'))
}

]]></script>
</robot>
</robotics-flow>
<export include-original-data="false"/>
</config>

Win32 desktop applications​

To accelerate finding UI elements of Win32 applications, you may use a specific search capability allowing to perform a search among components with a handle attribute only.

caution

Mind that the solution works best when used for applications built on the Win32 technology. When attempting to find elements without a handle attribute (for example, in applications like Microsoft Outlook 2016), you may face performance degradation instead.

There are two ways to enable advanced searching for UI elements.

  1. Recommended: Add a specific capability to the <robot/> plugin.
...
<robotics-flow>
<robot driver="desktop" name="driver1" close-on-completion="true">
<capability name="desktopOptions">
<script return="optionsMap"><![CDATA[
optionsMap = ['FindByHandle':true]
]]></script>
</capability>
<script><![CDATA[
...
]]></script>
</robot>
</robotics-flow>
...
  1. Optional: If you have a number of scripts and it's time-consuming to add a capability to each of them, you may launch a Worker with the option allowing to constantly execute a search by handle for all of these scripts. Mind that in this case, only the scripts automating Win32 applications should go to the specified Worker. To apply the option, launch the Worker adding the -DdesktopOptions.FindByHandle=true parameter.
note

If two of the above-mentioned ways are used, adding the capability is preferable, as a search like this can be applied not only for the entire Worker but for a specific script (a step in the business process).