Q27 of 37 · Selenium

Walk through your strategy for stable selectors that survive UI refactors.

SeleniumSeniorseleniumselectorsstabilityprocesssenior

Short answer

Short answer: Push for `data-test` (or similar) attributes on every interactive element. Treat them as test API — versioned, code-reviewed, never removed silently. Lint for forbidden patterns (positional xpath, generated class names). Track 'what broke and why' to keep the policy tight.

Detail

Stable selectors are a cultural problem more than a technical one. The technical patterns are simple; the discipline to maintain them is the real lift.

1. The selector hierarchy (in priority order):

  • [data-test=...] — test-only attribute, free of design concerns.
  • [role=...][aria-label=...] — semantic, often stable across visual refactors.
  • Stable name / form attributes.
  • Visible text via XPath (//button[normalize-space()='Sign in']).
  • Generated ids — only with starts-with anchors and as a last resort.

2. Treat data-test as a test API. The argument I make to dev teams: "If you'd remove a public method without a deprecation, you'd break callers. data-test attributes are the public API of your UI for QA. Treat them with the same care."

Concretely:

  • Code review checks: PRs that touch components without a data-test on new buttons get flagged.
  • Renames are a coordinated change with QA, not a side-effect of styling refactors.
  • ESLint rule (or equivalent for your stack) requiring data-test on <button> and <a>.

3. Lint your test suite for fragile patterns:

  • Positional xpath ((//tr)[3]).
  • Hashed CSS-in-JS classes (.css-1q2w3e4).
  • Brittle text matching that includes punctuation likely to change ("Sign in to your account.").

A pre-commit hook or CI grep that fails on these patterns is cheap and catches drift early.

4. Track failures by cause. Keep a small spreadsheet (or annotation in your bug tracker) of every test fix. Tag whether the cause was: a UI bug, a stale locator, a timing issue, or test logic. After a quarter, the mode is usually obvious — and the data lets you push back when leadership asks "why are tests still flaky?"

5. Pair-program the first round of pages with frontend engineers, especially on a new project. They learn what makes selectors fragile; you learn the underlying component structure. The selector strategy that emerges is mutual.

The interview signal: framing this as a cross-team policy with measurable inputs (lint, code review) and outputs (failure-cause tracking) — not as a "use data-test, the end."

// WHAT INTERVIEWERS LOOK FOR

Cross-team framing, treating data-test as an API, concrete enforcement (lint, code review), and the discipline to track *why* tests break, not just *that* they break.

// COMMON PITFALL

Treating selector stability as a QA-only problem. Without dev buy-in, you're forever patching around their refactors. The real win is making selector breakage a shared concern.