Know this thing in Cypress
Tags: react, nextjs, javascript, webdev
Published: 2021-11-13 00:43:55



---
canonical_url: "https://www.thangphan.xyz/posts/know-this-thing-in-cypress/"
---

### Why Cypress!

We are working on a project that uses the Next.js framework. And in order to do unit tests for the project. We use Jest.

Jest is so great!

But when we want to test the unit page of Next.js, Jest feels a little bit harder to implement. Instead of using Jest, Cypress is an amazing selection for our goal.

In this article, we're going to figure some core concepts of Cypress.

Let's grab a drink and go forward!

### before-after

When we run our test in Cypress environment, we are able to run debug or do some stuff in the browser.

For example:

I want to check the input whether it's typed or not, I need to do this flow:

1. Type some inputs.

2. Confirm the inputed value.

With this flow, the great thing in Cypress is I am able to travel forward or backward the action.

I can go backward to the input when it isn't typed. Or just go forward to the input when it is typed.

In order to better of understanding, I'm going to demo the `before-after` in Cypress.

This is the flow:

- Having an input that isn't typed any words.

- Type some words in the input.

- Observe the `after` state in Cypress.

**Step1: Create a page in Next.js**

There are an input element and a label element in our page.

```tsx
export default function BeforeAfter() {
  return (
    <div>
      <form>
        <label htmlFor="username" aria-describedby="userName">
          Username:
        </label>

        <input id="username" aria-describedby="userName" />
      </form>
    </div>
  )
}
```

**Step2: Write Cypress Code**

First of all, create a new file `cypress.ts` under the `cypress` folder in order to connect with `Cypress`.

```tsx
it('by default, the number of cars is shown on the screen', () => {
  cy.visit('/before-after')

  cy.findByLabelText(/username/i).type('Henry Ford')
})
```

Next, we go to the `BeforeAfter` page, find the label `username`(input element), and type `Henry Ford` for it.

Now, on the left side, you are able to click the `type` state and pin it. The `before` and `after` state immediately appears. Press `before` and `after` button on the screen, we can see the content of the input is changed before
typing and after typing.

### Query DOM

#### Asynchronous

_Did you be familiar with Jquery?_

_Did you do some query like $(.className)?_

Using Jquery, we are able to query the element in a synchronous way, and if we don't find the element, Jquery will return null for us.

But in Cypress, we don't do it synchronously, we find the element in the asynchronous way.

If the element isn't found the first time, Cypress will retry to find the element in the fixed time(4000ms).

After this fixed time, if Cypress still don't figure out the element, we will receive an error.

For ease of understanding, let's describe through the example below!

```tsx
cy.get('p.username')
```

This is the way `Cypress` does:

- Find the `p` element with class `username`.

- If the element is found just yield it.

- If the element isn't found, find the element again.

- In 4000ms if `Cypress` still doesn't see the element, throw error for us.

#### Content

We also can query the element from the content of the element using `contains` function.

```tsx
cy.contains('awesome')
```

We tell `Cypress` to find the element that has the word `awesome` on the screen.

### Command Running

#### Command Asynchronous

All commands in Cypress are asynchronous. Let's discover it through the example below!

```tsx
let userName = undefined

cy.get('p.name').then(($) => {
  userName = ...
})

if(userName) {
  // do some thing
} else {
  // do some thing
}
```

Take a look at the code above, the `userName` value always is `undefined` because the command `cy.get('p.name')` is asynchronous, it still doesn't finish!

_How to resolve the problem above?_

We just move the `if else` condition to `.then` that the element is found.

```tsx
let userName = undefined

cy.get('p.name').then(($) => {
  userName = ...

  if(userName) {
  // do some thing
} else {
  // do some thing
}
})
```

### Command Asynchronous Step By Step

Imagine that we have the code below:

```tsx
cy.visit('/user-name') // 1

cy.get('input.name').type('Henry Ford') // 2,3

cy.get('button#submit').click() // 4,5
```

How `Cypress` command is run, can you guess it?

This is the way `Cypress` does for us:

1. Visit the link and wait, retry until the successful state is achieved.

2. Get the input with class `name`, wait, retry until the element is figured out.

3. Type the content.

4. Get the button with id `submit`, wait, retry until the element is figured out.

5. Trigger the `click` event.

In the flow above, if `Cypress` doesn't find the element in the retry process, it throws the error for us.

In the code above, we don't stop visiting the `about` route, we also wait for the load event finishes, we have DOM, and we can do some stuff after that.

### Assertions

#### default assertions

The great thing in cypress is default assertions, what's default assertions?

```tsx
cy.get('div.container').get('p.name').contains('your name')
```

Take a look at the code above, we have one chain with 2 steps:

1. find the `div` element with the class `container`

2. find the `p` element with the class `name`

With this chain, by default Cypress auto add assertion, assert the class `container` exists, and the class `name` exists.

### should or expect

In Cypress, we have two ways in order to assert the behavior that we expect.

- should

- expect

Using `should` is preferred to use, because it's short, easy of watching the behavior happened before we have this goal.

There are a ton of `property` that `should` is supporting, take a look at the `Cypress` doc to see in detail.

### Recap

We just learned about the core concept in Cypress, Let's recap some key points!

- We can debug and travel all of the states in Cypress.
- Query the element in Cypress is asynchronous.
- Commands in Cypress is run asynchronously.
- By default, Cypress automatically has default assertions.
- Prefer to use `should` instead of `expect`.