Cypress: Stub response for same route with three different responses

I have a single endpoint in the application. We hit the same api for each request with different action in the params.

URL:

/application/api

Sample Request Payload 1:

{
  "action": "CARD_TRANSACTION_HISTORY",
  "data": {
    "date_from": "2018-12-01",
    "date_to": "2018-12-31",
    "total": 5
  },
  "meta": {}
}

Sample Request Payload 2:

{
  "action": "CARD_BALANCE",
  "data": {
    "date_from": "2018-12-01",
    "date_to": "2018-12-31",
    "total": 5
  },
  "meta": {}
}

Sample Request Payload 3:

{
  "action": "CURRENCY_RATES",
  "data": {
    "date_from": "2018-12-01",
    "date_to": "2018-12-31",
    "total": 5
  },
  "meta": {}
}

the action in above request changes for different requests.

When the dashboard page is loaded, we trigger 3 concurrent AJAX POST requests with different actions.

Problem with cypress is you can only specify one response for a route, and other way to handle this is make sequential requests (which we can't do)

Even if we write response as a function it gets called only once.

Any ideas on how we can mock data on the basis of payload?

Answers:

Answer

I had the exact same problem and found @Richard Matsen's answer very useful, however when using the whitelist option it isn't possible to access proxy.request, which returns undefined. But if you use onRequest instead of whitelist, you can access the request and thus implement any action depending on that request's body.

So this should work:

cy.server({
  onRequest: (xhr) => {
    xhr.url = xhr.url + 
      xhr.request.body.action  == 'CARD_TRANSACTION_HISTORY' ? '?transactionHistory'
      : xhr.request.body.action  == 'CARD_BALANCE' ? '?balance'
      : xhr.request.body.action  == 'CURRENCY_RATES' ? '?currencyRates'
      : ''
  }
})
Answer

I did one dirty work around that worked, I didn't like it but I am out of options.

I simply combined all the responses in the same response.

My Mock Response

{
  balance: {..},
  transactionHistory: {..},
  currencyRates: {..}
}

The each response handler simply processes part it is interested in, if one of the response is array, we'll need to change it to an object.

I'll be on a lookout for a better work around.

Answer

Here is another hack. It relies on your api ignoring url parameters and that the cy.server whitelist function is called before the request is made.

cy.server({
  whitelist: (proxy) => {
    proxy.url = proxy.url + 
      proxy.request.body.action  == 'CARD_TRANSACTION_HISTORY' ? '?transactionHistory'
      : proxy.request.body.action  == 'CARD_BALANCE' ? '?balance'
      : proxy.request.body.action  == 'CURRENCY_RATES' ? '?currencyRates'
      : ''
  }
})

const apiMocks = {
  balance: {..},
  transactionHistory: {..},
  currencyRates: {..}
}
cy.route('/application/api?balance', apiMocks.balance).as('balance')
cy.route('/application/api?transactionHistory', apiMocks.transactionHistory)
  .as('transactionHistory')
cy.route('/application/api?currencyRates', apiMocks.currencyRates).as('currencyRates')

cy.visit(...)

cy.wait('@balance').then(xhr => //should see correct mock here )
Answer

if anyone comes to this question I probably found another hack, that worked for me (I'm using unfetch polyfill to work around fetch requests and cypress) - here is the code for one route.

cy.route({
  url: '/api/ngfw/devices/search',
  method: 'POST',

  // Default response, when parametrs doesn't match
  response: [],

  onResponse: (xhr) => {
    xhr.response = { body: [] };
    const { body } = xhr.request;

    if (body.groupBy) {
      const [groupBy] = body.groupBy;
      if (groupBy === 'overallColor') {
        Object.defineProperty(xhr.xhr, 'responseText', {

          // Putting response inside
          value: JSON.stringify(mockData.totalsResult),

          enumerable: true
        });
      }
    }
  },
});

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.