cy.intercept() not stubbing API in Cypress

44.4k Views Asked by At

When I use cy.intercept(), the API does not stub.

cy.intercept("GET", `${API}farm/list`, {
  body: {
    statusCode: 200,
    message: "Request successful",
    result: seededFarmList,
  },
});

I am importing the fixture file like this:

import { seededFarmList } from '../../../../../fixtures/farm'; 

My API response looks like this:

{
  "statusCode": 200, 
  "message": "Request successful", 
  "result": [ 
    { "id": 1 "farmName": "ABCD", },
    { "id": 2 "farmName": "EFGH", }
  ]
}

Any help would be appreciated.

7

There are 7 best solutions below

2
On

I managed to get stubbing working with the pattern @eric99 gave,

cy.intercept(
  'GET',
  'https://jsonplaceholder.typicode.com/todos/1',
  {
    statusCode: 200,
    body: {
      message: 'Request successful',
      result: ['my-data']
    }
  }
)
.as('typicode')

cy.visit('https://jsonplaceholder.typicode.com/')
cy.get('#run-button').click();

cy.wait('@typicode')
.then((interception) => {
  console.log('interception', interception)
})

The page shows the stub information,

{
    "message": "Request successful",
    "result": [
        "my-data"
    ]
}
3
On

I'm not entirely sure why it's not stubbing (presume you mean the server response is getting through?).

In any case, the stubbed response pattern is now a lot more complicated, and it's going to trip up a lot of people.

Here's my interpretation of the documentation,

In cy.route(method, url, response), response documented as body

Supply a response body to stub in the matching route.

In cy.intercept(method, url, routeHandler?), routeHandler is a more complicated beast.

routeHandler (string | object | Function | StaticResponse)

but object and StaticResponse are both objects - Cypress makes the distinction by looking at the object keys, according to this

If an object with no StaticResponse keys is passed, it will be sent as a JSON response body.

StaticResponse keys are

{
  fixture?: string
  body?: string | object | object[]
  headers?: { [key: string]: string }
  statusCode?: number
  forceNetworkError?: boolean
  delayMs?: number
  throttleKbps?: number
}

Since you are sending statusCode, your object is a StaticResponse, and therefore message and result should be moved to body,

cy.intercept('GET',
  `${API}farm/list`,
  {
    statusCode: 200,
    body: {
      message: 'Request successful',
      result: seededFarmList
    }
  }
);

IMO they've over-engineered things a little - the fallback from StaticResponse to object (depending on keys) is a bit unnecessary.


I just found an example in the sample spec network_requests.spec.js (added on Cypress 1st run).

beforeEach(() => {
  cy.visit('https://example.cypress.io/commands/network-requests')
})

...

let message = 'whoa, this comment does not exist'

// Stub a response to PUT comments/ ****
cy.intercept({
  method: 'PUT',
  url: '**/comments/*',
}, {
  statusCode: 404,
  body: { error: message },                         // stub returns above message
  headers: { 'access-control-allow-origin': '*' },
  delayMs: 500,
}).as('putComment')

// we have code that puts a comment when
// the button is clicked in scripts.js
cy.get('.network-put').click()

cy.wait('@putComment')

// our 404 statusCode logic in scripts.js executed
cy.get('.network-put-comment').should('contain', message)
0
On

I had this issue before then I found out that it was caused by CORS policy.

There are some solutions to overcome this issue:

0
On

Cypress doesn't seem to resolve the route matcher params if you use template literals in the route matcher pattern.

Does not work:

cy.intercept('GET', `/.*${mybaseUrl}\/something\/.*/`)

(even though the pattern is valid, and it even shows up right in Cypress!)

There are 2 ways I have found to make it work.

  1. Explicate the url with the routematcher parameter:
cy.intercept(
          {
            method: 'GET',
            url: `.*${mybaseUrl}\/something\/.*`
          })
  1. Use RegExp constructor
cy.intercept('GET', new RegExp(`.*${mybaseUrl}\/something\/.*`)

It does look like a bug in Cypress, but these are two very acceptable workarounds.

0
On

Not sure if you are using getServerSideProps() or any of the Next's other SSR methods, but if you are, cy.intercept() will not work as the API call is done server-side. You will have to use nock to intercept and mock any server-side API calls done within getServerSideProps() or any similar server-side methods in Next.

Comprehensive reading on this subject here: https://glebbahmutov.com/blog/mock-network-from-server/

2
On

Make sure the network intercept is registered before the application makes the api call. Notice the cy.intercept is set up before cy.visit.

it('is registered correctly', () => {
  cy.intercept('/todos').as('todos')
  cy.visit('/')
  cy.wait('@todos')
})

In the following example cy.intercept is set up after cy.visit and this might fail.

 it('is registered too late, this might fail', () => {
    cy.visit('/')
    cy.intercept('/todos').as('todos')
    cy.wait('@todos')
  })
0
On

I did this, and it stubbed the API.

cy.intercept(
          {
            method: 'GET',
            url: `${API}farm/list`
          },

          {
            body: {
              statusCode: 200,
              message: 'Request successful',
              result: seededFarmList
            }
          }
        ).as('loadData');