DEV Community

Cover image for Mastering Advanced Cypress.io Test Automation [Part 3/4]: Promise Resolving
Ahsan Bilal
Ahsan Bilal

Posted on • Updated on • Originally published at Medium

Mastering Advanced Cypress.io Test Automation [Part 3/4]: Promise Resolving

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')
      }
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

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!')
})
Enter fullscreen mode Exit fullscreen mode

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')
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)