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
WebElement 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.
WebElement 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:
WebElement spanElement1 = $(byText("Order now!"))
WebElement spanElement2 = $(withText("Order"))
WebElement linkElement1 = $(byLinkText("Name of the Link"))
WebElement 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
tip
See also:
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 which are equivalent.
$("#password").sendKeys("secure_pass").pressEnter()
$(byCssSelector("form input:first-child")).sendKeys("my_login")
XPath selector
WEB and DESKTOP
tip
See also:
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 mathing 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
import com.workfusion.odf2.compiler.BotTask;
import com.workfusion.odf2.core.task.AdHocTask;
import com.workfusion.odf2.core.task.TaskInput;
import com.workfusion.odf2.core.task.output.TaskRunnerOutput;
import com.workfusion.odf2.core.webharvest.rpa.RpaDriver;
import com.workfusion.odf2.core.webharvest.rpa.RpaFactory;
import com.workfusion.odf2.core.webharvest.rpa.RpaRunner;
import com.workfusion.rpa.helpers.RPA;
import com.workfusion.rpa.helpers.UiElement;
import com.workfusion.rpa.helpers.UiElementCollection;
import org.openqa.selenium.JavascriptExecutor;
import org.slf4j.Logger;
import javax.inject.Inject;
@BotTask(requireRpa = true)
public class ApplyElementSelector implements AdHocTask {
private final RpaRunner rpaRunner;
private final Logger logger;
@Inject
public ApplyElementSelector(RpaFactory rpaFactory, Logger logger){
this.rpaRunner = rpaFactory
.builder(RpaDriver.UNIVERSAL)
.closeOnCompletion(true)
.build();
this.logger = logger;
}
@Override
public TaskRunnerOutput run(TaskInput taskInput) {
rpaRunner.execute(driver->{
RPA.timeouts(15000);
RPA.openChrome("https://rpa-tutorial.s3.amazonaws.com/trainings/iframe/form.html");
UiElementCollection inputList = RPA.$$("input");
logger.debug("Number of form inputs on a page: " + inputList.size());
logger.debug("ID of the 12th input: " + inputList.get(11).getAttribute("id"));
driver.switchDriver("chrome");
JavascriptExecutor javaexec = (JavascriptExecutor)driver;
for(UiElement input : inputList){
driver.executeScript("alert(\"Input Tag's Attribute Name Value - \" + arguments[0])",input.getAttribute("name"));
RPA.sleep(1000);
RPA.switchTo().alert().accept();
}
});
return taskInput.asResult()
.withColumn("example_bot_task_output", "completed_successfully");
}
}
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.
- Recommended: Add a specific capability to the
plugin.
...
<robotics-flow>
<robot driver="desktop" name="driver1" close-on-completion="true">
<capability name="desktopOptions">
<script return="optionsMap"></script>
</capability>
<script></script>
</robot>
</robotics-flow>
...
- 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=trueparameter.
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).