How far should a Cypress project's `selectorPriority` list constrain generated selectors?
answer
- It only governs code Cypress writes
- Both ends of the dial hurt
- Uniqueness is a constraint you cannot remove
- The API is documented as still moving
- Match the list to markup you ship
basics
~20 sFar enough that generated code reaches for your test attribute first, not so far that Cypress has nothing left to fall back on. A one-entry list forces Cypress to improvise; leaving class and nth-child in lets fragile selectors into the repo.
solid answer
~40 s`selectorPriority` is a lever over machine-written code only — Cypress Studio, the Selector Playground and `cy.prompt()` — so the decision is about what you are willing to have generated into the repository, not about how tests are written by hand. Put the project's test attribute first, so a recorded step names `[data-cy="room-card"]` rather than a class. Then choose the tail deliberately: dropping `class` and `nth-child` stops layout-coupled selectors appearing, but Cypress still has to produce something unique, so with fewer preferences left it improvises and the output gets longer rather than better. Two costs deserve an explicit decision — Cypress documents the API as still under active development, so a pinned list is upgrade surface; and a list naming attributes your components do not actually ship degrades every generated selector in silence.
go deeper
You will not set this. Recognise it as a project-level line in the Cypress support file, and ask what it is for rather than editing it because one generated selector looked wrong.
Be able to explain the mechanics the decision rests on: the list is a preference order, Cypress must still produce a unique selector, and the array replaces the default rather than extending it.
Show that you would read the shipped markup before writing the list. A priority naming attributes the components do not carry produces worse selectors than the default order it replaced, and nothing warns you.
Own the tradeoff and the exit. Decide who maintains the list, whether generated selectors are reviewed like any other code, and what the team does when Cypress changes an API it documents as still moving.
## What you are actually deciding `selectorPriority` is a lever over **machine-written code only**. Cypress Studio, the Selector Playground and `cy.prompt()` consult it when they derive a selector for an element you pointed at; `cy.get()` never does. So the question is not "what selector convention should this suite use" — that is settled in the components and in review — but "what am I willing to have Cypress write into the repository when somebody records a step against the room list". That reframing matters because it tells you who the decision is for. A team where nobody opens Studio or the playground gets nothing from tuning the list. A team where recorded steps are a normal way to start a spec gets a real lever, and the list becomes part of the code standard rather than a Cypress detail. ## The two ends of the dial | Setting | What you get | What it costs | | --- | --- | --- | | Leave the default alone | `data-cy`, `data-test`, `data-testid`, `data-qa`, then `name`, `id`, `class`, `tag`, `attributes`, `nth-child` | An element with no test attribute yields a class- or position-based selector into the repo | | Test attribute plus a deliberate tail | Generated selectors reach for your convention first, then a stable fallback you chose | One more thing to maintain, and it drifts as the markup changes | | One entry, such as `['data-cy']` | Nothing but your convention is ever preferred | The array **replaces** the default, so every fallback is gone; Cypress must still produce something unique and now improvises | The one-entry list is the trap worth naming out loud. It reads like strictness and behaves like the opposite: Cypress's contract is a selector unique in the document, not a selector drawn from your list, so removing the fallbacks does not stop a fragile selector appearing — it removes your say in which fragile selector appears. ## Read the markup before you write the list The list is a claim about what your components actually ship. Checking it costs very little and changes the answer: - If every interactive element in the booking flow carries `data-cy`, the tail is almost never reached and a short list is honest. - If test attributes are on the room card but not on the date picker's internals, the tail is doing real work and deserves thought — `attribute:aria-label` and `name` are usually better second choices than `class`. - If the components ship hashed CSS class names from a build step, leaving `class` in the list means generated selectors go stale on the next restyle. That is the strongest argument for editing the list at all. - If nothing on your proposed list appears on the elements people actually record against, the configured list produces worse output than the default order it replaced. ## The costs a lead signs up for - **Upgrade surface.** Cypress documents `selectorPriority` as under active development and warns it may change as the product refines selector generation. A team standard pinned to it has to be revisited at majors. - **A second place to look.** A reviewer who sees `[aria-label="Check-in"]` in a recorded spec now has to know that a support-file line explains it. - **A false sense of enforcement.** The list is a preference for a generator, not a lint rule. It stops nothing a person types into `cy.get()`. - **Silence when it is wrong.** `defaults()` validates entry *forms*, not whether those attributes exist in your application. A list naming attributes nobody ships throws nothing and quietly degrades every generated selector. ## A defensible default For a booking suite that has standardised on `data-cy`: 1. Put `data-cy` first, so recorded steps name the convention. 2. Follow it with one or two semantic fallbacks the application genuinely carries — `attribute:aria-label`, then `name`. 3. Keep `id` if your ids are hand-written and stable; drop it if a framework generates them. 4. Drop `class` if class names come out of a CSS-modules-style build, and keep `attributes` at the end so Cypress has somewhere reasonable to land. 5. Review generated selectors in pull requests like any other code, because that — not the list — is what actually keeps them good. ## When to leave it alone The default order already puts all four test-attribute conventions ahead of everything else, which is most of the value on offer. If your components carry a test attribute on the elements people record against, if nobody on the team uses Studio or the playground, or if you are not prepared to revisit the setting at Cypress majors, the honest answer is to ship the default and spend the attention on the markup instead. Choosing not to configure something, and being able to say why, is a complete answer to this question.
- What does a Cypress `selectorPriority` of `['data-cy']` do on markup that has no `data-cy`?Cypress guarantees uniqueness, not adherence to your list, so it produces whatever it can from what is left rather than refusing. The documentation is explicit that Cypress may skip lower-priority options or combine several selectors when one attribute is not unique enough; stripping the array to a single entry removes the alternatives that made that fallback readable. A tail entry such as `attributes` or `id` gives Cypress a better second choice than improvisation.
- Should a Cypress team keep `class` in its `selectorPriority` list?Only deliberately. Leaving `class` in means a recorded step can commit a styling class, which is exactly the selector that breaks on a restyle — a real risk when class names come out of a build step. Taking it out does not improve the generated selector by itself; it only moves Cypress further down the list. The useful question is whether the components carry a stable test attribute on the elements people record against, because then `class` is rarely reached at all.
saying these in an interview costs you the question
- Sets a one-entry list and expects cleaner selectors everywhere
- Treats selectorPriority as enforcement of a selector convention
- Assumes the list applies to hand-written cy.get() calls too
- Ignores that Cypress must still produce a unique selector
- Pins the list without owning the upgrade risk Cypress documents