DEV Community

Klaus
Klaus

Posted on • Updated on

Selenium WebDriver and Dynamic Locators

As we all know, functional testing scripts that run through the UI need stable locators in order to locate the elements.

Selenium uses the following locator strategies:
• ID
• Name
• Class Name
• XPath
• CSS Selector
• Tag Name
• Link Text
• Partial Link Text

But what happens if none of those locators are stable?
What happens if even the ID is dynamic and changes with each rendering of the page?

Let's say you want to click on the Register button, which has the register_312312312 ID.

Selenium dynamic ID

The classic way to write the Selenium code would be something like this:

But that won't work, because the next time when you run your test and the page is rendered, it will have a different ID.

We could also write a custom CSS Selector, but our purpose here is to find the ID of that element and use it in our test.

We need to grab on to something that makes that element unique, perhaps an attribute.

But we will need to use JavaScript in order to achieve that.

Luckily, Selenium has the execute_script() method for such cases.

As we can see, the Register button has an attribute named title which has the value Register. This is what makes this element unique on that page.

This is the JavaScript code that you would have to execute in order to find that element and get the ID:

We just have to add that JavaScript code into a variable and execute it in our Selenium code:

Notice how I'm returning that variable which contains the ID to a Python variable. After that, I'm clicking on the element by locating it with the ID from that Python variable.

And voilà, we did it!
We are now handling dynamic locators with Selenium WebDriver.

This can also be executed in Endtest:
Endtest dynamic ID

Top comments (5)

Collapse
 
danielavalero profile image
Daniela Valero

Hello Klaus,

Recently in the Selenium IDE github, someone asked a valid question about Selectors and modern JS frameworks like react of vue: github.com/SeleniumHQ/selenium-ide...

Relevant for my question is:

As a result using ID for selectors is now considered a bad practice to select elements, and bad practice to create a page out of components (it's not unique most of the time).
...
Using these data-test selectors allows for less brittle tests, and they clearly signal that messing with a certain element can cause a test to fail.

At the end, they added: data-test and data-test-id to select as well elements.

Also, in the Selenium/WebDriver website they comment that there is support to select react components, based on their name: webdriver.io/docs/selectors.html#r...

As a passionate for automated testing, what's your view on this? Would you say that using these are a good alternative to use?

Greetings

Collapse
 
razgandeanu profile image
Klaus

Hi Daniela,
Thank you for taking the time to write that comment.
Yes, you can easily write a stable CSS Selector or XPath based on a certain attribute and the value of that attribute. It's ideal if you have an attribute like data-test or data-test-id, but very few web applications actually have those.
If someone would start a project from scratch, I would definitely encourage them to implement and use data-test or data-test-id attributes.

Collapse
 
danielavalero profile image
Daniela Valero

Hello Klaus, thanks a lot!

Collapse
 
mstrelex profile image
Marat Strelets

Is this approach faster than searching with xpath? such as

//*[@state = 'active']

Collapse
 
philnash profile image
Phil Nash

I feel like the code in this post doesn't show an example of when you would need to use this technique, however it shows how to use it.

I can imagine a scenario where none of the Selenium selector strategies would apply (perhaps it moves about in the source of the page and shares attributes and classes with other items on the page) but you still need to pin down your element and get an ID for it. This would work in that case.

I'm pretty sure that using Selenium's native selection methods are what you would choose unless you simply can't get your element using them.