Look up Cypress commands without the docs tab
Cypress drives the browser through chained cy.* commands that yield subjects
to one another. This reference lists the common commands grouped by querying,
actions, assertions, network and utilities, noting their arguments and whether
they yield a chainable subject. It runs entirely in your browser.
The Cypress mental model
Unlike Selenium-style drivers where each command is a synchronous function call, Cypress enqueues commands into an internal queue and executes them in order. Nothing runs immediately — the chain is a declaration of what you want, not imperative execution. This is why you cannot do:
// Wrong — this stores the queue item, not the element
const el = cy.get("button");
el.click();
And must instead chain:
cy.get("button").click().should("have.text", "Done");
The subject flows down the chain: each command yields a subject (a DOM element, a value, or null) to the next one.
Retry-ability: Cypress’s core superpower
Query commands and the .should() assertion automatically retry until the assertion passes or the command’s timeout expires (default 4 seconds). This means you rarely need cy.wait(ms) for UI animations. Write:
cy.get(".toast").should("be.visible");
Cypress will poll the DOM until the element becomes visible or the timeout is hit, rather than waiting a fixed number of milliseconds.
Full login + network interception example
cy.intercept("POST", "/api/login").as("login");
cy.get('[data-cy="email"]').type("[email protected]");
cy.get('[data-cy="password"]').type("secret{enter}");
cy.wait("@login").its("response.statusCode").should("eq", 200);
cy.contains("Welcome").should("be.visible");
Breaking this down:
cy.interceptregisters a spy on the POST before the form submits.as("login")stores it as an aliascy.wait("@login")pauses the test until that specific network call resolves.its("response.statusCode")plucks the status code from the response object.should("eq", 200)asserts it equals 200
Selecting elements: best practices
| Selector type | Stability | Recommended? |
|---|---|---|
[data-cy="submit"] | High | Yes — decoupled from style |
[data-testid="submit"] | High | Yes — common alternative |
.btn-primary | Medium | Fragile if class names change |
button:nth-child(2) | Low | Breaks on layout changes |
button:contains("Submit") | Medium | Fine for visible copy |
Tips for better Cypress tests
- Chain
.should()directly after a query so Cypress retries both together; avoidcy.wait(ms)with fixed delays. - Use
.as("name")to alias elements, routes or fixtures, then reference them as@nameto keep tests readable and avoid re-querying. cy.fixture("user.json")loads test data fromcypress/fixturesand pairs withcy.intercept(url, { fixture: "user.json" })to stub responses without hitting a real backend.- For multi-step flows, reset state between tests with
cy.session()or a customcy.login()command rather than logging in every test from the UI. - Prefer
cy.contains()for elements with meaningful user-visible text — it reads like user expectations and survives markup changes.