skip to content

In Cypress, what does setting `selectorPriority` via `Cypress.ElementSelector` control?

level: middleimportance: should knowfreq 44%

answer

  1. It configures a generator, not a query
  2. Studio and the playground read it
  3. One ranked array of attribute kinds
  4. Replaces the default list, never merges
  5. Uniqueness can still override your order

basics

~20 s

It sets the order of attributes Cypress prefers when it writes a selector for you, in Cypress Studio, the Selector Playground and cy.prompt(). It never changes what cy.get() matches, and it replaces Cypress's default order rather than extending it.

solid answer

~40 s

`Cypress.ElementSelector.defaults({ selectorPriority: [...] })` configures the **generator**, not the query engine. Cypress Studio, the Selector Playground and `cy.prompt()` all have to derive a unique selector for an element you point at, and `selectorPriority` is the ranked list of attribute kinds they walk. As of Cypress 16 the default order is `data-cy`, `data-test`, `data-testid`, `data-qa`, `name`, `id`, `class`, `tag`, `attributes`, `nth-child`. Accepted entries are `data-*`, `attribute:*`, `id`, `class`, `tag`, `name`, `attributes` and `nth-child`; anything else throws. The array **replaces** the default list rather than merging with it, so a one-entry list drops every fallback. Uniqueness still wins: Cypress may skip a higher-priority kind, or combine several, when one attribute does not identify the element on its own. Call it once in the Cypress support file, so every spec in the suite sees the same order.

code

javascript · 10 lines
javascript
// cypress/support/e2e.js - loaded before every spec
Cypress.ElementSelector.defaults({
  selectorPriority: [
    'data-cy',
    'attribute:aria-label',
    'name',
    'id',
    'attributes',
  ],
})

go deeper

for a junior

Know this is configuration, not something you call inside a test. If asked how Cypress decides which attribute to put in a generated selector, name Cypress.ElementSelector.defaults and its selectorPriority option.

for a middle

Be ready to recite the default order and to explain that the array replaces the default list wholesale. Interviewers usually follow up by asking what happens to a selector kind you left out.

for a senior

Explain why a configured priority can still be overridden: Cypress must return a selector unique in the document, so it may skip your first choice or combine kinds when one attribute is not enough on its own.

for a principal

Decide whether the project pins this at all. Cypress documents selectorPriority as still under active development, so a team standard built on it carries upgrade risk somebody has to agree to carry.

## What the API configures, and what it does not `Cypress.ElementSelector.defaults({ selectorPriority: [...] })` configures the **selector generator**, not the query engine. Several parts of Cypress have to look at an element you pointed at and write down a selector that identifies it: Cypress Studio when it records a click on a room card, the Selector Playground in `cypress open` when you hover an element, and `cy.prompt()` when it turns a natural-language step into commands. `selectorPriority` is the ranked list of attribute kinds those tools walk. It has **no effect on `cy.get()`**. A selector you typed is passed through unchanged; nothing rewrites it, reorders it or prefers a different attribute on your behalf. This is the most common misreading of the API and it is worth saying out loud in an interview before anything else. ## The default order in Cypress 16 As of Cypress 16 the built-in priority list is, in order: 1. `data-cy` 2. `data-test` 3. `data-testid` 4. `data-qa` 5. `name` 6. `id` 7. `class` 8. `tag` 9. `attributes` 10. `nth-child` The four dedicated test-attribute conventions come first, then the semantic `name` attribute, then the identifiers an application also styles and scripts against, and finally the structural fallbacks. Point the Selector Playground at a `<button data-cy="book-room" id="book-btn" class="primary">` and you get `[data-cy="book-room"]`, not `#book-btn`. ## What the array accepts Every entry is validated, and an unrecognised one throws immediately: | Entry form | Meaning | Example | | --- | --- | --- | | `data-<name>` | one specific data attribute | `data-cy`, `data-qa` | | `attribute:<name>` | one specific non-data attribute | `attribute:aria-label`, `attribute:role` | | `attributes` | any remaining attribute, as a fallback | `attributes` | | `id` / `class` / `tag` / `name` | that kind of selector | `id` | | `nth-child` | positional fallback | `nth-child` | The trap is the `attribute:` prefix. `data-` is the only prefix that stands alone, so `data-cy` is valid but a bare `aria-label` is not — it has to be written `attribute:aria-label`. Passing anything else throws with a message listing the accepted forms, and passing a non-array throws a separate error. Both throws happen at the call site, so a bad support file fails every spec before its first test. ## Why your first choice can still lose Cypress guarantees the generated selector is **unique in the document**; it only *attempts* to follow your priority. Two things follow from that: - If the highest-priority attribute is present but not unique — every room card in the list carries `data-cy="room-card"` — Cypress may skip it or combine it with something else to disambiguate. - If nothing on your list is present on the element, Cypress works with whatever the rest of the list leaves it, which is why stripping the list down to a single entry usually makes generated selectors worse rather than cleaner. The documentation is also explicit that `selectorPriority` is under active development and may change, so a list a team pins today is upgrade surface tomorrow. ## Where the call belongs, and how it behaves - **Put it in the Cypress support file** (`cypress/support/e2e.js` by default). The support file is loaded before every spec, so one call covers the suite; a call inside a single spec lasts only for that spec's run. - **The array replaces, it does not merge.** `defaults({ selectorPriority: ['data-cy'] })` leaves exactly one entry, not eleven. Every fallback you want has to be listed explicitly. - **`defaults({})` is a no-op.** The function reads only the `selectorPriority` key, so an empty object leaves the current list in place, and there is no public reset. It also means an unrecognised key is ignored in silence rather than rejected. - **It is configuration, not a command.** It runs synchronously outside the Cypress command queue and is never chained onto `cy`. ## A worked example A hotel booking project that has standardised on `data-cy`, and wants ARIA labels as the next-best thing, would write: ```javascript // cypress/support/e2e.js Cypress.ElementSelector.defaults({ selectorPriority: [ 'data-cy', 'attribute:aria-label', 'name', 'id', 'attributes', ], }) ``` Recording a click on the check-in field in Cypress Studio then produces `[data-cy="check-in-date"]`, which the default order would also have produced. The difference shows up on a control that has no test attribute yet: it now falls to its `aria-label` rather than to a hashed CSS class, because `class` was deliberately left off the list.

  • In Cypress, what happens if a `selectorPriority` entry is written as `aria-label`?
    `Cypress.ElementSelector.defaults()` validates every entry and throws. The message says the value must be one of `data-*`, `attribute:*`, `id`, `class`, `tag`, `name`, `attributes` or `nth-child`, and a bare `aria-label` is none of those. The correct spelling for an arbitrary HTML attribute is `attribute:aria-label`; `data-` is the only prefix that stands alone. The throw happens at the call site, so a bad support file fails every spec immediately.
  • In Cypress, does `Cypress.ElementSelector.defaults({})` reset the priority list?
    No. `defaults()` reads only the `selectorPriority` key, so an empty object is a no-op and the current list stays in force; there is no public reset. The same behaviour means an unrecognised key is ignored rather than rejected, which is how a half-migrated support file can look correct and still not do what it appears to say.

Think of selectorPriority as a ranked-choice ballot rather than a rule. Cypress works down your preferences in order, but skips any candidate that cannot identify the element on its own.

saying these in an interview costs you the question

  • Thinks selectorPriority changes which elements cy.get() matches
  • Believes the array merges with Cypress's default list
  • Expects the top entry to win regardless of uniqueness
  • Writes a bare aria-label instead of attribute:aria-label