selenium-ide icon indicating copy to clipboard operation
selenium-ide copied to clipboard

Prefer 'data-test' attribute selectors when selecting elements

Open omril1 opened this issue 7 years ago • 15 comments

🚀 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

image

More reliable to use this:

image

omril1 avatar Oct 02 '18 15:10 omril1

That's a really good suggestion, drafting a css locator around that can be very powerful.

corevo avatar Oct 14 '18 12:10 corevo

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.

corevo avatar Dec 16 '18 13:12 corevo

Also these will take precedence over any other locator we can find.

corevo avatar Dec 16 '18 13:12 corevo

@corevo Awesome!

omril1 avatar Dec 16 '18 13:12 omril1

@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

ruinunes avatar May 13 '19 13:05 ruinunes

Correct, this should be if (value) instead.

corevo avatar May 13 '19 14:05 corevo

@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 avatar Nov 11 '19 00:11 bhavanic

@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.getElementById or jquery looking for it when there aren't any.
  • The data-test attribute 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.

omril1 avatar Nov 11 '19 08:11 omril1

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.

corevo avatar Nov 11 '19 08:11 corevo

@omril1 and @corevo - 'data-test' attribute makes better sense now. Thanks for clearing up my concerns.

bhavanic avatar Nov 11 '19 09:11 bhavanic

This seems to be not working when a data attribute on a input tag is nested inside a label tag

image

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

utsavll0 avatar Oct 20 '20 11:10 utsavll0

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

mpgo13 avatar Oct 05 '21 04:10 mpgo13

@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 avatar Sep 01 '22 09:09 Wilhop

@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.

toddtarsi avatar Sep 01 '22 13:09 toddtarsi

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-* 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.

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":

grafik 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!

Mocca101 avatar Oct 03 '23 09:10 Mocca101