Cypress Asynchronous nature and its promise handling in CypressIO

Any tool which is based on node.js is asynchronous i.e build by javascript. Let us understand the difference between synchronous and asynchronous.

  • Synchronous nature : The code executes sequentially. Only if the first line of code successfully executes, then the second line of code starts executing.
  • Asynchronous nature: All the code executes simultaneously at a time. It doesn't worry about the state of the previous code.

In general, It seems like cypress executes sequentially but it is not. Internally the cypress is handled synchronously with the help of promises by queuing the commands.

We need not worry about the concepts of synchronous and asynchronous nature because it is completely taken care of by the cypress. It makes sure the commands execute sequentially.

In asynchronous, every step returns promises. Promise is like a kid's promise that the kid will say "I will give you the toy" but we never know when it will give the toy.

With respect to cypress when we try to fetch the value from the application, cypress internally receives the promise. Unless the cypress solves the promise it never knows what is the value inside the promise. Cypress always resolves the promise and gives the value to us.

There are three states of promises they are,

  • Rejection
  • Resolved
  • Pending

then() command

To know about the value present inside the promise then() method is used. This method is concatenated with the code for which we have to know the value. then() method waits until the promise is resolved and goes to the next step.

Example program: To know about the state of the promise, we have to include the then() method in each step.

describe("asynchronous and promises", () => {
  it("loading the page", () => {
    Cypress.on("uncaught:exception", (err, runnable) => {
      // returning false here prevents Cypress from
      // failing the test
      return false;
    });
    cy.visit("https://chercher.tech/practice/dropdowns").then(() => {
      cy.get("#first.col-lg-3").select("Yahoo");
    });
    cy.get("select")
      .select("Bing", " Google", "IPhone", "Yahoo")
      .invoke("val")
      .should("deep.equal", "Microsoft", "Google", "Apple", "Yahoo")
      .then(() => {});
  });
});

If we include the then() method in each step the program becomes clumsy. In order to overcome it, cypress internally executes every step with the then() command even without giving the command in each step.

Basically, the cypress wraps and hides the promises from the user view to make the program more readable. In this way asynchronous execution becomes synchronous.

Cypress and its commands are always asynchronous. Promises are handled internally by cypress for the cypress concepts and commands.

Handling promises manually in Cypress IO

There are a few cases where we should manually handle the promises. When we manipulate the basic cypress behavior, the cypress gets confused and won't create promises internally for the entire code.

Let us understand a program where we should manually concatenate the then() method.

Example program :

describe("creating manual promises", () => {
  it("storing the header element CSS in some variable and executing", () => {
    Cypress.on("uncaught:exception", (err, runnable) => {
      // returning false here prevents Cypress from
      // failing the test
      return false;
    });
    cy.visit("https://chercher.tech/practice/dropdowns");
    const heading = cy.get("div h1");
    // storing the header element in a variable called heading
    cy.log(heading.text());
    //accessing the heading variable to get the element of the header
  });
});

The above program is logically correct but the program manipulates the cypress behavior since the text() method is a jquery method. So promises are not created internally and in the output, an error occurs as below,

Output :

accessing-by-variables-error

In order to overcome the above error, promises should be created manually by using the then() method.

cy.get("div h1").then(function (headerelement) {
  cy.log(headerelement.text());
});

Example program: For the manual resolving of cypress, the program should be redefined as follows,

describe("creating manual promises", () => {
  it("storing the header element CSS in some variable and executing", () => {
    Cypress.on("uncaught:exception", (err, runnable) => {
      // returning false here prevents Cypress from
      // failing the test
      return false;
    });
    cy.visit("https://chercher.tech/practice/dropdowns");
    cy.get("div h1").then(function (headerelement) {
      cy.log(headerelement.text());
    });
  });
});

Output :

manual-handling-promises

Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions