Skip to main content

How to define Element Selectors

Introduction​

With the goal to keep parity, between components and practices, we aim to assign unique test ID's to the elements in order to interact in our tests. Test ID's are the least likely to change over time and are locale-agnostic.

We are basing our own guidelines in those of WebdriverIO.


πŸ“ Selector Guidelines

βœ… When to Add data-testid​

Adding a data-testid will increase the bundle size, thus aim to add them only when necessary:

  • The element is a custom component not exposing native semantics
  • You need to target a key interactive element (e.g. button, input)
  • Visual text is dynamic, localized, or unstable
  • The test needs to disambiguate similar elements

❌ Do NOT add data-testid for:​

  • Static or purely visual content (e.g., headings, icons, paragraphs)
  • Decorative elements or wrappers (e.g., divs used for layout)
  • Every DOM node β€” this clutters markup, greatly increase the bundle size and hurts maintainability

🧩 Naming Convention​

Use this format:

<component>--<element>--<index>

This ensures predictable, structured selectors.

Examples​

ContextSelector
Componentaction-button
Element in Componentaction-button--loading-bar

πŸ’‘ For dynamic lists, include the index, p.e., radio-list--item--0


πŸ§ͺ WebdriverIO Best Practices​

βœ… Select by data-testid:​

await $('[data-testid="${ACTION_BUTTON}"]').click();

🚫 Avoid:​

  • XPath selectors (//button[contains(text(),"Submit")])
  • CSS selectors based on structure (div > button:nth-child(3))
  • Class names (.btn-primary) β€” subject to change with styling

πŸ’‘ Implementation Example​

const ACTION_BUTTON = "action-button";
const LOADING_BAR = `${ACTION_BUTTON}--loading-bar`;

module.exports = {
ACTION_BUTTON,
LOADING_BAR,
};

export const ActionButton: FunctionComponent<ActionButtonProps> = ({

(...)

return (
<button type="button" (...) data-testid={ACTION_BUTTON}>
{children}
<div className={loadingBarClassNames} (...) data-testid={LOADING_BAR}/>
</button>
);
};

πŸ“ Rules Summary​

RuleDescription
βœ… Use for key interactive elementsButtons, inputs, toggles
βœ… Use when role/text is unreliableCustom UI or dynamic content
βœ… Use consistent naming<component>--<element>, if needed add an index <component>--<element>--<index>
❌ Don’t overuseAvoid static, presentational elements
❌ Don’t duplicate semantic rolesPrefer built-in queries if available