selenium-ide
selenium-ide copied to clipboard
Prefer 'data-test' attribute selectors when selecting elements
🚀 Feature Proposal
Prefer CSS attribute selectors that are dedicated for testing when selecting an element. Common conventions that I know of are and seen a lot in the wild are:
[data-test][data-test-id][data-testid]
And the rival project cypress has [data-cy].
Motivation
A lot of the modern web development workflow moved away from designing by page - to designing by component (frameworks such as react/vue/angular).
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).
Also note that some of the "CSS-in-JS" workflows such as when using css-modules in webpack will create unique classes for each component, so the names are changing frequently when changing styles.
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.
These selectors also allow the user to to remove them easily if he doesn't want them to show in production code and increase bundle size.
Example
When using the select target feature it should look for these data-test selectors befure id, class, or xpath selectors.
class generated with css-modules

More reliable to use this:

That's a really good suggestion, drafting a css locator around that can be very powerful.
Fixed in 5f672a7f.
For the time being I've added data-test and data-test-id, I don't want to fill it with custom things by default, we will add a settings page to the IDE where you could specify custom ones at a later date.
Also these will take precedence over any other locator we can find.
@corevo Awesome!
@corevo, I wasn't able to use data-test-id. Only data-test.
The method returns too soon for data-test, hence data-test-id does not get evaluated.
https://github.com/SeleniumHQ/selenium-ide/commit/5f672a7ff8bf1345a81fe3c36b15f48ffdfd7cc6#diff-8d485dc1a3c8d818231087476f3d4ae6R296
Correct, this should be if (value) instead.
@omril1 May I know how using data-test attribute is any better than using an id? what I don't get is - if id and data-test-id attributes exist at the same level (either at the component or at the composer), shouldn't both attributes face the same problems?
@bhavanic It's about communication and separation of concerns.
- When you use data-test it is clear that the attribute is for automated tests to find this element, and there should be no other use for the attribute.
- During refactoring the attribute it would be clear that there are tests in regarding the element/component that should be addressed.
- Using plain simple ids can signal or hint that there is a
document.getElementByIdor jquery looking for it when there aren't any. - The
data-testattribute can be automatically safely removed from production code when needed by a babel plugin in react apps to remove redundant code, while ids can still affect selectors in code, assistive accessibility technologies etc.
Right, id is an attribute that has DOM implications to it, meaning it already has use cases for the normal operation of the web app, overloading it with test based use cases could lead to unexpected issues.
Instead using a specific attribute designed for testing could be beneficial, especially in situations where you can't control the element's id attribute but can freely add data attributes.
@omril1 and @corevo - 'data-test' attribute makes better sense now. Thanks for clearing up my concerns.
This seems to be not working when a data attribute on a input tag is nested inside a label tag

For the first case it is picking up the data attribute correctly but for rest two where the input tags are nested it doesnt seem to work or rather is showing inconsistent behavior.
Apart from this also the IDs if nested are not getting picked up from the above image
@corevo please check it up
This seems to be not working when a data attribute on a input tag is nested inside a label tag
you could try to set pointer-events: none to the input element
@omril1 May I know how using data-test attribute is any better than using an id? what I don't get is - if id and data-test-id attributes exist at the same level (either at the component or at the composer), shouldn't both attributes face the same problems?
It's a good valid question, which I was asking before I ran into an Angular application. I turns out anything and everything is dynamic in Angular (obviously depending on use cases). Let's look at:
<div id="cdk-overlay-5" class="cdk-overlay-pane" style="width: 600px; position: static;">
What if.. suddenly after a build, it becomes:
<div id="cdk-overlay-6" class="cdk-overlay-pane" style="width: 600px; position: static;">
Now when we introduce "data-testid" or any other custom attribute, we can build the logic to be as stable as we possible can. For example, the same re-usable main button can exist anywhere, but it will eventually be unique to in the context and we can hardcode a "data-testid" or look around if a combination of component file or similar would make it unique. Moral of the story: Id isn't as unique as we think in modern web development.
@Wilhop - Well, id should definitely be unique. But we all agree with you. data-* or data-test-* attributes tend to be king. We currently use https://github.com/antonmedv/finder for our css selector library and need to look at increasing the priority there using their tooling.
It might be related to what @Wilhop mentioned in this comment:
@Wilhop - Well, id should definitely be unique. But we all agree with you.
data-*ordata-test-*attributes tend to be king. We currently use https://github.com/antonmedv/finder for our css selector library and need to look at increasing the priority there using their tooling.
But currently it seems to not prefere data-test as a selector if it's only present in a parent element. E.g. I'm working on a webapp using Vue & Vuetify. When I add the data-test="some-id" to the v-btn element, the generated component will be a parent element holding the attribute like a <a ...data-test="some-id"... >, <button ...data-test="some-id"... >,.. with one or more child elements that usually hold the text or other content.
When I click on the content, this results in SIDE recording selectors like: css=.v-btn:nth-child(11) > .v-btn__content instead of what I'd expect: css=*[data-test="some-id" > .v-btn__content].
However, when clicking outside the content but inside the button, it does produce the expected selector.
Example of a generated component for which it "fails":
and it's corresponding code:
<v-btn
text
to="/log"
data-test="log-link"
>
{{ $t('TopNavigationBar.log') }}
</v-btn>
Please tell me if there's any more clarification I might be able to give and thanks for all your work!