Mastering Advanced Cypress.io Test Automation [Part 3/4]: Promise Resolving
Tags: cypress, testing, javascript, e2e
Published: 2023-05-12 01:37:27

With the techniques covered in this part, you’ll have a grasp on promise resolution in Cypress.io and be closer to mastering advanced test automation with Cypress. Let’s begin!

## Promise-Resolving
JavaScript is an asynchronous language and often relies on promises to handle async operations. Cypress.io offers powerful tools for handling promises in tests. In this article, we will cover how to resolve promises in Cypress.io tests with an advanced-level example.

Promise-Resolving with Cypress.io: Promises are a fundamental part of modern JavaScript, and they enable asynchronous operations in a non-blocking manner. In Cypress.io, we can use the `.then()` method to resolve promises. However, sometimes we may encounter situations where we need to resolve promises before executing further test cases.

Consider a scenario where we need to log in to a website and then perform some actions on the dashboard. Cypress.io offers powerful tools for handling such situations.

Here’s an example code:

```
describe('Promise-Resolving', () => {
  it('Logs in and performs actions on dashboard', () => {
    cy.visit('https://example.com')
    cy.get('#username').type('testuser')
    cy.get('#password').type('testpassword')
    cy.get('#login-button').click()
    
    cy.url().then((url) => {
      if (url.includes('/dashboard')) {
        cy.get('#dashboard-actions').click()
        cy.get('#dashboard-action-1').click()
        cy.get('#dashboard-action-2').click()
      }
      else {
        cy.log('User is not logged in')
      }
    })
  })
})
```

In the code above, we first visit the website and enter the login credentials. After clicking on the login button, we resolve the promise by using the `.then()` method. We then check if the user is redirected to the dashboard page. If yes, we perform some actions on the dashboard. If not, we log a message saying that the user is not logged in.

Here is a step-by-step breakdown of the code example:
1. We start by visiting the website using the `cy.visit()` method.
2. We then use the `cy.get()` method to locate the username and password fields and enter the login credentials.
3. We click on the login button using the `cy.get()` method and the `.click()` method.
4. After clicking on the login button, we use the `cy.url()` method to get the current URL and resolve the promise using the `.then()` method.
5. We then check if the URL includes ‘/dashboard’. If yes, we perform some actions on the dashboard using the `cy.get()` and `.click()` methods.
6. If the URL does not include ‘/dashboard’, we log a message saying that the user is not logged in.

### Complications and Possible Solutions:
One common issue with resolving promises in Cypress.io tests is that it can lead to flaky tests. Flaky tests are tests that sometimes pass and sometimes fail without any obvious reason. This can happen when the promise resolution takes longer than expected, and the test fails because it times out. To avoid flaky tests, we can use the `cy.wrap()` method to wrap the promise and ensure that the test waits until the promise is resolved before proceeding.

```
it('Resolves promises using cy.wrap()', () => {
  // Promise that resolves after 2 seconds
  const promise = new Promise(resolve => {
    setTimeout(() => {
      resolve('Promise resolved!')
    }, 2000)
  })
  
  // Wrapping the promise with cy.wrap() ensures that the test waits for it to resolve
  cy.wrap(promise).should('equal', 'Promise resolved!')
})
```

In the example above;

1. We define a promise that resolves after 2 seconds using the `setTimeout()` method.
2. We then wrap the promise with the `cy.wrap()` method, which ensures that the test waits for the promise to resolve before proceeding.
3. We use the `.should()` method to assert that the resolved value of the promise is equal to _‘Promise resolved!’_.

In this way, we can ensure that our tests wait for promises to resolve and avoid flakiness in our Cypress.io tests. But another complication is when we encounter nested promises. In such cases, we can use the `Promise.all()` method to resolve multiple promises at once.

```
it('Resolves nested promises using Promise.all()', () => {
  cy.visit('https://example.com')
  cy.get('#my-element').then(element => {
    // Perform an action that returns a promise
    const promise1 = element.click()
    // Perform another action that returns a promise
    const promise2 = cy.get('#my-other-element').click()
    // Use Promise.all() to wait for both promises to resolve
    Promise.all([promise1, promise2]).then(() => {
      // Assert that the expected behavior has occurred
      cy.get('#my-element').should('have.class', 'active')
      cy.get('#my-other-element').should('be.visible')
    })
  })
})
```

In this example, we’re visiting a website and then selecting an element with the ID `#my-element`. We're then performing two actions on this element that return promises: a `.click()` action and a `cy.get()` action to select another element. We're using `Promise.all()` to wait for both of these promises to resolve before asserting that the expected behaviour has occurred.

Here’s a step-by-step breakdown of what’s happening in this code:

1. We visit the website using `cy.visit()`.
2. We select an element with the ID `#my-element` using `cy.get()`.
3. We perform an action on this element that returns a promise by calling `element.click()`. We store this promise in a variable called `promise1`.
4. We perform another action that returns a promise by calling `cy.get('#my-other-element').click()`. We store this promise in a variable called `promise2`.
5. We use `Promise.all()` to wait for both promises to resolve by passing an array of promises as an argument. When both promises have resolved, the `.then()` callback is executed.
6. Inside the `.then()` callback, we assert that the expected behaviour has occurred by using `cy.get()` and `.should()` to check that the `#my-element` element has the class `active` and that the `#my-other-element` element is visible.

Using `Promise.all()` in this way ensures that all promises are resolved before the test continues, helping to prevent flaky tests caused by promise resolution taking longer than expected.

**Summary:** Handling promises in Cypress.io tests is a critical skill for test automation engineers. It enables us to write more robust tests and handle complex scenarios. In this article, we covered how to resolve promises in Cypress.io tests with an advanced-level example. We also discussed the complications and possible solutions to ensure reliable tests. With these techniques, you can create more robust and efficient tests that can handle complex async scenarios.

---

_If you liked this, click ❤ so other people will also notice here._