Sebastiano Schwarz
Sebastiano Schwarz

Reputation: 1146

How to achieve retries for individual tests using Cypress Cucumber Preprocessor?

I currently face the challenge of achieving individual test retries to stabilize a small group of specific tests that are dependent on some background processing and therefore tend to be flaky. I am using Cypress 9.2.0 with TypeScript and Cypress Cucumber Preprocessor 4.3.1.

To give a few more details, the application receives events that are processed in the background (normally takes max. 1-2 sec) and then data records are created. These records are then displayed in the UI in a table.

In some Cucumber scenarios I test exactly these cases end-to-end. Since the processing sometimes takes a little longer, I would like to preventively include retries that only apply to these test cases, more specifically the "Then" steps of the scenarios that check the final display in the table.

Since individual test retries like in standard Cypress tests unfortunately don't work with the Cucumber Preprocessor and global test retries in the cypress.json are buggy as well, I wonder if there is another way to achieve this?

Docs for normal Cypress Test Retries: https://docs.cypress.io/guides/guides/test-retries

Upvotes: 1

Views: 858

Answers (1)

Sebastiano Schwarz
Sebastiano Schwarz

Reputation: 1146

I have found a solution to my issue, although the solution in general may not be completely ideal. But first, I'd like to also mention the approaches I tried before, but which didn't work for me:

  1. Individual Test Retries for specific test steps are unfortunately not usable when working with Cypress Cucumber Preprocessor.

  2. Global Test Retries are as already mentioned in the question unfortunately also buggy in connection with Cucumber Preprocessor.

  3. Another approach I have tried was to use cy.should() with a callback but also without success.

  4. The fourth approach was based on conditional testing and finally the one that brought me to the following solution, also considering the thoughts from this post on how to not break Cypress tests, if elements are not available:

Then('the results related to some search keyword {string} are shown in the table', (search: string) => {
  checkTableWithRetries(search, 2);
});

function checkTableWithRetries(searchCriteria: string, retries: number) {
  cy.get('table').then(($table) => {
    if (checkIfTableRowExists($table) || retries === 0) {
      cy.get('table').find('tbody').contains('td', searchCriteria);
    } else {
      const time = retries === 1 ? 10000 : 5000;
      cy.wait(time);

      search(searchCriteria);
      checkTableWithRetries(searchCriteria, retries - 1);
    }
  });
}

function checkIfTableRowExists(element: JQuery<HTMLTableElement>) {
  return element.find('tbody').find('tr').length === 1;
}

function search(search: string) {
  cy.getByTestId('search-input').clear().type(`${search}`).should('have.value', `${search}`);
  cy.intercept('GET', `/api/endpoint**`).as('search');
  cy.getByTestId('search-button').click();
  cy.wait('@search');
}

The code ensures that I can check several times in a row with different delay if an element is created and displayed in the table. If after x repetitions the element is still not present, it can be assumed that there is indeed an error.

For clarification, the used function cy.getByTestId() is not a standard Cypress command but was added as a custom command according to the recommendation in the official best practices section here.

Cypress.Commands.add('getByTestId', (selector, ...options) => {
  return cy.get(`[data-test=${selector}]`, ...options);
});

Upvotes: 1

Related Questions