1. Cypress

Handle Non-Cypress Async Promises

In the previous article, we learned about how Cypress internally handles the asynchronous behavior of its commands and still provides a seamless, sequential, and consistent execution of the test cases. Still, there can be situations, such as combining the Cypress commands with third-party libraries or JavaScript commands, where we have to handle the async promises or commands explicitly. In this article, we will cover the following topics, which will help in managing these Non-Cypress Async Promises explicitly:

  • How to Handle Non-Cypress Async Promises using the “then” method?

As we discussed above, there will be multiple scenarios when we need to invoke/include various asynchronous third-party JavaScript libraries in our Cypress test cases. Now, as Cypress just ensures sequential execution of Cypress commands, which starts from “cy.“, we need to handle the execution of those third-party asynchronous libraries explicitly.

To achieve this, Cypress offers the “.then()” method. The “then” method enables us to work with the subject yielded/returned from the previous command. In actual, the “then” method returns a Promise, which helps in method chaining. Its syntax looks like below:

Syntax

Then method can be used with below syntax along with below options :

.then(callbackFn)
.then(options, callbackFn)

Where, callbackFn is a function that takes the previously yielded subject as its first argument.

Option Default Description
timeout defaultCommandTimeout Time to wait for .then() to resolve before timing out

.then ( ) method is modeled identically to the way how Promises work in JavaScript. Whatever returns from the callback function becomes the new subject and will flow into the next command. Additionally, the result of the last Cypress command in the callback function will be returned as the new subject and flow into the following command if there is no return or exception.

In order to understand the usage of “.then()” in more detail, let’s look at the following example:

Example: Promise handling of Console.log() command

Logging is one of the critical functionality provided by any of the test automation tools. Cypress provides commands to log details on its console, and we can invoke the same using the cy.log() method. Also, as the basis of Cypress is Mocha js library, it supports the usage of functions provided by the Mocha library. One of those functions is Console.log(), which is widely used by the Cypress test developers to print the logs directly on the browser’s console.

Now, as Console.log() is not a Cypress inbuilt function, so Cypress can’t control its asynchronous behaviour, and that should be explicitly handled by the user while developing the test case.

Let’s consider the following example, where we are using both cy.log() and Console.log() to print the information on the console.

// type definitions for Cypress object "cy"
/// <reference types="cypress" />
 
describe('My First Cypress Test', function() {
  it('Visits the ToolsQA Demo Page and check the menu items', function() {
  //Visit the Demo QA Website
  cy.visit("https://demoqa.com/");
  
 // Clicking on Widget Menu Item
  cy.get(':nth-child(4) > :nth-child(1) > .avatar > svg').click();

  //Verify number of items present under the Widget Tab
  cy.get(':nth-child(4) > .element-list > .menu-list > li').should('have.length',9);

  //Verify the number of span items under the Widgets Tab
  cy.get(':nth-child(4) > .element-list > .menu-list > li').find('span').should('have.length',9);

  //Print a string to console to show Async nature 
  cy.log('Using Cypress Log');
  console.log('Using Mocha Log'); 
  
})
})

While executing the test, you can see in the below screencast that, Console.log() as shown with marker one prints the string much before the test case starts its execution and cy.log is marker two as shown below :

Console.log() is not a cypress command, so it doesn’t follow the sequential order enforced by Cypress. On the other hand, in the same screenshot, cy.log is a cypress command, and you can see on the left-hand side, it is there at the bottom and prints according to the sequential order.

Now to run Console.log() also in sequential order, we have to handle this promise handling explicitly. We can do that using the .then() method as shown in the below code snippet:

// type definitions for Cypress object "cy"
/// <reference types="cypress" />
 
describe('My First Cypress Test', function() {
  it('Visits the ToolsQA Demo Page and check the menu items', function() {
  //Visit the Demo QA Website
  cy.visit("https://demoqa.com/");
  
 // Clicking on Widget Menu Item
  cy.get(':nth-child(4) > :nth-child(1) > .avatar > svg').click();

  //Verify number of items present under the Widget Tab
  cy.get(':nth-child(4) > .element-list > .menu-list > li').should('have.length',9);

  //Verify the number of span items under the Widgets Tab
  cy.get(':nth-child(4) > .element-list > .menu-list > li').find('span').should('have.length',9).then(() => { 
    //Handling Async behavior using then method 
    console.log('Using Mocha Log'); 
  })
  cy.log('Using Cypress Log');
})
})

Execute the above test and validate that now console.log() also gets executed sequentially. The same can be verified from the below screenshot also. As seen previously, it prints at the start, but now it’s visiting widgets hyperlink, and still, not printed yet.

So, in this example, we have explicitly resolved this promise that it should only print when the assertions happen for Cucumber results search.

Key Takeaways

  • To integrate and use third party libraries with Cypress, for automated test development, it becomes essential to handle the asynchronous nature of those libraries and “.then()” method handles it in a very efficient way.
  • “.then()” is one of the best ways to control and manage the sequential execution of the asynchronous commands provided by third-party libraries.

I hope we are now comfortable in understanding the concept of how Cypress handles the asynchronous nature of JavaScript commands and the ways to manage these commands for sequential execution.

Let’s move to the next section to understand various kinds of Cypress Assertions available.