Cypress · Junior

Cypress Selector Interview Questions and Answers

Stable selectors, cy.contains, .first()/.eq(), and why position-based selectors break.

10 questions, each with the answer and the reason every other option is wrong. You can read them here, then sit the timed session to find out what you actually remember.

1. Which selector does the Cypress team recommend for finding elements?

Answer

A dedicated test attribute, e.g. cy.get('[data-testid="submit"]')

Correct. A data-* attribute added for testing does not change when styling or layout changes, so it is the most stable choice.

Cypress best practice: target a dedicated data-testid (or similar) so tests do not break when styling or structure changes.

Why the other answers are wrong

  • A long CSS path like .container > div:nth-child(2) > button. Position- and structure-based paths break with any layout change.
  • The element's utility class, e.g. .bg-blue-500. Styling classes change often and say nothing about what the element is.
  • An index copied from the DevTools 'Copy selector' menu. Copied selectors are usually long and position-based, which makes them fragile.

2. What does cy.contains('Add to cart') match?

Answer

The first element whose visible text contains 'Add to cart'

Correct. cy.contains finds by visible text and yields the first match. It is useful for buttons and links a user reads.

cy.contains(text) matches the first element with that visible text. To scope it, pass a selector first: cy.contains('button', 'Add to cart').

Why the other answers are wrong

  • Every element on the page containing that text. cy.contains yields the first match, not all of them.
  • Only elements with an exact text of 'Add to cart' and nothing else. cy.contains matches partial text by default, not only exact text.
  • Elements with a title attribute of 'Add to cart'. cy.contains matches visible text content, not the title attribute.

3. What is wrong with cy.get('.product-card').eq(0).find('button').click() as the way to add the first product to the cart?

Answer

It depends on position, if the grid reorders, .eq(0) clicks a different product

Correct. Position-based selection breaks when the order changes. Target the product by a stable handle instead.

Selecting by position (.eq, :nth-child) breaks on reorder. Prefer a stable per-item test id, e.g. cy.get('[data-testid="add-to-cart"]').first().

Why the other answers are wrong

  • eq(0) is not a real Cypress command. .eq(index) is a real command. The problem is that it selects by position, which is fragile.
  • You cannot chain .find() after .eq(). You can chain .find() after .eq(). The issue is the position dependency, not the chaining.
  • click() does not work inside a grid. click() works anywhere. The concern is which element .eq(0) lands on if the grid reorders.

4. When is .first() an acceptable choice rather than a fragile one?

Answer

When any matching element is equally valid, e.g. 'add the first product, any product'

Correct. If the test does not care which item, .first() is fine. It is fragile only when you rely on a specific item being first.

The test's intent decides. 'Any product' → .first() is honest. 'The Trail Runner product' → target that product directly.

Why the other answers are wrong

  • Never, .first() is always fragile. It is fine when any match works. It is only fragile when the identity of the first element matters.
  • Only when there is exactly one match. With one match .first() is harmless but unnecessary. Its real use is 'any of these will do'.
  • Only inside cy.contains. .first() works after any command that yields multiple elements, not only cy.contains.

5. What does cy.get('[data-testid="contact-row"]') yield when the table has 8 matching rows?

Answer

All 8 matching elements. You can then assert their count or act on one

Correct. cy.get yields every match. cy.get(...).should('have.length', 8) checks the count.

cy.get yields all matches. Note the contrast with Playwright: Cypress does not throw on multiple matches; you narrow with .first()/.eq() or assert on length.

Why the other answers are wrong

  • Only the first row. cy.get yields all matches. To get one, chain .first() or .eq(i).
  • A count of 8 as a number. It yields the elements, not a number. You assert on their length to check the count.
  • An error, because the selector matches more than one element. Matching many elements is fine in Cypress. Unlike Playwright's strict mode, cy.get does not error on multiple matches.

6. How do you get the table row that contains 'Maya Chen'?

Answer

cy.contains('[data-testid="contact-row"]', 'Maya Chen')

Correct. Passing a selector and text to cy.contains yields the matching row by who it is, not where it sits.

cy.contains(selector, text) finds an element by identity. Prefer it over position when you mean 'the Maya row'.

Why the other answers are wrong

  • cy.get('[data-testid="contact-row"]').eq(2). That selects by position. If the table sorts differently, row 2 is someone else.
  • cy.get('Maya Chen'). cy.get takes a selector, not free text. Use cy.contains for text.
  • cy.find('Maya Chen'). cy.find is not a root command, and it takes a selector, not text. Use cy.contains.

7. What is the difference between .find() and cy.get() inside a chain?

Answer

.find() searches within the current subject; cy.get() searches the whole document

Correct. .find() is scoped to the yielded element. cy.get() starts a fresh search from the document root.

Scope: cy.get('[data-testid="cart"]').find('button') looks for a button inside the cart element only.

Why the other answers are wrong

  • They are identical. They differ in scope: .find() searches inside the current subject, cy.get() searches everywhere.
  • .find() only works with XPath. .find() takes a CSS selector and searches within the current subject.
  • cy.get() can only be used once per test. cy.get() can be used as often as needed. The difference from .find() is search scope.

8. A test uses cy.get('button') on a page with 12 buttons and calls .click(). What happens?

Answer

Cypress clicks, but the yielded set has 12 elements, so .click() fails asking you to narrow to one

Correct. click() needs a single element. With 12 matches, Cypress asks you to select one first.

Actions need one element. Narrow with a test id, cy.contains, or .first()/.eq() before .click().

Why the other answers are wrong

  • It clicks all 12 buttons in order. click() acts on a single element and does not fan out to many.
  • It clicks a random button. Cypress does not guess. It requires one element for an action.
  • It silently clicks the first button. Cypress does not silently pick the first for an action; it asks you to narrow the selection.

9. Why is cy.get('[data-testid="add-to-cart"]') better than cy.get('.MuiButton-root-2891')?

Answer

The test id is added on purpose and stays stable; the generated class can change on any build

Correct. Framework-generated class names can change between builds. A test id is meant for testing and stays put.

Generated class names (from CSS-in-JS or utility frameworks) change without notice. A dedicated test id is stable by design.

Why the other answers are wrong

  • Test ids are faster to query. Query speed is not the point. The test id is stable across builds; the generated class is not.
  • Class selectors do not work in Cypress. Class selectors work. The problem is that this particular class is generated and unstable.
  • Only attribute selectors can be clicked. Any selector can lead to a click. The point is stability, not the selector type.

10. cy.get('[data-testid="contact-line"]') times out, but the rows are visible on the page. What is most likely wrong?

Answer

The selector is wrong. The rows use a different test id (e.g. contact-row)

Correct. If the element exists but the command times out, the selector does not match it. Check the real test id.

A timeout on an element you can see almost always means the selector does not match. Confirm the real attribute before adding waits.

Why the other answers are wrong

  • Cypress needs a longer default timeout. A longer timeout will not help if the selector matches nothing. Fix the selector.
  • The table has too many rows to query. Row count is not the issue. The selector simply does not match the rows.
  • cy.get cannot select table rows. cy.get selects any element, including rows. The test id in the selector is wrong.

Now prove it in code

Knowing the answer and writing the test are different skills. These problems run your test against a working app, then against a copy with the behaviour broken on purpose, and tell you which behaviour your test missed.

More Cypress interview questions

Other frameworks