'Wait in Cypress custom comand for response value to change

What is the best solution for polling response until value in response change from 'WAITING' to 'RUNNING'. So recursive function is not solution, because I don't want to send more than 1 request.

Cypress.Commands.add('createService', () => {
  const query = '';
  cy.request({
   method: 'POST',
      url: 'http://localhost:3000/create',
      body: {
        query
      }
  }).then((response){
     //before RUNNING status is WAITING
    expect(response.body.serviceStatus).to.eql('RUNNING');
  });
});


Solution 1:[1]

You cannot poll a cy.request() because it only ever replies with a single response.

If that response is 'WAITING', the test will not receive another response. You would have to resend the request.

Solution 2:[2]

HTTP is only single response, but the original POST can give you a status of 202 and a header to poll.

const poll = (url, attempts = 0) => {
  if (attempts > 20) throw 'Too many attempts'

  cy.request(url).then(response => {
    if (response.body.serviceStatus !== "RUNNING") {
      cy.wait(1000)  // throttle if desired
      poll(url, ++attempts)
  })
}

cy.request({
  method: 'POST',
  url: 'http://localhost:3000/create',
  body: {
    query
  }
}).then((response){

  if (response.status === 202) {
    poll(response.headers.location)
  } else {
    expect(response.body.serviceStatus).to.eq('RUNNING')
  }
})

Solution 3:[3]

You can apply a should('equal', 'RUNNING') assertion with a custom timeout. The should assertion will re-try for the specified amount of time for the expected value RUNNING. Currently the timeout is 6000ms(6 seconds) but you can change it to whatever works for your case.

Cypress.Commands.add('createService', () => {
  const query = ''
  cy.request({
    method: 'POST',
    url: 'http://localhost:3000/create',
    body: {
      query,
    },
  }).as('req')

  cy.wait('@req')
    .its('response.body.serviceStatus', {timeout: 6000})
    .should('equal', 'RUNNING')
})

Solution 4:[4]

You can use cypress-recurse for your situation.

import { recurse } from 'cypress-recurse'

recurse (
  cy.request({
     method: 'POST',
     url: 'http://localhost:3000/create',
     body: { query }
  }), // actions you want to iterate
  response.body.serviceStatus == 'RUNNING', // until this condition is satisfied  
  { // options to pass along
      log: true,
      limit: 50, // max number of iterations
      timeout: 30000, // time limit in ms
      delay: 300, // delay before next iteration, ms
  }
)

Solution 5:[5]

You should use an intercept/wait combination:

cy.intercept({
    method: 'POST',
    hostname: 'http://localhost:3000/create'
}).as('checkStatus');


cy.wait('@checkStatus').then((interception) => {
    expect(interception.response.body.serviceStatus).to.be.eq('RUNNING');
})

Above should work whether you make a single request or you make multiple requests, since the cy.wait command will intercept any call defined in the 'checkStatus' intercept function.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 SuchAnIgnorantThingToDo-UKR
Solution 2 Fody
Solution 3
Solution 4 jjhelguero
Solution 5 Fseee