skip to content

Primary Query Commands

The commands that begin a chain and what they really hand you - a jQuery collection, not one node - covering CSS selectors, aliases, text matching and the page-level queries.

on this pageshow

explore

questions

5

In Cypress, what does `cy.get('.room-card')` yield when the page renders 12 room cards?

level: juniorimportance: must knowfreq 78%

answer

  1. Ask what the chain passes along next
  2. Count the matches, not just one
  3. Cypress bundles a familiar DOM library
  4. The subject exposes length and text()
  5. Same shape Cypress.$ would hand you

basics

~20 s

One jQuery-wrapped collection holding all 12 room-card elements, not a single DOM node and not an array. Its length is 12, and the whole set becomes the subject the next command in the chain receives.

solid answer

~40 s

`cy.get()` is a Cypress query that yields a **jQuery object** wrapping every element that matched, so a twelve-card room list gives you one collection of length 12, and that collection is the subject of the next command. It is not an `HTMLElement`, not a `NodeList`, and not a promise you can `await`. Inside `.then(($cards) => ...)` you hold the jQuery object itself: `$cards.length` is `12`, and jQuery's `.text()` concatenates all twelve cards rather than returning the first. Cypress also refuses most action commands on a multi-element subject, failing with *`cy.click()` can only be called on a single element. Your subject contained 12 elements.* The subject has jQuery's API because Cypress bundles jQuery and exposes the same function as `Cypress.$`.

code

javascript · 10 lines
javascript
// the room list renders 12 <li class="room-card"> elements
cy.get('.room-card').should('have.length', 12)

cy.get('.room-card').then(($cards) => {
  // $cards is one jQuery collection, not a single element
  expect($cards.length).to.equal(12)

  // jQuery's .text() runs every card together into one string
  expect($cards.text()).to.contain('Deluxe Double')
})

go deeper

for a junior

Be ready to say plainly what a Cypress query hands the next command: one jQuery-wrapped set of every match, with a length. Knowing it is not a raw DOM node is the whole point of the question.

for a middle

Explain why the subject is a jQuery object at all - Cypress bundles jQuery and exposes it as Cypress.$ - and what that means inside a callback, where jQuery's methods, not the DOM's, are what you hold.

for a senior

Show how a multi-element subject becomes a real failure: an action command that refuses a set of twelve, or a callback that silently reads text concatenated from every card. Say how you would recognise that from the failure alone.

for a principal

Frame the cost: a suite whose queries routinely match more elements than their authors expected produces failures that read as flake. Decide what your suite asserts about set size and where that belongs.

## What a Cypress query hands to the next command `cy.get('.room-card')` is a **query**. When the room list of a hotel booking app renders twelve `<li class="room-card">` elements, the query does not pick one of them for you and it does not hand back a raw DOM node. It yields a single **jQuery object** wrapping all twelve, and that object becomes the *subject* of whatever comes next in the chain. Cypress bundles jQuery and exposes the same function as `Cypress.$`, so the subject carries jQuery's API rather than the DOM's. That one fact explains most of the behaviour people find surprising the first week: | you write | what you actually get | |---|---| | `cy.get('.room-card')` | one jQuery set holding all 12 `<li>` elements | | `$cards.length` inside a callback | `12` | | `$cards.text()` inside a callback | every card's text run together in one string | | `cy.get('.room-card').click()` | an error — the action needs exactly one element | | `cy.get('.no-such-card')` | a failure, never an empty subject | ## The subject is a set, and commands react to its size Assertions are happy with a set. Chai-jQuery chainers such as `have.length` are written for collections, so `cy.get('.room-card').should('have.length', 12)` reads naturally and is the normal way to state how many rooms the page offers. Action commands are not happy with a set. Most of them insist on exactly one element, because Cypress refuses to guess which of your twelve room cards you meant to click: ``` cy.click() can only be called on a single element. Your subject contained 12 elements. Pass `{ multiple: true }` if you want to serially click each element. ``` That error is a feature. A locator that quietly matched more elements than its author expected is one of the most common ways a browser suite ends up acting on the wrong row, and Cypress turns it into a loud failure at the moment it happens rather than a wrong assertion three commands later. ## Inside `.then()`, you are holding jQuery `cy.get('.room-card').then(($cards) => { ... })` gives the callback the same jQuery object, which is why the convention is to name the parameter with a leading `$`. Three consequences catch people out: - **`$cards.text()` is a getter over the whole set.** jQuery concatenates the text of every element, so on a twelve-room list you get one long string, not the first card's name. - **It is not an array.** The methods on it are jQuery's, so jQuery's `.map()` does not hand back a plain JavaScript array. `$cards[0]` does reach the underlying DOM node, because jQuery objects are array-like, but everything above that index access belongs to jQuery, not to `Array.prototype`. - **It is a snapshot of the query's result at that instant.** If the app re-renders the room list while your callback is still working with `$cards`, the nodes it holds may no longer be the ones on the page. ## The two questions an interviewer usually follows with 1. **What if nothing matches?** `cy.get()` does not yield an empty collection to the next command. It keeps looking for the element and, failing that, fails the test with *Expected to find element: `.room-card`, but never found it*. Zero matches is a failure condition, not a subject — which is why you cannot test for absence by checking `$cards.length === 0` in a callback, since the chain never reaches the callback. 2. **Is it a promise?** No. Cypress subjects are not promises and a Cypress chain is not awaitable. `const $cards = cy.get('.room-card')` does not give you elements; it gives you a chainer. Anything that needs the value has to go inside `.then()` or into an assertion. ## Why this matters beyond trivia Almost every confusing early Cypress failure traces back to treating the subject as one element: a `.click()` that errors on a twelve-row room list, a `.text()` read that returns the whole list glued together, a variable assigned from a `cy` chain that is `undefined` on the next line. Saying out loud "the subject is a jQuery collection of every match, and the next command decides what to do about its size" is the sentence that makes all three obvious at once, and it is exactly what a first-screen question about `cy.get()` is looking for.

  • In Cypress, does `cy.get()` ever yield an empty jQuery collection?
    Not on its own. If nothing matches, the query fails with *Expected to find element: `.room-card`, but never found it* instead of handing an empty set onward, unless a downstream assertion explicitly permits zero matches. That is why you cannot prove absence by testing `$cards.length === 0` inside `.then()` — the chain never reaches the callback.
  • Why does `cy.get('.room-card').click()` fail in Cypress, and what does the error say?
    Most action commands require exactly one element. Cypress throws *`cy.click()` can only be called on a single element. Your subject contained 12 elements. Pass `{ multiple: true }` if you want to serially click each element.* The subject is the whole matched set, so you either reduce it to one element or opt into the serial form deliberately.

Think of it as a search results page rather than the top hit: the query hands you every match it found, and it is the next step's job to say which one you meant.

saying these in an interview costs you the question

  • Says cy.get returns a DOM element readable synchronously
  • Thinks cy.get returns a promise you can await
  • Expects .text() on 12 cards to give the first one
  • Believes cy.get yields an empty array when nothing matches
open as a page

In Cypress, how does `cy.contains()` choose which element to yield, and what does a selector argument change?

level: middleimportance: should knowfreq 58%

basics

~20 s

It yields one element: the first deepest match, promoted to an enclosing input[type=submit], button, a or label when there is one. Passing a selector as the first argument filters the candidates and switches that promotion off.

open as a page

In Cypress, a room row is aliased with `.as('firstRoom')` and then re-renders. What does `cy.get('@firstRoom')` yield?

level: seniorimportance: should knowfreq 46%

basics

~20 s

The freshly rendered row. By default Cypress stores the chain of queries that produced the subject rather than the element itself, so reading the alias re-runs those queries against the current DOM instead of returning a stale reference.

open as a page

In a Cypress test, when is `Cypress.$` safe to use, and why is it empty right after `cy.visit()`?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Cypress.$ is the bundled jQuery function and it queries the page synchronously, the instant its line runs. cy.visit() above it has only been queued, so it reads the previous page. Use it inside a callback, or from DevTools while debugging.

open as a page

In Cypress, what do `cy.title()`, `cy.document()` and `cy.window()` yield to the next command?

level: middleimportance: nice to knowfreq 30%

basics

~20 s

cy.title() yields the document.title string, cy.document() yields the application's window.document, and cy.window() yields its window object. All three read the app under test, and none of them yields a DOM element you can chain element commands onto.

open as a page