Cypress E2E: Before hook not working on retries

Viewed 1190

Our tests have a reset state cypress command on the before hook that clears local storage and cookies so that before each run this function makes sure no session was stored. But we are somehow getting test fail upon retry because it looks like its ignoring the reset state function and doesn't start the test on the signup page. Is there a way to force the before hook when a retry happens?

2 Answers

The before-hook is excluded from retry as described here: https://docs.cypress.io/guides/guides/test-retries#How-It-Works

Also notable, if something went wrong within before-hook there will be no retry.

There is also an issue that requests this feature: https://github.com/cypress-io/cypress/issues/19458

As a workaround you can use a beforeEach:

let isError = false;

beforeEach(() => {
  cy.once('fail', (err) => {
    isError = true;
    throw err;
  });
  if (isError) {
    cy.resetAll(); // or whatever you have to do before retry
    isError = false;
  }
});

Explanation: If there is an assertion error then the 'fail'-event is triggered an is catched. In the catch-block the 'isError'-flag is set. Then on the first retry we make our reset-work and also resets the 'isError'-flag.

If you have some initial work that you do in before-hook normally, you have to do a little modification:

let isError = false;
let firstTime = true;

beforeEach(() => {
  cy.once('fail', (err) => {
    isError = true;
    throw err;
  });
  if (isError) {
    cy.resetAll();
  }
  if (firstTime || isError) {
    firstTime = false;
    isError = false;
    // setupMyBackend()
  }
});

Slightly simpler, make the before() callback callable elsewhere (declare and name it).

Use test:after:run event to call it depending on test results.

const beforeCallback = () => {...}

before(beforeCallback)

Cypress.on('test:after:run', (result) => {
  if (result.currentRetry < result.retries && result.state === 'failed') {
    beforeCallback()
  }
})

it('fails', {retries:3}, () => expect(false).to.eq(true)) // failing test to check it out
Related