javascripttestingcypresscypress-intercept

Catch unhandled requests when using cy.intercept


Is there any way to have Cypress catch any requests that are not handled and stubbed using cy.intercept. I'd like Cypress to return a useful error to highlight instances where a request is made that isn't stubbed. At the moment it just lets these requests through which is't helpful.

The way it is architected would allow for a catch-all handler if there was a way of guaranteeing a handler was the last one in the chain, but it doesn't look like there is any way to do that.


Solution

  • It's technically possible, here is a demo test to play with.

    I'm basing pattern on the premise that intercepts are processed on a last-defined basis (ignoring middleware types), so the catch-all is defined before all others.

    The catch-all uses * as matcher which will catch absolutely everything, but only those not already caught by another intercept.

    it('catching unstubbed requests', () => {
      
      const unstubbedRequests = []
      cy.intercept('*', (req) => unstubbedRequests.push(req))
    
      // these requests I have stubbed already
      cy.intercept('https://jsonplaceholder.typicode.com/todos/1', {stub:1}).as('stub1')
      cy.intercept('https://jsonplaceholder.typicode.com/posts/1', {stub:2}).as('stub2')
    
      // make some calls on the app window, simulating real app calls
      cy.window().then(win => {
        win.fetch('https://jsonplaceholder.typicode.com/todos/1')   // should stub
        win.fetch('https://jsonplaceholder.typicode.com/posts/1')   // should stub
        win.fetch('https://jsonplaceholder.typicode.com/users/1')   // should not stub
        win.fetch('https://jsonplaceholder.typicode.com/photos/1')   // should not stub
      })
    
      cy.wait('@stub1')
      cy.wait('@stub2')
      cy.wrap({}).should(() => {
        expect(unstubbedRequests.length).to.eq(2)
        expect(unstubbedRequests[0].url).to.eq('https://jsonplaceholder.typicode.com/users/1')
        expect(unstubbedRequests[1].url).to.eq('https://jsonplaceholder.typicode.com/photos/1')
      })
    })
    

    Notes

    This strategy is not bomb-proof if you want to apply it to real-world app.

    Above I've used expect(unstubbedRequests.length).to.eq(2) because I know that there will be two uncaught requests, and the .should() command will retry if there is some delay in sending the requests (there is isn't any delay in this simulation).

    To get around that, in your test you would need to provide some way of waiting before checking unstubbedRequests array, either

    but these waiting methods may be flaky if the wait time isn't long enough.

    It's a consequence of trying to prove a negative in the test.

    Ideally you want the final test to "know" all the requests that will be sent, but as an temporary test development tool this technique could be useful.