Stable classnames or ids
We have lots of selenium based tests that use classnames for selectors, and it seems like the classnames are not very stable and these tests have broken when we update HIG packages. I would like to be able to rely on stable classnames or ids to select parts of components to test against.
Some of the pain points are the flyout classnames with -v1 attached to them while removing the non -v1 classnames and the removal of the __top-nav__ section of hig__profile-flyout__content__email and hig__profile-flyout__content__name.
Context
We don't consider the class names, IDs, and tag names to be public APIs. While consumers may reference them for their needs, there's no guarantee of stability.
Each of those serve a different purpose in the library:
- Class names are used for styling.
- The
-v1suffix was added to serve as temporary versioning while we make components themeable. - Themeable components will use a CSS-in-JS solution and have dynamically generated class names, which are not suitable for automated browser testing.
- The
- IDs are used for accessibility (ARIA attributes) and application level concerns.
- IDs are dynamically generated by default
- Some components have props to allow consumers to override the generated IDs
- Static IDs aren't an option.
- Tag names are used for semantics and accessibility.
- As the components evolve, we'll make changes to the markup structure.
Proposed solution
In past experiences, I've found it best to use dedicated data attributes for the concerns of automation. This helps to maintain separation of concerns and avoid usage confusion. An example may be data-hig="top-nav" and the selector would be just as simple [data-hig="top-nav"]. These wouldn't be added to every element, but only to those that apply to automation use cases.
While we've discussed this solution in the past, the work was never prioritized.
The data attribute makes sense to me, and it could also provide a hook for custom styling, so that works. I am wondering is there a downside to providing or leaving a class name?
I like leaving custom ids because it's under our control, and if we decide to render two or three of something on a page it's easier to distinguish without relying on order. It also allows us to id a component to something that more closely matches it's purpose.
Custom classnames would be really nice to override styles as well, but theme data should mitigate that need.
@wmui51
and it could also provide a hook for custom styling
That's what I'm trying to avoid actually. We shouldn't have to be concerned about breaking custom styling if we need to move a data-attribute that's for automated testing. Likewise, we shouldn't have to be concerned with breaking automated testing when we want to change a hook that's used for custom styling.
I am wondering is there a downside to providing or leaving a class name?
The issue comes from reusing the same class names across multiple different versions of a component. Right now we're using static class names across multiple versions of our components, and the styles can conflict with each other.
For example, it's quite easy to have three different versions of @hig/flyout on the same page if you also use @hig/top-nav and @hig/tooltip. This doesn't include the Flyouts from hig-react and hig-vanilla.
If we were to still use class names to better support automated testing, they would need to be different than ones that were used for styling. If they should be different, using a completely different attribute would provide more clarity.
@kennyw12
I like leaving custom ids because it's under our control, and if we decide to render two or three of something on a page it's easier to distinguish without relying on order.
This is probably the easiest way forward at the moment. This can be added to the simpler components fairly easily. With that said, the more complex components would need a more robust solution for interacting with multiple areas.