The Ultimate Guide to Choosing CYPRESS

13 Apr.,2024

 

Introduction to Cypress

info

  • How Cypress queries the DOM
  • How Cypress manages subjects and chains of commands
  • What assertions look like and how they work
  • How timeouts are applied to commands

tip

Important!

This is the single most important guide for understanding how to test with Cypress. Read it. Understand it. Ask questions about it so that we can improve it.

After you're done, we suggest watching some of our Tutorial Videos.

Simplicity is all about getting more done with less typing. Let's look at an example:

  • End-to-End Test
  • Component Test

describe

(

'Post Resource'

,

(

)

=>

{


it

(

'Creating a New Post'

,

(

)

=>

{


cy

.

visit

(

'/posts/new'

)



cy

.

get

(

"input.post-title"

)


.

type

(

"My First Post"

)

;



cy

.

get

(

"input.post-body"

)


.

type

(

"Hello, world!"

)

;



cy

.

contains

(

"Submit"

)


.

click

(

)

;



cy

.

get

(

"h1"

)


.

should

(

"contain"

,

"My First Post"

)

;


}

)

;


}

)

;


describe

(

'Post Resource'

,

(

)

=>

{


it

(

'Creating a New Post'

,

(

)

=>

{


cy

.

mount

(

<

PostBuilder

/

>

)



cy

.

get

(

"input.post-title"

)


.

type

(

"My First Post"

)

;



cy

.

get

(

"input.post-body"

)


.

type

(

"Hello, world!"

)

;



cy

.

contains

(

"Submit"

)


.

click

(

)

;



cy

.

get

(

"h1"

)


.

should

(

"contain"

,

"My First Post"

)

;


}

)

;


}

)

;


Can you read this? If you did, it might sound something like this:

note

  1. Visit page at /posts/new (or mount the PostBuilder component).
  2. Find the <input> with class post-title.
  3. Type "My First Post" into it.
  4. Find the <input> with class post-body.
  5. Type "Hello, world!" into it.
  6. Find the element containing the text Submit.
  7. Click it.
  8. Find the h1 tag, ensure it contains the text "My First Post".

This is a relatively straightforward test, but consider how much code has been covered by it, both on the client and the server!

For the remainder of this guide, we'll explore the basics of Cypress that make this example work. We'll demystify the rules Cypress follows so you can productively test your application to act as much like a user as possible, as well as discuss how to take shortcuts when it's useful.

If you've used jQuery before, you may be used to querying for elements like this:

$

(

'.my-selector'

)


In Cypress, querying elements is the same:

cy

.

get

(

'.my-selector'

)


In fact, Cypress bundles jQuery and exposes many of its DOM traversal methods to you so you can work with complex HTML structures with ease using APIs you're already familiar with.


cy

.

get

(

'#main-content'

)

.

find

(

'.article'

)

.

children

(

'img[src^="/static"]'

)

.

first

(

)


tip

Core Concept

Cypress leverages jQuery's powerful selector engine to help make tests familiar and readable for modern web developers.

Interested in the best practices for selecting elements? Read here.

Accessing the DOM elements returned from the query works differently, however:


const

$jqElement

=

$

(

'.element'

)




const

$cyElement

=

cy

.

get

(

'.element'

)


Let's look at why this is...

Question: What happens when jQuery can't find any matching DOM elements from its selector?

Answer: Oops! It returns an empty jQuery collection. We've got a real object to work with, but it doesn't contain the element we wanted. So we start adding conditional checks and retrying our queries manually.


const

$myElement

=

$

(

'.element'

)

.

first

(

)





if

(

$myElement

.

length

)

{


doSomething

(

$myElement

)


}


Question: What happens when Cypress can't find any matching DOM elements from its selector?

Answer: No big deal! Cypress automatically retries the query until either:

cy



.

get

(

'#element'

)





.

then

(

(

$myElement

)

=>

{


doSomething

(

$myElement

)


}

)


cy





.

get

(

'#element-does-not-exist'

)




.

then

(

(

$myElement

)

=>

{


doSomething

(

$myElement

)


}

)


This makes Cypress robust and immune to dozens of common problems that occur in other testing tools. Consider all the circumstances that could cause querying a DOM element to fail:

  • The DOM has not loaded yet.
  • Your framework hasn't finished bootstrapping.
  • An XHR request hasn't responded.
  • An animation hasn't completed.
  • and on and on...

Before, you'd be forced to write custom code to protect against any and all of these issues: a nasty mashup of arbitrary waits, conditional retries, and null checks littering your tests. Not in Cypress! With built-in retrying and customizable timeouts, Cypress sidesteps all of these flaky issues.

tip

Core Concept

Cypress wraps all DOM queries with robust retry-and-timeout logic that better suits how real web apps work. We trade a minor change in how we find DOM elements for a major stability upgrade to all of our tests. Banishing flake for good!

info

In Cypress, when you want to interact with a DOM element directly, call .then() with a callback function that receives the element as its first argument. When you want to skip the retry-and-timeout functionality entirely and perform traditional synchronous work, use Cypress.$.

Another way to locate things -- a more human way -- is to look them up by their content, by what the user would see on the page. For this, there's the handy cy.contains() command, for example:


cy

.

contains

(

'New Post'

)




cy

.

get

(

'.main'

)

.

contains

(

'New Post'

)


This is helpful when writing tests from the perspective of a user interacting with your app. They only know that they want to click the button labeled "Submit". They have no idea that it has a type attribute of submit, or a CSS class of my-submit-button.

caution

Internationalization

If your app is translated into multiple languages for i18n, make sure you consider the implications of using user-facing text to find DOM elements!

As we showed above, Cypress anticipates the asynchronous nature of web applications and doesn't fail immediately the first time an element is not found. Instead, Cypress gives your app a window of time to finish whatever it may be doing!

This is known as a timeout, and most commands can be customized with specific timeout periods (the default timeout is 4 seconds). These Commands will list a timeout option in their API documentation, detailing how to set the number of milliseconds you want to continue to try finding the element.


cy

.

get

(

'.my-slow-selector'

,

{

timeout

:

10000

}

)


You can also set the timeout globally via the configuration setting: defaultCommandTimeout.

tip

Core Concept

To match the behavior of web applications, Cypress is asynchronous and relies on timeouts to know when to stop waiting on an app to get into the expected state. Timeouts can be configured globally, or on a per-command basis.

info

Timeouts and Performance

There is a performance tradeoff here: tests that have longer timeout periods take longer to fail. Commands always proceed as soon as their expected criteria is met, so working tests will be performed as fast as your application allows. A test that fails due to timeout will consume the entire timeout period, by design. This means that while you may want to increase your timeout period to suit specific parts of your app, you don't want to make it "extra long, just in case".

Later in this guide we'll go into much more detail about Implicit Assertions and Timeouts.

It's very important to understand the mechanism Cypress uses to chain commands together. It manages a Promise chain on your behalf, with each command yielding a 'subject' to the next command, until the chain ends or an error is encountered. The developer should not need to use Promises directly, but understanding how they work is helpful!

As we saw in the initial example, Cypress allows you to click on and type into elements on the page by using .click() and .type() action commands with a cy.get() or cy.contains() query command. This is a great example of chaining in action. Let's see it again:

cy

.

get

(

'textarea.post-body'

)

.

type

(

'This is an excellent post.'

)


We're chaining .type() onto cy.get(), telling it to type into the subject yielded from the cy.get() query, which will be a DOM element.

Here are even more action commands Cypress provides to interact with your app:

  • .blur() - Make a focused DOM element blur.
  • .focus() - Focus on a DOM element.
  • .clear() - Clear the value of an input or textarea.
  • .check() - Check checkbox(es) or radio(s).
  • .uncheck() - Uncheck checkbox(es).
  • .select() - Select an <option> within a <select>.
  • .dblclick() - Double-click a DOM element.
  • .rightclick() - Right-click a DOM element.

These commands ensure some guarantees about what the state of the elements should be prior to performing their actions.

For example, when writing a .click() command, Cypress ensures that the element is able to be interacted with (like a real user would). It will automatically wait until the element reaches an "actionable" state by:

  • Not being hidden
  • Not being covered
  • Not being disabled
  • Not animating

This also helps prevent flake when interacting with your application in tests. You can usually override this behavior with a force option.

tip

Core Concept

Cypress provides a simple but powerful algorithm when interacting with elements.

Assertions let you do things like ensuring an element is visible or has a particular attribute, CSS class, or state. Assertions are commands that enable you to describe the desired state of your application. Cypress will automatically wait until your elements reach this state, or fail the test if the assertions don't pass. Here's a quick look at assertions in action:

cy

.

get

(

':checkbox'

)

.

should

(

'be.disabled'

)



cy

.

get

(

'form'

)

.

should

(

'have.class'

,

'form-horizontal'

)



cy

.

get

(

'input'

)

.

should

(

'not.have.value'

,

'US'

)


In each of these examples, it's important to note that Cypress will automatically wait until these assertions pass. This prevents you from having to know or care about the precise moment your elements eventually do reach this state.

We will learn more about assertions later in this guide.

A new Cypress chain always starts with cy.[command], where what is yielded by the command establishes what other commands can be called next (chained).

Each command specifies what value it yields. For example,

  • cy.clearCookies() yields null. You can chain off commands that yield null, as long as the next command doesn't expect to receive a subject.
  • cy.contains() yields a DOM element, allowing further commands to be chained (assuming they expect a DOM subject) like .click() or even cy.contains() again.
  • .click() yields the same subject it was originally given.
  • .click() requires a DOM element from the previous command.
  • .its() requires a subject, but it can be of any type.
  • cy.contains() behaves differently depending on the previous subject. If chained directly off of cy, or if the previous command yielded null, it will look at the entire document. But if the subject is a DOM element, it will only look inside that container.
  • cy.clearCookies() does not require a previous subject - it can be chained off of anything, even .end().

This is actually much more intuitive than it sounds.

cy

.

clearCookies

(

)


.

visit

(

'/fixtures/dom.html'

)



cy

.

get

(

'.main-container'

)


.

contains

(

'Headlines'

)


.

click

(

)


tip

Core Concept

Cypress commands do not return their subjects, they yield them. Remember: Cypress commands are asynchronous and get queued for execution at a later time. During execution, subjects are yielded from one command to the next, and a lot of helpful Cypress code runs between each command to ensure everything is in order.

info

Don't continue a chain after acting on the DOM

While it's possible in Cypress to act on the DOM and then continue chaining, this is usually unsafe, and can lead to stale elements. See the Retry-ability Guide for more details.

But the rule of thumb is simple: If you perform an action, like navigating the page, clicking a button or scrolling the viewport, end the chain of commands there and start fresh from cy.

info

To work around the need to reference elements, Cypress has a feature known as aliasing. Aliasing helps you to store and save references for future use.

Want to jump into the command flow and get your hands on the subject directly? No problem, add a .then() to your command chain. When the previous command resolves, it will call your callback function with the yielded subject as the first argument.

If you wish to continue chaining commands after your .then(), you'll need to specify the subject you want to yield to those commands, which you can achieve with a return value other than null or undefined. Cypress will yield that to the next command for you.

cy



.

get

(

'#some-link'

)



.

then

(

(

$myElement

)

=>

{





const

href

=

$myElement

.

prop

(

'href'

)




return

href

.

replace

(

/

(

#

.

*

)

/

,

''

)


}

)


.

then

(

(

href

)

=>

{




}

)


tip

Core Concept

We have many more examples and use cases of cy.then() in our Core Concept Guide that teaches you how to properly deal with asynchronous code, when to use variables, and what aliasing is.

Cypress has some added functionality for quickly referring back to past subjects called Aliases. It looks something like this:

cy

.

get

(

'.my-selector'

)


.

as

(

'myElement'

)


.

click

(

)





cy

.

get

(

'@myElement'

)


.

click

(

)


This lets us reuse our queries for more readable tests, and it automatically handles re-querying the DOM for us as it updates. This is particularly helpful when dealing with front end frameworks that do a lot of re-rendering!

It is very important to understand that Cypress commands don't do anything at the moment they are invoked, but rather enqueue themselves to be run later. This is what we mean when we say Cypress commands are asynchronous.

  • End-to-End Test
  • Component Test

it

(

'hides the thing when it is clicked'

,

(

)

=>

{


cy

.

visit

(

'/my/resource/path'

)



cy

.

get

(

".hides-when-clicked"

)


.

should

(

"be.visible"

)


.

click

(

)



cy

.

get

(

'.hides-when-clicked'

)


.

should

(

'not.be.visible'

)


}

)






it

(

'hides the thing when it is clicked'

,

(

)

=>

{


cy

.

mount

(

<

MyComponent

/

>

)



cy

.

get

(

".hides-when-clicked"

)


.

should

(

"be.visible"

)


.

click

(

)



cy

.

get

(

'.hides-when-clicked'

)


.

should

(

'not.be.visible'

)


}

)






Cypress doesn't kick off the browser automation until the test function exits.

Remembering that Cypress commands run asynchronously is important if you are attempting to mix Cypress commands with synchronous code. Synchronous code will execute immediately - not waiting for the Cypress commands above it to execute.

Incorrect usage

In the example below, the el evaluates immediately, before the cy.visit() has executed, so will always evaluate to an empty array.

it

(

'does not work as we expect'

,

(

)

=>

{


cy

.

visit

(

'/my/resource/path'

)



cy

.

get

(

'.awesome-selector'

)


.

click

(

)







let

el

=

Cypress

.

$

(

'.new-el'

)



if

(

el

.

length

)

{



cy

.

get

(

'.another-selector'

)


}

else

{





cy

.

get

(

'.optional-selector'

)


}


}

)






Correct usage

Below is one way the code above could be rewritten in order to ensure the commands run as expected.

it

(

'does not work as we expect'

,

(

)

=>

{


cy

.

visit

(

'/my/resource/path'

)



cy

.

get

(

'.awesome-selector'

)


.

click

(

)


.

then

(

(

)

=>

{




let

el

=

Cypress

.

$

(

'.new-el'

)



if

(

el

.

length

)

{


cy

.

get

(

'.another-selector'

)


}

else

{


cy

.

get

(

'.optional-selector'

)


}


}

)


}

)






Incorrect usage

In the example below, the check on the username value gets evaluated immediately, before the cy.visit() has executed, so will always evaluate to undefined.

it

(

'test'

,

(

)

=>

{


let

username

=

undefined



cy

.

visit

(

'https://example.cypress.io'

)


cy

.

get

(

'.user-name'

)


.

then

(

(

$el

)

=>

{




username

=

$el

.

text

(

)


}

)





if

(

username

)

{



cy

.

contains

(

username

)

.

click

(

)


}

else

{





cy

.

contains

(

'My Profile'

)

.

click

(

)


}


}

)






Correct usage

Below is one way the code above could be rewritten in order to ensure the commands run as expected.

it

(

'test'

,

(

)

=>

{


let

username

=

undefined



cy

.

visit

(

'https://example.cypress.io'

)


cy

.

get

(

'.user-name'

)


.

then

(

(

$el

)

=>

{




username

=

$el

.

text

(

)





if

(

username

)

{


cy

.

contains

(

username

)

.

click

(

)


}

else

{


cy

.

get

(

'My Profile'

)

.

click

(

)


}


}

)


}

)






tip

Core Concept

Each Cypress command (and chain of commands) returns immediately, having only been appended to a queue to be executed at a later time.

You purposefully cannot do anything useful with the return value from a command. Commands are enqueued and managed entirely behind the scenes.

We've designed our API this way because the DOM is a highly mutable object that constantly goes stale. For Cypress to prevent flake, and know when to proceed, we manage commands in a highly controlled deterministic way.

info

Why can't I use async / await?

If you're a modern JS programmer you might hear "asynchronous" and think: why can't I just use async/await instead of learning some proprietary API?

Cypress's APIs are built very differently from what you're likely used to: but these design patterns are incredibly intentional. We'll go into more detail later in this guide.

Using JavaScript loop commands like while can have unexpected effects. Let's say our application shows a random number on load.

We want the test to stop when it finds the number 7. If any other number is displayed the test reloads the page and checks again.

Note: you can find this application and the correct test in our Recipes.

Incorrect test

The test written below WILL NOT work and most likely will crash your browser.

let

found7

=

false



while

(

!

found7

)

{






cy

.

get

(

'#result'

)


.

should

(

'not.be.empty'

)


.

invoke

(

'text'

)


.

then

(

parseInt

)


.

then

(

(

number

)

=>

{


if

(

number

===

7

)

{


found7

=

true


cy

.

log

(

'lucky **7**'

)


}

else

{


cy

.

reload

(

)


}


}

)


}


The above test keeps adding more cy.get('#result') commands to the test chain without executing any! The chain of commands keeps growing, but never executes - since the test function never finishes running. The while loop never allows Cypress to start executing even the very first cy.get(...) command.

Correct test

We need to give the test a chance to run a few commands before deciding if it needs to continue. Thus the correct test would use recursion.

const

checkAndReload

=

(

)

=>

{



cy

.

get

(

'#result'

)


.

should

(

'not.be.empty'

)


.

invoke

(

'text'

)


.

then

(

parseInt

)


.

then

(

(

number

)

=>

{




if

(

number

===

7

)

{


cy

.

log

(

'lucky **7**'

)



return


}





cy

.

wait

(

500

,

{

log

:

false

}

)


cy

.

reload

(

)


checkAndReload

(

)


}

)


}



cy

.

visit

(

'public/index.html'

)


checkAndReload

(

)


The test runs and correctly finishes.

You can see a short video going through this example at

https://www.youtube.com/watch?v=5Z8BaPNDfvA

After a test function is finished running, Cypress goes to work executing the commands that were enqueued using the cy.* command chains.

  • End-to-End Test
  • Component Test

it

(

'hides the thing when it is clicked'

,

(

)

=>

{


cy

.

visit

(

'/my/resource/path'

)



cy

.

get

(

'.hides-when-clicked'

)


.

should

(

'be.visible'

)


.

click

(

)



cy

.

get

(

'.hides-when-clicked'

)


.

should

(

'not.be.visible'

)


}

)

;


it

(

'hides the thing when it is clicked'

,

(

)

=>

{


cy

.

mount

(

<

MyComponent

/

>

)



cy

.

get

(

'.hides-when-clicked'

)


.

should

(

'be.visible'

)


.

click

(

)



cy

.

get

(

'.hides-when-clicked'

)


.

should

(

'not.be.visible'

)


}

)

;


The test above would cause an execution in this order:

  1. Visit the URL (or mount the component).
  2. Find an element by its selector.
  3. Assert that the element is visible.
  4. Perform a click action on that element.
  5. Find an element by its selector.
  6. Assert that the element is no longer visible.

These actions will always happen serially (one after the other), never in parallel (at the same time). Why?

To illustrate this, let's revisit that list of actions and expose some of the hidden ✨ magic ✨ Cypress does for us at each step:

  1. Visit the URL ✨ and wait for the page load event to fire after all external resources have loaded ✨ (or mount the component ✨ and wait for the component to finish mounting ✨)
  2. Find an element by its selector ✨ and retry until it is found in the DOM
  3. Assert that the element is visible ✨ and retry until the assertion passes
  4. Perform a click action on that element ✨ after we wait for the element to reach an actionable state
  5. Find an element by its selector ✨ and retry until it is found in the DOM
  6. Assert that the element is no longer visible ✨ and retry until the assertion passes

As you can see, Cypress does a lot of extra work to ensure the state of the application matches what our commands expect about it. Each command may resolve quickly (so fast you won't see them in a pending state) but others may take seconds, or even dozens of seconds to resolve.

While most commands time out after a few seconds, other specialized commands that expect particular things to take much longer like cy.visit() will naturally wait longer before timing out.

These commands have their own particular timeout values which are documented in the Cypress configuration.

tip

Core Concept

Any waiting or retrying that is necessary to ensure a step was successful must complete before the next step begins. If they don't complete successfully before the timeout is reached, the test will fail.

While the API may look similar to Promises, with its then() syntax, Cypress commands and queries are not promises - they are serial commands passed into a central queue, to be executed asynchronously at a later date. These commands are designed to deliver deterministic, repeatable and consistent tests.

Almost all commands come with built-in retry-ability. Without retry-ability, assertions would randomly fail. This would lead to flaky, inconsistent results.

info

While Cypress does have a .then() command, Cypress commands are not Promises and cannot be awaited. If you'd like to learn more about handling asynchronous Cypress Commands please read our Variables and Aliases Guide.

Commands also have some design choices that developers who are used to promise-based testing may find unexpected. They are intentional decisions on Cypress' part, not technical limitations.

  1. You cannot race or run multiple commands at the same time (in parallel).
  2. You cannot add a .catch error handler to a failed command.

The whole purpose of Cypress (and what makes it very different from other testing tools) is to create consistent, non-flaky tests that perform identically from one run to the next. Making this happen isn't free - there are some trade-offs we make that may initially seem unfamiliar to developers accustomed to working with Promises or other libraries.

Let's take a look at each trade-off in depth:

Cypress guarantees that it will execute all of its commands and queries deterministically and identically every time they are run.

A lot of Cypress commands mutate the state of the browser in some way.

  • cy.request() automatically gets + sets cookies to and from the remote server.
  • cy.clearCookies() clears all of the browser cookies.
  • .click() causes your application to react to click events.

None of the above commands are idempotent; they all cause side effects. Racing commands is not possible because commands must be run in a controlled, serial manner in order to create consistency. Because integration and e2e tests primarily mimic the actions of a real user, Cypress models its command execution model after a real user working step by step.

In Cypress there is no built in error recovery from a failed command. A command eventually passes, or if it fails, all remaining commands are not executed, and the test as a whole fails.

You might be wondering:

How do I create conditional control flow, using if/else? So that if an element does (or doesn't) exist, I choose what to do?

Cypress does not support this type of conditional control flow because it leads to non-deterministic tests - different runs may behave differently, which makes them less consistent and useful for verifying your application's correctness. In general, there are only a handful of very specific situations where you can or should create control flow using Cypress commands.

With that said, as long as you are aware of the potential pitfalls with control flow, it is possible to do this in Cypress! You can read all about how to do conditional testing here.

As we mentioned previously in this guide:

note

Assertions describe the desired state of your elements, your objects, and your application.

What makes Cypress unique from other testing tools is that assertions automatically retry. Think of them as guards - assertions describe what your application should look like, and Cypress will automatically block, wait, and retry until it reaches that state.

Let's look at how you'd describe an assertion in English:

note

After clicking on this <button>, I expect its class to be active.

To express this in Cypress you'd write:

cy

.

get

(

'button'

)

.

click

(

)


cy

.

get

(

'button'

)

.

should

(

'have.class'

,

'active'

)


This above test will pass even if the .active class is applied to the button asynchronously, after an indeterminate period of time or even if the button is removed from the DOM entirely for a while (replaced with a waiting spinner, for example).




$

(

'button'

)

.

on

(

'click'

,

(

e

)

=>

{


setTimeout

(

(

)

=>

{


$

(

e

.

target

)

.

addClass

(

'active'

)


}

,

2000

)


}

)


Here's another example.

note

After making an HTTP request to my server, I expect the response body to equal {name: 'Jane'}

To express this with an assertion you'd write:

cy

.

request

(

'/users/1'

)

.

its

(

'body'

)

.

should

(

'deep.eq'

,

{

name

:

'Jane'

}

)


Despite the dozens of assertions Cypress makes available to you, sometimes the best test may make no assertions at all! How can this be? Aren't assertions a basic part of testing?

  • End-to-End Test
  • Component Test

cy

.

visit

(

'/home'

)



cy

.

get

(

'.main-menu'

)

.

contains

(

'New Project'

)

.

click

(

)



cy

.

get

(

'.title'

)

.

type

(

'My Awesome Project'

)



cy

.

get

(

'form'

)

.

submit

(

)


cy

.

mount

(

<

MyComponent

/

>

)



cy

.

get

(

'.main-menu'

)

.

contains

(

'New Project'

)

.

click

(

)



cy

.

get

(

'.title'

)

.

type

(

'My Awesome Project'

)



cy

.

get

(

'form'

)

.

submit

(

)


Without a single explicit assertion, there are dozens of ways this test can fail. Here's a few:

  • The initial cy.mount() or cy.visit() could respond with something other than success.
  • Any of the cy.get() queries could fail to find their elements in the DOM.
  • The element we want to .click() on could be covered by another element.
  • The input we want to .type() into could be disabled.
  • Form submission could result in a non-success status code.
  • The in-page JS (the application under test) or the component could throw an error.

tip

Core Concept

With Cypress, you don't have to write explicit assertions to have a useful test. Without a single expect() or .should(), a few lines of Cypress can ensure thousands of lines of code are working properly across the client and server.

This is because many commands have built in Implicit Assertions which offer you a high level of confidence that your application is working as expected.

Many commands have default, built-in assertions, or rather have requirements that may cause it to fail without needing an explicit assertion you've added.

  • cy.visit() expects the page to send text/html content with a 200 status code.
  • cy.request() expects the remote server to exist and provide a response.
  • cy.contains() expects the element with content to eventually exist in the DOM.
  • cy.get() expects the element to eventually exist in the DOM.
  • .find() also expects the element to eventually exist in the DOM.
  • .type() expects the element to eventually be in a typeable state.
  • .click() expects the element to eventually be in an actionable state.
  • .its() expects to eventually find a property on the current subject.

Certain commands may have a specific requirement that causes them to immediately fail without retrying, such as cy.request().

Others, such as DOM queries automatically retry and wait for their corresponding elements to exist before failing.

Action commands automatically wait for their element to reach an actionable state before failing.

tip

Core Concept

All DOM commands automatically wait for their elements to exist in the DOM.

You never need to write .should('exist') after querying the DOM.

Most commands give you the flexibility to override or bypass the default ways they can fail, typically by passing a {force: true} option.

cy




.

get

(

'button'

)





.

click

(

)


Cypress will automatically wait for elements to pass their implicit assertions. See Timeouts below for more on how timeouts are determined.

Most of the time, when querying for elements, you expect them to eventually exist. But sometimes you wish to wait until they don't exist.

All you have to do is add that assertion and Cypress will skip implicitly waiting for elements to exist.

cy

.

get

(

'button.close'

)

.

click

(

)





cy

.

get

(

'button.close'

)

.

should

(

'not.exist'

)





cy

.

get

(

'#modal'

)

.

should

(

'not.exist'

)


tip

Core Concept

If you want to disable the default existence assertion, you can add .should('not.exist') to any DOM command.

Other commands have other implicit assertions not related to the DOM.

For instance, .its() requires that the property you're asking about exists on the object.


const

obj

=

{

}




setTimeout

(

(

)

=>

{


obj

.

foo

=

'bar'


}

,

1000

)




cy

.

wrap

(

obj

)

.

its

(

'foo'

)


Cypress bundles Chai, Chai-jQuery, and Sinon-Chai to provide built-in assertions. You can see a comprehensive list of them in the list of assertions reference. You can also write your own assertions as Chai plugins and use them in Cypress.

There are two ways to write assertions in Cypress:

  1. As Cypress Commands: Using .should() or .and().
  2. As Mocha Assertions: Using expect.

Using .should() or .and() commands is the preferred way of making assertions in Cypress. These are typical Cypress commands, which means they apply to the currently yielded subject in the command chain.



cy

.

get

(

'tbody tr:first'

)

.

should

(

'have.class'

,

'active'

)


You can chain multiple assertions together using .and(), which is another name for .should() that makes things more readable:

cy

.

get

(

'#header a'

)


.

should

(

'have.class'

,

'active'

)


.

and

(

'have.attr'

,

'href'

,

'/users'

)


Because .should('have.class') does not change the subject, .and('have.attr') is executed against the same element. This is handy when you need to assert multiple things against a single subject quickly.

Using expect allows you to assert on any JavaScript object, not just the current subject. This is probably how you're used to seeing assertions written in unit tests:


expect

(

true

)

.

to

.

be

.

true


info

Did you know you can write Unit Tests in Cypress?

Check out our example recipes for unit testing and unit testing React components.

Mocha assertions are great when you want to:

  • Perform custom logic prior to making the assertion.
  • Make multiple assertions against the same subject.

The .should() assertion allows us to pass a callback function that takes the yielded subject as its first argument. This works like .then(), except Cypress automatically waits and retries for everything inside of the callback function to pass.

info

Complex Assertions

The example below is a use case where we are asserting across multiple elements. Using a .should() callback function is a great way to query from a parent into multiple children elements and assert something about their state.

Doing so enables you to block and guard Cypress by ensuring the state of descendants matches what you expect without needing to query them individually with regular Cypress DOM commands.

cy

.

get

(

'p'

)

.

should

(

(

$p

)

=>

{




let

texts

=

$p

.

map

(

(

i

,

el

)

=>

{


return

Cypress

.

$

(

el

)

.

text

(

)


}

)





texts

=

texts

.

get

(

)




expect

(

texts

)

.

to

.

have

.

length

(

3

)




expect

(

texts

)

.

to

.

deep

.

eq

(

[


'Some text from first p'

,


'More text from second p'

,


'And even more text from third p'

,


]

)


}

)


danger

Make sure .should() is safe

When using a callback function with .should(), be sure that the entire function can be executed multiple times without side effects. Cypress applies its retry logic to these functions: if there's a failure, it will repeatedly rerun the assertions until the timeout is reached. That means your code should be retry-safe. The technical term for this means your code must be idempotent.

Almost all commands can time out in some way.

All assertions, whether they're the default ones or whether they've been added by you all share the same timeout values.

You can modify a commands's timeout. This timeout affects both its default assertions (if any) and any specific assertions you've added.

Remember because assertions are used to describe a condition of the previous commands - the timeout modification goes on the previous commands not the assertions.



cy

.

get

(

'.mobile-nav'

)


Under the hood Cypress:

  • Queries for the element .mobile-nav

    and waits up to 4 seconds for it to exist in the DOM


cy

.

get

(

'.mobile-nav'

)

.

should

(

'be.visible'

)

.

and

(

'contain'

,

'Home'

)


Under the hood Cypress:

  • Queries for the element .mobile-nav

    and waits up to 4 seconds for it to exist in the DOM✨ ✨and be visible✨ ✨and contain the text: Home

The total amount of time Cypress will wait for all of the assertions to pass is for the duration of the cy.get() timeout (which is 4 seconds).

Timeouts can be modified per command and this will affect all implicit assertions and any assertions chained after that command.



cy

.

get

(

'.mobile-nav'

,

{

timeout

:

10000

}

)


.

should

(

'be.visible'

)


.

and

(

'contain'

,

'Home'

)


Under the hood Cypress:

  • Gets the element .mobile-nav

    and waits up to 10 seconds for it to exist in the DOM✨ ✨and be visible✨ ✨and contain the text: Home

Notice that this timeout has flowed down to all assertions and Cypress will now wait up to 10 seconds total for all of them to pass.

danger

Note that you never change the timeout inside the assertion. The timeout parameter always goes inside the command.


cy

.

get

(

'.selector'

)

.

should

(

'be.visible'

,

{

timeout

:

1000

}

)



cy

.

get

(

'.selector'

,

{

timeout

:

1000

}

)

.

should

(

'be.visible'

)


Remember, you are retrying the command with attached assertions, not just the assertions!

Cypress offers several different timeout values based on the type of command.

We've set their default timeout durations based on how long we expect certain actions to take.

For instance:

  • cy.visit() loads a remote page and does not resolve until all of the external resources complete their loading phase. This may take awhile, so its default timeout is set to 60000ms.
  • cy.exec() runs a system command such as seeding a database. We expect this to potentially take a long time, and its default timeout is set to 60000ms.
  • cy.wait() actually uses 2 different timeouts. When waiting for a routing alias, we wait for a matching request for 5000ms, and then additionally for the server's response for 30000ms. We expect your application to make a matching request quickly, but we expect the server's response to potentially take much longer.

That leaves most other commands including all DOM queries to time out by default after 4000ms.

Finding your dream home in a bustling city like Cypress can be both exhilarating and overwhelming. With a diverse array of neighborhoods, architectural styles, and amenities, the options may seem endless. In this comprehensive blog post, we'll provide you with the ultimate guide to streamline your home search and help you find the perfect place to call home in the vibrant city of Cypress.

1. Define Your Priorities

Start by creating a list of your must-haves and deal-breakers. Consider factors such as location, commute times, school districts, and the type of property that suits your lifestyle, whether it's a single-family home, townhouse, or condominium.

2. Research Cypress's Diverse Neighborhoods

Cypress, Texas, showcases diverse neighborhoods, each with its distinctive charm. Explore Bridgeland for master-planned living, discover Towne Lake for waterfront allure, or venture into Cypress Town Center for shopping and entertainment options. Grasping the personality of each locale aids in streamlining your search.

3. Work with a Knowledgeable Realtor®

A local real estate agent with extensive knowledge of Cypress's market is an invaluable resource. They can guide you to neighborhoods that align with your preferences, provide insight into market trends, and help negotiate a competitive offer.

4. Determine Your Budget

Knowing your budget is crucial to finding a home that meets your financial goals. Get pre-approved for a mortgage to understand how much you can afford, and set a budget that includes not just the purchase price but also closing costs, moving expenses, and any renovations or updates you may want to make.

5. Attend Open Houses and Virtual Tours

Take advantage of open houses and virtual tours to explore potential homes. This hands-on approach will give you a feel for the property's layout, condition, and neighborhood. Take notes and pictures to remember the features of each home.

6. Consider Future Growth and Development

Look into the future development plans for the neighborhood you're considering. Changes in infrastructure, nearby businesses, and upcoming community projects can influence your decision.

7. Factor in Commute and Transportation

Cypress's vast size means commuting times can vary significantly. Consider proximity to major highways, public transportation options, and the distance to your workplace or other frequent destinations.

8. Check for Amenities and Services

Identify the amenities and services that matter most to you. Whether it's parks, schools, shopping centers, or recreational facilities, ensure your chosen neighborhood aligns with your lifestyle preferences.

9. Be Prepared to Act Swiftly

The Cypress real estate market can be competitive, so be prepared to act quickly when you find a home that checks all your boxes. Have your finances in order and be ready to make a competitive offer.

10. Trust Your Instincts

Lastly, trust your instincts when choosing your dream home. Take your time to find the property that feels right for you and your family. This decision is not just about the house; it's about finding a place where you'll create lasting memories and build your future.

Cypress Awaits Your Dream Home

As you embark on your home search journey in Cypress, remember that finding your dream home is an exciting process filled with possibilities. Define your priorities, work with a knowledgeable realtor®, and explore the diverse neighborhoods this city has to offer. With a well-informed approach and a sense of adventure, you'll soon discover the perfect place to call home in the thriving metropolis of Cypress.

Welcome to Cypress, where your dream home awaits!

I hope you have found this blog post super helpful. If there is anything else we can do for you, including helping you sell (or buy) a home, I would be honored to assist. I hope you have a great day/evening. Cheers, E + J.

We are so happy you found our little corner of the interwebs. We look forward to y'all reaching out to us. We love to answer questions and welcome them. Recently we created some local maps, and you can download those by clicking the image/link above. Below, you will find an index of some very helpful information to assist you in learning more about the Houston suburbs. If you are relocating to our neck of the woods, we hope you reach out to us, because we would love to help you by being your local realtor and friend. Thoughtfully written for you. Hugs, Jo.

We are Waiting for You

If you are looking to relocate to the Houston Area, we would love to meet you, and hear your story. Below you will find all of my contact information, as well as some homes for sale in the area. We truly look forward to hearing from you! P.S. Don't forget to check out our YouTube Channel!

If you are overwhelmed..

Now if you are feeling overwhelmed on where you should plant your roots, I would love to talk to you. You can schedule a call with me by click this link: http://byjoandco.com/call or just send us an email: [email protected]. There are some amazing communities all over the Houston suburbs. In this post, https://search.byjoandco.com/blog/best-neighborhoods-in-houston/, I deep dive into all the different suburbs/neighborhoods that you might want to consider, and why. There are many resources here, so please reach out if you are curious what to look at next! Thank you for trusting us.

What next?!

• Navigate our Blog: https://byjoandco.com/categories-to-help-you-navigate-the-blog/
• Download our Moving to Texas ebook! http://byjoandco.com/movingtotexasebook.
• Download our Where to Live in Houston Texas ebook! http://byjoandco.com/wheretoliveebook.
• Browse our Ebooks and Relocation Guides: http://byjoandco.com/ebooks
• Schedule a phone call or appointment with us! http://byjoandco.com/appointment.
• Email us! [email protected].
• Looking for a buyer’s agent? Fill out our buyer questionnaire! http://byjoandco.com/q.
• Ready to find your dream home? Search, http://search.byjoandco.com.
• Subscribe to our YouTube Channel: http://byjoandco.com/youtube.

The Ultimate Guide to Choosing CYPRESS

The Ultimate Guide to Finding Your Dream Home in Cypress