how to handle dynamic IDs in test selectors
Handles dynamic IDs in selectors: stable attributes and partial matching. Use when IDs change per render. Not for static IDs.
TL;DR
Never select by dynamic IDs. Use stable attributes (data-testid), partial-match selectors ([id^='prefix-']), or role locators, and push back on the app to add test hooks.
Error
(Not an error; a selector strategy. Symptom: selectors with IDs like `id="ember123"` break every run.)Steps
- Confirm the ID is dynamic: reload and compare. Expected: it changes.
- Replace with a stable attribute: ask for
data-testidor use an existing stable attribute. Expected: the durable fix. - If stuck, use prefix matching:
[id^='user-form-']. Expected: works but fragile; document it. - Prefer role or text locators that ignore the ID entirely. Expected: the robust alternative.
- Lint against bare dynamic-ID selectors. Expected: no new ones.
When to use
- Framework-generated IDs (Ember, auto-increment).
- Any ID that changes between runs.
When not to use
- Stable IDs (use them directly).
- You control the app (add test IDs instead).
Tool compatibility
- Any framework; attribute selectors everywhere.
Variant phrasings
Dynamic ID selector workaround
The tactical fix; stable attributes are the strategy.
Ember generated ID testing
The classic case; test IDs are the answer.
Why it happens
Frameworks generate IDs for internal bookkeeping. They are explicitly unstable across renders.
Edge cases
- Prefix matching breaks when the prefix scheme changes; treat as tech debt.
- Some dynamic IDs embed the record ID, which is actually useful; extract it deliberately.
- ARIA attributes are stable alternatives when test IDs are unavailable.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_kxg6DSbNgAZTAacqSRPSmg
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.