3-MIN READ

Making promises in Cypress, literally.

There are a lot of mind-twisting basic theoretical concepts about promises in Cypress: are they real promises or does Cypress internal fake them out?

Instead of jumping into the detailed theory (you can read about it from the official site), today we will go through some examples to understand its usage.

Now, Cypress.Promise is powered by the Promises API exposed by Bluebird.

Technically it’s not the ES6 JavaScript Promises, but it works and functions the same. You can use the .then method to chain multiple calls in a single expression. The element returned by cy.get is of Chainable type that exposes a .then method. The API behaves like a JavaScript promise because Cypress captures the element asynchronously from the DOM and passes it to the callback.

One of the first concepts you’ll need to understand is that all Cypress’s commands appear to be synchronous but are, in fact, asynchronous.

Cypress does the magic for you.

It manages the asynchronous queue in the background so that you can write tests “as if” they were synchronous.

Let’s consider the following example:

function getElementTextByElementSelector(selElement) {
	cy.get(selElement).then(($txt) => {
		const txt = $txt.text()
		return txt;
	});
}

In the function above, we use the cy.get method to capture an element via the selection. The API does not return the element straight-away; as that is an expensive operation.

Instead, Cypress finds the element and (upon success) passes it to the callback method. We capture the element in our $txt parameter. After that the synchronous flow continues where we read the text of the element and return it.

Cypress is a unique framework as it provides all the language features as its first-class citizen objects. The Promise API is one such example where it provides fine-grained control over the API.

Leaf Grow performance marketing tech platform campaign report screenshot

The above image of part of our proprietary marketing tech platform, Leaf Grow, shows the overall table structure that we have to run the code for; however, I attached it just for the table structure reference. Note that the text under the hidden grey lines are the ones we are searching the required text through.

function validateSearchTermInCampaignNamesFromTableRow(selColumn, selBaseRow, rowCount, strSearchTerm){
  var genArr = Array.from({length:rowCount},(v,k)=>k+1)
  console.log(`processing table with rowCount: ${rowCount}`);
  cy.wrap(genArr).each((index) => {
     //cy.get([${selBaseRow.substring(0, selBaseRow.length - 1)}-${index}"])
     cy.get([${selBaseRow.substring(0, selBaseRow.length - 1)}-${index-1}-1"])
     .find(selColumn).children().invoke('text').then((text)=>{
        console.log(text);
        if(!text.includes(strSearchTerm)){
           keywords.assert("The searched term in not found in the Campaign name!!");
        }
    }); 
  })
}

The above snippet is taken from a long code file, but it serves the purpose of explaining to you the behaviour of how we can work with promises in Cypress. You get the idea from the keyword name that we want to fetch the table rows iteratively; then, we are invoking a particular column text to check if it contains the string we want to validate or not.

Programmatically, we’ve created an array based on the parameters that we receive. We use the wrap(https://docs.cypress.io/api/commands/wrap) method to capture each element and perform an operation on it; each method would loop the handler on every item in the list.

The main part of the function is to find the element using the selColumn and then use them to handle the element asynchronously. Inside the asynchronous handler, we check if the element contains the search term we are interested in.

Though the concept of promises in Cypress is a little complicated, we have seen different scenarios where we can use them. They help us use the yielded subject in a callback function, and we can also use it to manipulate some values and perform different actions. At least for me, it’s a convenient concept to use when working with real-world applications and complex test cases.