Introduction
This is the first post in a multi-part series focused on the core Cypress open-source end-to-end testing features. These posts exclude any paid tools and will be kept concise and focused, starting with this Bronze Series for foundational concepts and progressing through to the Legendary Series, which explores the most advanced levels of core Cypress.
Tip! This is the introductory post; topics will be explored in more detail later in the series.
What is Cypress?
Cypress is an open-source website testing tool written in JavaScript. To use Cypress, you need to write your tests in either JavaScript or TypeScript.
During tests, Cypress runs alongside the application under test using browser automation APIs. This gives you some advantages while writing your tests, such as the ability to mock API responses or access the window or document objects.
Example Cypress Test
In this example, the test checks that a footer section is present, visible, and displays the expected copy.
describe("Footer tests", () => {
it("should show copyright text", () => {
cy.visit("/");
cy.contains("footer", "© 2025 awilliams.me.")
.should("be.visible");
});
});
Installing Cypress
To install Cypress, run npm i -D cypress
in your project. After that, run npx cypress open
to launch the Cypress open mode app where you can run single tests at a time and view a snapshot of the application under test at each step of the test.
jQuery Under the Hood
Cypress tests are written using Cypress commands, such as cy.get('main')
. Under the hood, these commands use jQuery and yield a jQuery-wrapped array of DOM elements. You can access properties using cy.invoke()
or access the raw DOM node via indexing ([0]
).
Cypress Command Chaining
Unlike regular JavaScript, Cypress commands do not execute immediately. Each command is queued to run later, after the test function has finished running.
Cypress commands are chained. Each command yields a result to the next — this yielded value is known as the subject.
cy.get('a')
.should("have.length.greaterThan", 0);
In this example, the list of a
tags is yielded from cy.get()
and passed down to the .should()
assertion.
Because of Cypress’s command queueing, you can’t directly return a value from a Cypress command. Instead, tests must continue using Cypress’s chaining model.
Warning! Cypress commands may look like Promises, but they can't be used like Promises. They’re added to a queue and run later.
Retry-ability
One of Cypress's key selling points is its retry-ability feature. It automatically gives querying and assertions retries until they pass or timeout.
For example, jQuery’s $('main')
will attempt to find the <main>
tag once and return the result immediately. The Cypress equivalent cy.get('main')
will, by default, retry for up to 4 seconds until it finds the element, and then yield it to the next command in the chain.
Actionability
Cypress also has actionability, which is a process that takes place when using commands like .click()
, .type()
, or .clear()
. These trigger a series of checks to simulate real user behavior, such as scrolling the element into view and verifying visibility.
Cypress Command Types
Below is a categorized reference of common Cypress commands, grouped by purpose. This isn’t exhaustive but outlines how Cypress commands are structured.
Assertions
Handle chained expectation callbacks for the subject.
cy.should()
cy.and()
Actions
Actions should be used on a yielded subject. These run through the actionability checks before interacting with the element.
cy.click()
cy.type()
Aliasing
Assigns the previous subject or request to an alias for later reuse using cy.get('@YOUR_ALIAS_NAME')
.
cy.as()
Querying
Queries on the DOM are automatically retried until they find a selector or alias or timeout.
cy.get()
cy.find()
Traversal
Traversal helpers to use on the yielded subject.
cy.find()
cy.children()
Navigation
Navigate within the application under test.
cy.visit()
cy.reload()
Waiting
It... waits...
cy.wait()
Spies, Stubs & Clocks
Spying and stubbing are Sinon wrappers.
cy.stub()
cy.clock()
Network Requests
Performing or intercepting network requests.
cy.request()
cy.intercept()
Cookies
Manage browser cookies.
cy.setCookie()
cy.clearCookies()
Storage
Manage local/session storage per origin.
cy.getAllLocalStorage()
cy.clearAllSessionStorage()
Window & Document
Query window objects or set the viewport size.
cy.document()
cy.viewport()
Location
Query the page URL or document location value.
cy.url()
cy.location()
Origin
Cross-origin commands used with testing multiple domains.
cy.origin()
Files & Fixtures
Filesystem I/O commands.
cy.readFile()
cy.fixture()
Screenshots
Test runner screenshot command.
cy.screenshot()
Sessions
Authentication session managed across test run.
cy.session()
Task & Exec
Running node code during or before the test run.
cy.task()
cy.exec()
Utilities & Connectors
Helpers for working with values or chaining logic.
cy.wrap()
cy.then()
Debugging
Debug with full access to your app and the Cypress command chain.
cy.pause()
cy.debug()
Limitations
Because of how Cypress works, it comes with a few important limitations to understand. To name some:
- 🫤 Only supports Chrome, Firefox, and WebKit browsers
- 🫤 Testing using multiple tabs is not supported
- 🫤 Testing across multiple domains is limited (possible with workarounds)
- 🫤 JavaScript alongside Cypress commands can sometimes be challenging
Wrapping Up
Continue through this series to explore more of these topics and explore more of what Cypress has to offer.