Skipping a test in Cypress conditionally

I think you are almost there, but instead of the synchronous if () {...} else {...} pattern you need the asynchronous callback pattern.

it('shows the list', function() {

  const whenFailed = function() {
    this.skip()
  }

  const whenSucceeded = function() {
    cy.get('.list').should('be.visible')
  }

  queryFailed(whenFailed, whenSucceeded);
}

function queryFailed(whenFailed, whenSucceeded) {
  cy.get('.spin')
    .then($container => {
      const htmlLoaded = $container[0].innerHTML;

      if (htmlLoaded.indexOf('List') !== -1) {
        whenSucceeded();
        return;
      }

      if (htmlLoaded.indexOf('error') !== -1) {
        whenFailed();
        return;
      }

      cy.wait(1000);
      queryFailed(whenFailed, whenSucceeded);
    });
}

However, I note the recursive call to queryFailed(), which looks like you are manually retrying the content of the spin container.

Cypress has built in retries, so all you have to do is decide on a maximum time your result will possibly take (say 20 seconds), and it will conclude the command as soon as the desired content arrives, or fail the test altogether if it doesn't happen in 20 seconds.

Also, you should be in control of the success/failure of whatever the spinner is waiting on (e.g fetching the list via XHR). So you should split the test into two - one for success and one for failure.

context('when the list loading succeeds' function() {

  it('shows the list', function() {
    // Mock XHR success here
    cy.contains('.spin', 'List', { timeout: 20000 });
    cy.get('.list').should('be.visible');
  })

  it('does not show an error message', function() {
    ...
  })

})

context('when the list loading fails' function() {

  it('does not show the list', function() {
    // Mock XHR failure here
    cy.contains('.spin', 'error', { timeout: 20000 });
    cy.get('.list').should('not.be.visible');
  })

  it('shows an error message', function() {
    ...
  })

})

This is a bit rough as I don't know the exact HTML expected, or what the spinner is waiting on, but you can see this pattern is much tidier and tests all paths in a controlled manner.


Cypress now also provides a library @cypress/skip-test which can give more controls by

  • cy.skipOn
  • cy.onlyOn
  • isOn
  • boolean flag
  • headed / headless environments
  • ENVIRONMENT

DISCLOSE: I am not associated with Cypress.


Thank you for the detailed description! I provide you a solution for your very first question

I'm trying to find out if I'm able to conditionally skip a test it() in my test suite and deal with its async nature as well.

Use an environment variable, I report you a solution of mine (actually using in my pipeline).

if (!Cypress.env("SKIP_E2E_TESTS")) {
  it(...);
}

and in my package.json file I have a script that looks like this

"test": "CYPRESS_SKIP_E2E_TESTS=true npm-run-all --parallel --silent test:unit test:cypress",

My goal was the same as yours, I'd like to disable some tests in some circumstances (the CI pipeline in my case).

So put the whole test into a condition instead of having a conditional test.

Let me know if you need some more help 😉