javascripttestingcypressrace-condition

Looking for alternatives to cy.wait() on a flaky test in Cypress


So I have a flaky test case right now in Cypress. When the modal loads, it skips the filling out the name part but fills out everything else. Therefore, causing it to fail the first time, but on the retry, it passes. I tried adding an assertion (see below), but it does not work. I am trying to avoid adding using a wait command, but wanted to see if there are any other alternatives out there to cy.wait().

describe("Coach dealing with forms" () => {
 beforeEach(() => {
    loginfile.login(users.coach)
});

it("Can fill out form and submit", () => {
    cy.get("#modal-button").click()
    cy.get("#modal-form").should("exist")
    cy.get("#form-name").type("Mike Johnson")
    cy.get("#form-age").type("33")
    cy.get("#form-email").type("mj09@yahoo.com)
    cy.get("#submit-button").click()

   }    
}

Solution

  • There a number of ways to approach flaky tests. You can try these and check what suits best for your use case:

    1.Test Retries easy and effective, just retry the execution automatically it something fails. Can be applied, globally using cypress.json or to a describe block or to a it block as well.

    For it block:

      // `it` test block with custom configuration
      it('allows user to login', {
        retries: {
          runMode: 2,
          openMode: 2
        }
      }, () => {
        // ...
      })
    

    For describe block:

    // Customizing retry attempts for a suite of tests
    describe('User bank accounts', {
      retries: {
        runMode: 2,
        openMode: 2,
      }
    }, () => {
      // The per-suite configuration is applied to each test
      // If a test fails, it will be retried
      it('allows a user to view their transactions', () => {
        // ...
      }
    
      it('allows a user to edit their transactions', () => {
        // ...
      }
    })
    

    2.Adding .visible and click() before writing into the name field

    it("Can fill out form and submit", () => {
        cy.get("#modal-button").click()
        cy.get("#modal-form").should("exist")
        cy.get("#form-name").should('be.visible') //making sure the name field is visible
        cy.get("#form-name").click() //clicking on the name field
        cy.get("#form-name").type("Mike Johnson")
        cy.get("#form-age").type("33")
        cy.get("#form-email").type("mj09@yahoo.com")
        cy.get("#submit-button").click()
    })
    

    3.Use timeouts instead of waits

    cy.get("#form-name", {timeout: 10000}).type("Mike Johnson")
    

    4.Use cy.intercept() to wait for the XHR request to finish execution. Here I am assuming that there is some unfinished XHR request after clicking the modal button that is causing the issue. If that is not the case, you can debug your tests to find out and apply intercept accordingly.

    it("Can fill out form and submit", () => {
        cy.intercept('http://example.com/settings').as('getSettings') //Intercept the url that is triggered after clicking the modal button
        cy.get("#modal-button").click()
        cy.wait('@getSettings') //Wait till that request has finished execution
        cy.get("#modal-form").should("exist")
        cy.get("#form-name").type("Mike Johnson")
        cy.get("#form-age").type("33")
        cy.get("#form-email").type("mj09@yahoo.com")
        cy.get("#submit-button").click()
    })