Cypress 7.0+ / Override responses in intercept

Fujo DJ

I hope you're doing well. I'm currently working on the upgrade of cypress to 7.0. (v7.4.0 more exactly) I have an issue with the overriding of intercept calls.

It seems that Cypress team worked on the overriding problem https://github.com/cypress-io/cypress/pull/14543 (issue : https://github.com/cypress-io/cypress/issues/9302), but it doesn't work for me.

BREAKING CHANGE: Request handlers supplied to cy.intercept are now matched starting with the most-recently-defined request interceptor. This allows users to override request handlers by calling cy.intercept again. This matches the previous behavior that was standard in cy.route.

My first call deals with 2xx responses (I mock it myself)

cy.intercept('GET', 'sameUrl', {
statusCode: 2xx
}

but then I need another intercept with the same url but a different status :

cy.intercept('GET', 'sameUrl', {
statusCode: 4xx
}

I tried using middleware : A new option, middleware, has been added to the RouteMatcher type. If true, the supplied request handler will be called before any non-middleware request handlers.

cy.intercept({ method: 'GET', url: 'sameUrl', middleware: true}, req => {
    req.continue(res => {
         res.statusCode = 4xx
    });
}

But it didn't work, the first intercept is always the one being called. Please if you have any idea what I did wrong/another solution I'm all ears !

Richard Matsen

If I make a minimal example app + test, it follows the rules you quoted above.

Test

it('overrides the intercept stub', () => {

  cy.visit('../app/intercept-override.html')
  
  cy.intercept('GET', 'someUrl', { statusCode: 200 })

  cy.get('button').click()

  cy.get('div')
    .invoke('text')
    .should('eq', '200')                               // passes

  cy.intercept('GET', 'someUrl', { statusCode: 404 })

  cy.get('button').click()

  cy.get('div')
    .invoke('text')
    .should('eq', '404')                               // passes
})

App

<button onclick="clicked()">Click</button>
<div>Result</div>
<script>
  function clicked() {
    fetch('someUrl').then(response => {
      const div = document.querySelector('div')
      div.innerText = response.status
    })
  }
</script>

So, what's different in your app?


Test revised according to comments

Main points that break the test

  • unique aliases are needed
  • the string-based url (2nd test) requires minimatch wildcard prefix ** to work
beforeEach(() => {
  cy.intercept('GET', /api\/test-id\/\d+/, { statusCode: 200 })
    .as('myalias1')
  cy.visit('../app/intercept-overide.html')
})

it('sees the intercept stub status 200', () => {
  cy.get('button').click()
  cy.wait('@myalias1')
  cy.get('div')
    .invoke('text')
    .should('eq', '200')
})

it('sees the intercept stub status 404', () => {
  cy.intercept('GET', '**/api/test-id/1', { statusCode: 404 })
    .as('myalias2')

  cy.get('button').click()
  cy.wait('@myalias2')
  cy.get('div')
    .invoke('text')
    .should('eq', '404')
})

App

<button onclick="clicked()">Click</button>
<div>Result</div>
<script>
  function clicked() {
    fetch('/api/test-id/1').then(response => { 
      // logs as "http://localhost:53845/api/test-id/1" in the Cypress test runner
      const div = document.querySelector('div')
      div.innerText = response.status
    })
  }
</script>

Minimatch

The 2nd intercept uses a string which will match using minimatch. Use this code to check the intercept will work with your app's URL

Cypress.minimatch(<full-url-from-app>, <url-in-intercept>)  // true if matching 

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related