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

Viewed 5475

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()

   }    
}
2 Answers

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

1.Test Retires 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()
})

You should add a timeout to the type() command (not to the get() command) and follow it with a should() to confirm the value has been entered.

type() and should() will both retry until they succeed.

it("Can fill out form and submit", () => {
  cy.get("#modal-button").click()
  cy.get("#modal-form")  // .should("exist") - don't need as cy.get() does that already

  cy.get("#form-name").type("Mike Johnson", {timeout: 10000}) // wait for actionability
    .should('have.value', 'Mike Johnson');

  cy.get("#form-age").type("33")
  cy.get("#form-email").type("mj09@yahoo.com")
  cy.get("#submit-button").click()
})
Related