Element Identification
Your UI Coverage score is only as trustworthy as the way elements are counted. UI Coverage gives every interactive element a single, stable identity, so that one control, such as a "Place order" button that appears in hundreds of snapshots across a run, counts as one element, marked tested the moment any test interacts with it.
That stability is what makes the score meaningful:
- When identity is stable, the same button is recognized in every snapshot and view, and your score reflects real coverage.
- When identity drifts, for example from an
idthat regenerates on every render, that one button fractures into many duplicate "untested" elements that add noise and drag the score down for no real reason.
In reports, each element appears under a selector like [data-cy="place-order"], or a readable name when you configure one. This page explains how UI Coverage builds that identity, what keeps it stable automatically, and how to correct it when your application's markup works against the defaults. You don't need any configuration to get started: the defaults described below apply out of the box.
Snapshotsβ
A snapshot is a capture of your application's DOM at one moment during a test. As your tests run, the same capture protocol that powers Test Replay records snapshots automatically as your application changes state, on page loads, interactions, and other DOM updates, with no extra code or configuration.
UI Coverage analyzes the snapshots in a recorded run: it detects the interactive elements in each one and computes an identity for each element using the rules on this page. Elements that produce the same identity in different snapshots count as one element, and views group snapshots by URL. An identity that changes between snapshots, such as one built from an autogenerated id, is what splits a single button into many untested elements.
How an element is identifiedβ
For each interactive element it tracks, UI Coverage looks for an identifying attribute. It checks a single prioritized list and uses the first attribute that is present with a usable value:
- Your
significantAttributes, in the order you list them - The default test attributes, in order:
data-cy,data-test,data-testid,data-test-id,data-qa, androw-id(data grids) id, thenname, as fallbacks
The first attribute in this list that the element has, with a value that isn't excluded by an attributeFilters rule, becomes the element's identifying attribute. That single attribute-value pair drives how the element is identified across snapshots, named in reports, and grouped with repeated elements that share the same value.
For example, both attributes below can identify this button, but data-cy outranks id, so it wins:
<button data-cy="place-order" id="btn-8f3a">Place order</button>
The button is identified as [data-cy="place-order"], and the generated id is never used. Using one of these attributes consistently across your application is the most effective way to keep identification accurate.
In reports, elements appear under their identifying selector, and the Snapshots column shows how many snapshots each one spans while still counting as a single element. An element without a usable attribute falls back to a structural selector.
![A UI Coverage report listing elements under their identifying selectors, such as [data-cy="convertConfigButton"], with a Snapshots column showing how many snapshots each element appears in](/img/ui-coverage/guides/cypress-ui-coverage-tested-elements-with-high-interactions.png)
When an element has no identifying attributeβ
Not every interactive element carries a useful attribute. When none of the attributes above apply, UI Coverage falls back to identifying the element by its structure and position in the DOM, such as its tag and where it sits among sibling elements. Its visible text content is never used, so a button labeled "Save" that briefly becomes "Savingβ¦" during a request stays one element.
A structural identity like this is less stable than an attribute you control: a change to the surrounding markup can shift it, so the same element can appear as new and untested when you compare two runs in Branch Review. Adding a stable test attribute is the reliable fix.
Links are a special case. An <a> element is identified by its destination href. Links whose URLs follow the same pattern are resolved into views and grouped by that pattern, so a list of 50 product links doesn't become 50 separate untested elements.
Unstable attributes are filtered automaticallyβ
UI Coverage already ignores the most common sources of unstable identity, such as auto-generated IDs and framework-generated class names, so in most applications you don't need to configure anything.
If your application produces an unstable value that these built-in rules don't cover, add an attributeFilters rule to ignore it. If a single specific element needs a fixed identity, use an elements rule.
Elements in iframes and shadow DOMβ
UI Coverage identifies interactive elements inside iframes and shadow DOM as well, qualifying each element's identity with its host chain. A #submit button inside a checkout iframe is therefore a different element from a #submit in the main document, and both are tracked. To target an element inside a specific iframe or shadow root with a configuration rule, use the documentScope property on elements, elementFilters, or elementGroups rules.
Tuning element identificationβ
When the defaults don't match your application, three configuration options adjust how elements are identified. Set them in the App Quality tab of your project settings in Cypress Cloud, then regenerate a recent run to preview the effect without re-running your tests.
| Your goal | Use |
|---|---|
Prefer your own attribute (like data-component) as identity | significantAttributes |
| Stop a dynamic or generated attribute from identifying elements | attributeFilters |
| Give one specific element a stable identity or a readable name | elements |
See Which option do I need? in the configuration overview for how these fit alongside grouping and filtering.
Prioritize your own attributesβ
If your components already render a descriptive attribute, add it to significantAttributes so UI Coverage prefers it over the defaults. Elements are then identified and named by the vocabulary your team recognizes, showing [data-component="CheckoutButton"] instead of a generated selector.
{
"uiCoverage": {
"significantAttributes": ["data-component"]
}
}
Refer to the significantAttributes guide for the full priority rules and examples.
Ignore an unstable attributeβ
Exclude a dynamically generated attribute value so it can't split one element into many. For example, to stop a React-generated id like :r17: from being used as identity:
{
"uiCoverage": {
"attributeFilters": [
{
"attribute": "id",
"value": ":r.*:",
"include": false
}
]
}
}
Once the unstable value is ignored, UI Coverage identifies the element by the next stable attribute it has. Learn more in the attributeFilters guide.
Fix a single element's identityβ
When one element's attributes change between snapshots, an elements rule pins it to a selector you choose and gives it a readable name. The matched element is identified by the rule's selector alone, so it stays one element across snapshots even as its id regenerates.
{
"uiCoverage": {
"elements": [
{
"selector": "#checkout-form [id^='country-']",
"name": "Country Dropdown"
}
]
}
}
An elements rule applies only when its selector matches exactly one interactive element in a snapshot. Refer to the elements guide for how rules are matched and scoped.
See alsoβ
- Element Grouping: how related elements are combined so interacting with one counts for the set.
- Interactivity: which elements UI Coverage tracks and which commands mark them tested.
significantAttributes: prioritize your own attributes for identifying and naming elements.attributeFilters: stop dynamic or generated attribute values from identifying elements.elements: give a single element a stable identity and a readable name.- UI Coverage FAQ: common questions about element identification.