Why is data-* attributes preferred for element selection over a plain ID attribute? - selenium-webdriver

Cypress and many other posts around testing web applications suggest relying on a data attribute like data-cy or data-test-id for locating elements rather than relying on the id attribute.
My understanding is that for two reasons:
The modern way of re-using the components can lead to having multiple components of the same type and can lead to multiple of those IDs on the same page - But this should also apply to the 'data-cy' or 'data-test-id' attributes.
When IDs are tied to CSS, there's a tendency to change them more often while data-* attributes may be less prone to change.
Can someone please throw more light on the recommendation?
The other thing I am considering is to request my devs to place the data-test* attributes on a div tag that would consume the component - that way the test attribute is actually one level above the component id attribute and may come handy even in cases where multiple instances of the same component are used. But again, I am not sure why the id attribute for that div tag is bad when compared to the data-test* attribute.

From Cypress official docs:
Anti-Pattern: Using highly brittle selectors that are subject to change.
Best Practice: Use data-* attributes to provide context to your selectors and isolate them from CSS or JS changes.
Every test you write will include selectors for elements. To save yourself a lot of headaches, you should write selectors that are resilient to changes.
Oftentimes we see users run into problems targeting their elements because:
Your application may use dynamic classes or ID's that change
Your selectors break from development changes to CSS styles or JS behavior
Luckily, it is possible to avoid both of these problems.
Don't target elements based on CSS attributes such as: id, class, tag
Don't target elements that may change their textContent
Add data-* attributes to make it easier to target elements
The point is that id's and classes can be dynamic (also text-content) so you always want to use a selector that is static like the "data-cy" attribute.

Related

Custom class or attribute in E2E testing

Having pretty complex angular application with many pages (states) and conditional sections that creates a lot of test scenarios I need to perform e2e tests. I'm tired of nested selectors like 'div.SomeComponent > ul:nth-child(2) > ... ' and so on even using BEM namings (especially when app is evolving and it's easy to spoil tests by little change of html structure).
The question is, would you guys opt for creating some dummy (empty) classes or data-* attrs just to simplify protractor (or groovy) selector at the expense of loosing semantics? What's the alternative?
To avoid changing your element definitions every time developers change the css and to avoid using long css strings to select your elements, you can try referring to them by other means (id, className, model, etc.). See https://github.com/angular/protractor/blob/master/docs/locators.md for examples.
My personal favorite is to use element(by.css('[ng-click="executeSomeAction()"]')) as this will most likely not change with any application updates. It also works for other directives as well.
As for testing applications with a high volume of pages and elements, it's nice to define your elements in a class(es) and then call them in the test spec as needed. This reduces the code in your specs and makes them easier to read. You may also want to create a separate file for actions/functions your tests perform.
Hope this helps answer to your questions.

Should I use ids to locate elements?

Started with Angular and Protractor.
It just feels wrong to write some heavy css selectors which will break instant when you change something.
Using ID's would make testing way easier.
I'm not using any id attribute for styling yet. Are there any drawbacks using ids for testing I haven't considered?
The general rule is to use IDs whenever possible assuming they are unique across the DOM and not dynamically generated. Quoting Jim Holmes:
Whenever possible, use ID attributes. If the page is valid HTML, then
IDs are unique on the page. They're extraordinarily fast for
resolution in every browser, and the UI can change dramatically but
your script will still locate the element.
Sometimes IDs aren't the right choice. Dynamically generated IDs are
almost always the wrong choice when you're working with something like
a grid control. You rely on an id that is likely tied to the specific
row position and then you're screwed if your row changes.
Also, in general try to use the "data-oriented" approach: by.model, by.binding, by.repeater locators, or if you rely on class names, choose them wisely: do not use layout-oriented classes like .col-xs-4 or .container-fluid.
See also these related topics:
Best Practices for Watir and Selenium Locators
best way to detect an element on a web page for seleniumRC in java

Unique identifiers for ui automation

Our ui automation team is asking for a better way to select elements for their automated tests. My thinking is that we can inject a dedicated attribute (say "ui-auto") for each testable element. This attribute would have a value which is:
unique
persistent (doesn't change across sessions or page loads so as to not break the tests)
predictable (follows some naming convention depending on action type, location, etc.)
My questions are:
Is this a good idea? better ideas are welcome.
Are there existing conventions for this?
What the best way to implement
this?
I should mention that we are using angular and I thought that
using some kind of directive and/or service would help automate
this.
I should also say that I don't want to use the "id" attribute b/c I'd like to have separation between development concerns (ids may be used for javascript), and qa concerns (selection of elements for automated tests)
In our implementation we add to the DOM element a data-awt attribute, the value consists of a context (page and mode) type and unique string. As we use the EXTJS library our type is the xtype and the unique string is components name or text property. The context is developer controlled by placing a unique property on the upper most parent and all children use this as their context.
In practice we end up with data-awt values like devicesListing-button-edit, deviceDetails-displayfield-name, deviceDetailsEditWindow-textfield-name.
We found that relying on css, id, or other attributes aren't reliable and predictable since we don't want to rewrite our tests whenever there is some UI change. Now the test only needs updating if an existing element changes its name (for example the PM says the name field should now use the 'customer' data from the DTO).
You can also use the class of the element and provide a unique identifier prefixed with something like "auto_" or "t_".
The agreement exists that if anyone changes the class name with that prefix, tests will break.
#o4ohel I agree that not using ids is better as devs also depend on them and they need to change sometimes. Identifiers for automation should be isolated. It's nice to have that separation.

Does the className attribute take on the role of the id attribute in Reactjs?

Since id attributes are rarely used in Reactjs components due to the fact that id attributes imply that the component will not be reused, then are className attributes used instead of id's? If this is the case, then what is the Reactjs equivalent of the class attribute in HTML?
className is used for class names for CSS styling, just as elsewhere.
You can give something a unique className for styling purposes the same way you might give otherwise give it an id, sure, but that doesn't really imply anything else for other className usage, which can never really be a direct equivalent to id because className can contain multiple class names, none of which have to be unique. (There are also pretty good reasons not to use id for styling, regardless of React).
A more usual reason not to give something an id with React is that you rarely need to add hooks to go and look up an element from the real DOM, as you can use state or props to control rendering changes which do whatever dynamic stuff you need to do, and if you do need to go grab an element, you can give it a ref name and use getDOMNode() on it.
To add to insin's answer, ids do have practical uses, but styling is not one of them.
The two cases are fragment identifiers, and input/label pairing. In that case, you usually want to generate ids that are guaranteed to be globally unique (but consistent across renders). For that, use a mixin like unique-id-mixin.
First of all, ids are used with React, and they don't necessarily prevent re-use. For instance, if you'd want to use a element then you'd have to give it an ID (so it can be referenced from the "list" attribute of its tag). In that case, I usually auto-generate an ID using a counter variable. Hence, IDs and re-use don't have to rule each other out.
To answer your question, the className attribute is used instead and works just like the class attribute. The "react/addons" module provides a utility for easily creating className values.
ID's are for single use (in React and in general) or one-time instances.
classNames are for multiple usage (in React and in general) or for many-time instances - the same way that classes are used in traditional CSS.

Angular directives - element or attribute?

I'm part of a team with about 6 UI devs, of varying quality and next to no Angular experience. Many are contractors, with little experience with the code base. The app has a very fancy (complicated) UI. It supports IE8+ (soon hopefully IE9+).
We're introducing Angular for a major extension to the app, and I've been asked to write guidelines on the use of Angular for the team.
We'll use directives to create fancy UI elements, all prefixed with "ipwr" to avoid name clashes. I'm trying to decide whether to mandate that devs give their directives the restriction "element" or "attribute". Mandating only one, to avoid chaos and confusion.
My question is: what restrict is better or more popular for directives, "element" or "attribute"?
My main concern is ease of use for people with little Angular experience who are new to the application code base, to reduce bugs, copy and paste behaviour, etc.
The angular guidance says that you should use the "element" restriction whenever the directive has full control over it's template meaning it has a template that it is rendering out, etc.
For attributes, they suggest to use these only when you are adding "behavior" to an existing element or decorating an existing element.
For example, think of the ng-click directive, this is used a attribute not as a element because the click directive is just adding the click behavior to some element.
Another example would be the ng-repeat directive, it is also used as an attribute not as a element because it is going to repeat the element in which it is being used in.
Now, this guidance is from the angular documentation; however, I don't know necessarily that element vs. attribute is going to give you a "better" approach it's more of a convention.
Now if you have to support older browsers, then you may want to consider using either the comment or class directives.
My personal preference is to just use the attribute restriction; mainly because people that are new to angular get overwhelmed at first when they see the restrict and it's variations of the options that can be used.
I usually defer to the John Papa AngularJS style guide when making these types of decisions. He says:
Lean towards implementing as an element when its standalone and as an
attribute when it enhances its existing DOM element.
If you want to keep your HTML valid you'd use attributes, e.g. if you have a directive ipwr-modal, you can declare it as <div data-ipwr-modal="you-could-put-some-binding-here"></div>.
When creating directives with a custom layout, however, you'd better use element declaration (if you don't need to have your HTML valid). This is the more obvious way to say: "hey, we have a custom component here".
This blog post explains it with some more ideas
Some points to consider:
Most of the time attributes is the best/most convenient option (it's not the default by chance).
Anything you can do with element-bound directives, you can do with attribute-bound as well.
Element-bound directives can be more descriptive/readable at times.
If you want your code to pass certain types of validation, you should use attributes.
Since you want to support IE8, keep in mind that custom tags have an extra overhead (more info), which hurts maintainability.
BTW, you can't limit directives to elements only (without affecting functionality), so it is more a question of allowing 'element' or not. Note that an element often has more than one directives and directives placed on the same element can cooperate and augment each other's behaviour. So limiting the use of directives to 'element', means limiting the number of custom directives per element to 1, which severly reduces the functionality-potential.
That said, this is what I ('d) do:
If IE8 is not an issue, allow both (mostly use attributes).
If IE8 (or the overhead for custom tags) is an issue, use only attributes.
In general, if only one form should be allowed, it should be attributes (works anywhere, no extra overhead, offers all functionality).

Resources