Dhamo
Dhamo

Reputation: 1251

Suggestions to fix a flaky test in cypress

I have a map-based application (like Google Maps) and I am writing tests for the zoom-in option. The test covering all the zoom levels when zooming in. My test is working but the result is not consistent and it is flaky.

My code:

static verifyAllAvailableZoomInZoomSizeInNM() {
var expectedValues = [500,200,100,50,20,10,5,2,1,0.5,0.2,0.1,0.05,0.02,0.01,0.005,0.002,0.001,0.0005,0.0002,0.0001,0.00005,0.00002];
    cy.getCurrentZoomSizes({
      numValues: 26,//I expect to give 23 but I just gave 26 in order to capture all sizes
      waitBetween: 1000,
      elementLocator: BTN_MAP_ZOOMIN,
    }).should("be.eql", expectedValues);
  }

Cypress Commands:

/* Get the numeric value of zoom size in nm */
Cypress.Commands.add("getCurrentZoomSize", () => {
    cy.get('div[class="ol-scale-line-inner"]').then(
    ($el) => +$el[0].innerText.replace(" nm", "")
  ); 
});

/* Get a sequence of zoom size values */
Cypress.Commands.add("getCurrentZoomSizes", ({ numValues, waitBetween, elementLocator }) => {
  const values = [];
  Cypress._.times(numValues, () => {
    cy.getCurrentZoomSize()
      .then((value) => values.push(value))
          
    cy.get(elementLocator)
        .click()
        .wait(waitBetween);
  });
  return cy.wrap(values);
});

And the test result1:

enter image description here

test result2: enter image description here

As you can see in the screenshots, a few of the zoom sizes had duplicated. I tried giving enough wait between each zoom-in click but it is not helping either. Is there any way, I can fix this flaky test?

Upvotes: 1

Views: 969

Answers (1)

user14783414
user14783414

Reputation:

The loop executes a lot faster than the Cypress commands or the zoom operation, you can see it if you add a console.log() just inside the loop

Cypress._.times(numValues, (index) => {
  console.log(index)

That's not necessarily a problem, it just fills up the command queue really quickly and the commands then chug away.

But in between getCurrentZoomSize() calls you need to slow things down so that the zoom completes, and using .wait(waitBetween) is probably why thing get flaky.

If you apply the .should() to each zoom level, you'll get retry and wait in between each zoom action.

The problem is figuring out how to arrange things so that the proper retry occurs.

If you do

cy.getCurrentZoomSize()
  .should('eq', currentZoom);

which is equivalent to

cy.get('div[class="ol-scale-line-inner"]')
  .then($el => +$el[0].innerText.replace(" nm", "") ) 
  .should('eq', currentZoom);

it doesn't work, the conversion inside the .then() gets in the way of the retry.

This works,

cy.get('div[class="ol-scale-line-inner"]')
  .should($el => {
    const value = +$el[0].innerText.replace(" nm", "")
    expect(value).to.eq(expectedValue) 
  })

or this

cy.get('div[class="ol-scale-line-inner"]')
  .invoke('text')
  .should('eq', `${currentZoom} nm`);

So the full test might be

Cypress.Commands.add("getCurrentZoomSizes", (expectedValues, elementLocator) => {

  const numValues = expectedValues.length;
  Cypress._.times(numValues, (index) => {

    const currentZoom = expectedValues[index];

    cy.get('div[class="ol-scale-line-inner"]')
      .invoke('text')
      .should('eq', ${currentZoom} nm`);       // repeat scale read until zoom finishes
                                               // or fail if never gets there
    cy.get(elementLocator).click();            // go to next level
  });
});

const expectedValues = [...
cy.getCurrentZoomSizes(expectedValues, BTN_MAP_ZOOMIN)

Upvotes: 1

Related Questions