Implementing re-usable custom locators for RF SeleniumLibrary
Extending Robot Framework SeleniumLibrary with a plugin that implements DOM testing library inspired locator strategies.

As a full stack developer, I am often involved in multiple different testing phases of an application. Recently, the front-end applications I have been working with have been implemented with React and unit-tested with Jest and react-testing-library. In addition to these unit-tests, the projects have usually had end-to-end tests run in a browser and implemented with Robot Framework and SeleniumLibrary.
These two testing tools, react-testing-libary and SeleniumLibrary, have very different approaches to locating HTML elements. react-testing-library, and all other testing libraries based on the dom-testing-library, provides methods for finding elements in a similar way that the end-user would use, such as findByLabelText()
. SeleniumLibrarys locators are more developer focused and use, for example, elements id
attribute or a XPath expression to locate the element. This difference in locating elements is one of the things that makes transitions between development and testing tasks more challenging for me.
In order to reduce the cost of context switches between development and testing task, I have often implemented some sort of hack to the end-to-end tests in order to produce XPath expressions to match the logic of the finder functions provided by the dom-testing-library. While these hacks have greatly helped to reduce the confusion when switching between these tools, they have not been very clean or re-usable solutions. For example:
*** Keywords ***
Title locator strategy
[Arguments] ${browser} ${locator} ${tag} ${constraints}
${element}= Get WebElements //*[@title='${locator}']
[Return] ${element}Add custom locator strategies
FOR ${name} ${keyword} IN
... title Title locator strategy
# Other custom locators
Run Keyword And Ignore Error
... Add Location Strategy ${name} ${keyword}
END
After implementing a very similar hacky solution to many different projects, I decided to look into implementing these dom-testing-library inspired locators as custom locators that could be installed as a Python package. According to the most recent recommendations on how to extend SeleniumLibrary, it seemed like the way to go would be to implement the custom locators in a SeleniumLibrary plugin.
The plugin interface of the SeleniumLibrary provides an easy way to extend the default element finder. The element finder can be modified through the element_finder
property of LibraryComponent
, which is the base class that the plugin class must inherit. The default element finder can be created as an instance of ElementFinder
by providing the constructor with the same context as the plugin class instance is initialized with. This created ElementFinder
instance can then be used to register the custom locator strategies.
My solution replaces the default element finder with a new element finder that registers custom locators to implement the dom-testing-library style locators when the plugin is loaded. This allows easy re-usability and simplifies the setup process a lot. See import and usage example below.
*** Settings ***
Library SeleniumLibrary plugins=TestingLibrarySelectorsPlugin*** Test cases ***
Click search bar
Click element placeholder:Search
The actual locator functions are mostly just wrappers for the xpath:…
locator strategy of the SeleniumLibrary. At the moment, the only more complex locator is the find by label strategy, which will first find all the label elements with matching for
or id
attributes. This will allow locating input fields with matching id
or aria-labelledby
attributes. See the _plugin.py
file in GitHub for the implementation.
At this point I had pretty much all of the features implemented that I have been usually using and could have been happy with what I had implemented. However, as the dom-testing-library supports also regexps and functions to match elements, I wanted to try something similar. Parsing the regexps from the locator criteria and passing it to matches()
function in XPath expression seemed simple enough. And it was, but any of the browsers available didn’t seem to support this approach. Nevertheless, I still wanted to know if these XPath expressions are valid.
In order to test the XPath expression which uses the matches function, I decided to use the lxml Python library. While lxml also lacks the support for matches function out-of-the-box, it provides an option to implement custom functions to be used in the XPath expression. I implemented a custom matches()
function that seems to find elements as expected. Could be possible that I made similar mistakes twice, but I would argue that there is no hurry to fix possible bugs before the matches()
function, and XPath2 in general, is supported by any of the target browsers.
To summarize, I implemented a custom locator strategies for SeleniumLibrary as a plugin. My goal was to decrease the cost context switches when moving from development to testing tasks, and vice versa. The code is available in GitHub and as a python package.
Step-by-step getting started
In order to be able to use these locators in your Robot Framework Selenium library:
- Install rf-se-dtl-selectors-plugin by running
pip install rf-se-dtl-selectors-plugin
. - Add TestingLibrarySelectorsPlugin to plugins parameter of SeleniumLibrary import:
*** Settings ***
Library SeleniumLibrary plugins=TestingLibrarySelectorsPlugin
- Use provided custom locators, for example:
*** Test cases ***
Click search bar
Click element placeholder:Search