eithed
eithed

Reputation: 4320

Assert request hasn't happened

I have following test

it('does not trigger request', () => {
    cy.shortcutThatTriggersRequest()

    cy.route({
      method: 'POST',
      url: '[url]',
      onRequest: () => {
        cy.contains('request was invoked').should('exist')
      },
    })

    cy.wait(1000)
})

which does what I want to do - if given request has happened, it will fail the test and if it didn't then the test will pass.

There're two troublesome things with it though:

Upvotes: 2

Views: 2194

Answers (3)

zithir
zithir

Reputation: 895

The most concise solution (with Cypress 13.7) I came up with was simply throwing an error in the route handler. It's not an explicit assertion, but the test still fails if the endpoint get's called

cy.intercept("...", () => {
  throw new Error("Should not happen");
})

Upvotes: 1

Miroslav Vojtuš
Miroslav Vojtuš

Reputation: 55

I have used following setup with module variable. cy.wrap failed inside cy.intercept. Maybe Cypress.env could be used but I guess it would leak to another test.


let requestPerformed;

beforeEach(() => {
   requestPerformed = false;
});

it('', () => {
  cy.intercept('/route', () => {
    requestPerformed = true;
  });

  cy.someTrigger();

  cy.wrap(requestPerformed).should('be.false');
});

I believe it could be generalized to a command.

Upvotes: 1

eithed
eithed

Reputation: 4320

Ok, to achieve this, I've used following:

it.skip('does not trigger products requests', () => {
    Cypress.on('fail', (error, runnable) => {
      if (error.message.indexOf('Timed out retrying') !== 0) throw error
    })

    cy.server()
    cy.route({
      method: 'POST',
      url: '[url]',
    }).as('products')

    cy.shortcutThatTriggersRequest()
    cy.wait('@products', {
      requestTimeout: 1000,
    }).then((xhr) => {
      assert.isNull(xhr.response.body)
    })
})

If a timeout is reached, it will be handled within fail and thus test will pass. If it gets inside then then the test will fail.

There's an additional issue here, that if multiple routes are checked (cy.wait['route1', 'route2']) and one of them doesn't exist, then the test will pass even though one of the assertions specifies that it shouldn't, for example:

it.skip('does not trigger products requests', () => {
    Cypress.on('fail', (error, runnable) => {
      if (error.message.indexOf('Timed out retrying') !== 0) throw error
    })

    cy.server()
    cy.route({
      method: 'POST',
      url: '[url]',
    }).as('route1')

    cy.route({
      method: 'POST',
      url: '[url]',
    }).as('route2')

    cy.shortcutThatTriggersRequest()
    cy.wait(['@route1', '@route2'], {
      requestTimeout: 1000,
    }).then((xhrs) => {
      assert.isNull(xhrs[0].response.body)
      assert.isNull(xhrs[1].response.body)
    })
})

passes even though there was a request to one of those endpoints (I assume it's a bug caused by handling of onfail. What needs to be done, is the request assertions need to be sequential:

cy.wait('@route1', {
  requestTimeout: 1000,
}).then((xhr) => {
  assert.isNull(xhr.response.body)
})

cy.wait('@route2', {
  requestTimeout: 1000,
}).then((xhr) => {
  assert.isNull(xhr.response.body)
})

As far as I can see we can't check the type of error in onfail as it's always CypressError irregardless of what caused it

Upvotes: 3

Related Questions