cypresscypress-intercept

Cypress intercept identical request based on request body


In my app, I have a flow that triggers two POST requests to the same endpoints but with a slightly changed request body. How can we achieve this with cypress?

Request 1: Request URL: http://localhost:8000/weather/F20210908060000/spot

Request Method: POST

Request body:

{
  "locations": [
    {
      "timestamp": "2021-09-18T06:00:00.000Z",
      "coordinates": [
        106.41364531249987,
        -15.435157996299878
      ]
    },
    {
      "timestamp": "2021-09-18T07:00:00.000Z",
      "coordinates": [
        106.41364531249987,
        -15.435157996299878
      ]
    }
  ],
  "elements": [
    2
  ]
}

Request 2: Request URL:

http://localhost:8000/weather/F20210908060000/spot

Request Method: POST

Request body:

{
  "locations": [
        {
      "timestamp": "2021-09-18T04:00:00.000Z",
      "coordinates": [
        106.41364531249987,
        -15.435157996299878
      ]
    },
    {
      "timestamp": "2021-09-18T05:00:00.000Z",
      "coordinates": [
        106.41364531249987,
        -15.435157996299878
      ]
    },
{
      "timestamp": "2021-09-18T06:00:00.000Z",
      "coordinates": [
        106.41364531249987,
        -15.435157996299878
      ]
    },
    {
      "timestamp": "2021-09-18T07:00:00.000Z",
      "coordinates": [
        106.41364531249987,
        -15.435157996299878
      ]
    }
  ],
  "elements": [
    2
  ]
}

Note: Request 2 has more data in its request.

My code so far:

 cy.intercept("POST", "**/spot", (req) => {
        expect(req.locations).to.have.length.above(3);
    }).as('postSPOT1');
    Weather.activateSPOTWeather()
 });
 cy.wait('@postSPOT1').its('response.statusCode').should("eq", 200);

enter image description here


Solution

  • There's a pattern for checking the response here How to match intercept on response

    I changed the matcher to a function, as you want to evaluate an expression not match part of the response.

    cy.intercept("POST", "**/spot").as('postSPOT1')
    
    function waitFor(alias, checkFn, maxRequests, level = 0) {
      if (level === maxRequests) {
        throw `${maxRequests} requests exceeded`        
      }
      cy.wait(alias).then(interception => {
        if (!checkFn(interception)) {
          waitFor(alias, checkFn, maxRequests, level+1)
        }
      })
    }
    
    const maxRequests = 10
    const checkFn = (interception) => interception.request.locations > 3
    waitFor('@postSPOT1', checkFn, maxRequests) 
    
    cy.get('@postSPOT1.last')
      .then(lastInterception => {
        ...     
      })
    

    Or with cypress-recurse add-on

    cy.intercept("POST", "**/spot").as('postSPOT1')
    
    recurse(
      () => cy.wait('@postSPOT1'),
      (interception) => interception.request.locations > 3,
      {
        log: true,
        limit: 10, // max number of iterations
        timeout: 30000, // time limit in ms
      },
    )
    
    cy.get('@postSPOT1.last')
      .then(lastInterception => {
        ...     
      })
    

    If there are exactly two requests and you only want the second, it might be simpler to just wait twice

    cy.intercept("POST", "**/spot").as('postSPOT1')
    cy.wait('@postSPOT1')  // discard
    cy.wait('@postSPOT1')
      .then(lastInterception => {
        ...     
      })