Can you throttle requests rather than responses in Cypress?

5.6k Views Asked by At

I am trying to end to end test a file upload page in Cypress, which includes testing if a file upload progress bar works.

Unfortunately, in the local environment the upload happens instantly so the progress bar is not shown.

I am aware that you can throttle the response speed using cy.intercept() to simulate slow networks. However, this isn't slowing the request upload speed:

cy.intercept('post', `/route`, (req) => {
    req.on('response', (res) => {
        res.setThrottle(1000) 
    })
}).as('post')

Is there any way that I can apply a throttle to the outgoing request?

3

There are 3 best solutions below

1
Sebastiano Schwarz On

I think Cypress itself can only throttle or delay responses using cy.intercept() as mentioned in the question and described here: Throttle or delay response all incoming responses

However, you can probably use the Chrome Debugger Protocol from Chrome DevTools for that. Here you have the function Network.emulateNetworkConditions that allows you to throttle both download and upload throughput. This approach then assumes that your tests run in Chrome.

If you're unsure how to use this in your Cypress tests, here is a blog post about testing an application in offline network mode that uses a similar approach with Network.enable: Testing an Application in Offline Network Mode

6
Fody On

In the routeHandler, use setTimeout() to delay the call to req.continue().

To get the command queue to wait for setTimeout, return a Promise wrapper. See Request phase

If the handler returned a Promise, wait for the Promise to resolve.

If you want a delay longer than the default command timeout of 4 seconds, you will need to increase the config since cy.intercept does not take a timeout option.

Cypress.config('defaultCommandTimeout', 6000)  // timeout in 6 seconds

cy.intercept('POST', '/route', (req) => {
  return new Promise(resolve => {
    setTimeout(() => resolve(req.continue()), 5000) // delay by 5 seconds
  })
}).as('delayedRequest')

// trigger POST

cy.wait('@delayedRequest')  

Cypress.config('defaultCommandTimeout', 4000)  // revert to normal timeout 

Middleware

If you already have a complex intercept, you can set the delay in a middleware intercept.

Middleware is always executed first, but if does not handle the request the call is passed to the next intercept.

// request is delayed here
cy.intercept('POST', '/route', {
    middleware: true                       // middleware always fires first
  }, 
  (req) => new Promise(resolve => 
    setTimeout(() => resolve(), 5000)      // no handler, just delay
  )
)

// then passed to here
cy.intercept('POST', '/route', 
  (req) => {
    req.continue()                            // handler for request
  }
).as('delayedRequest')

// trigger POST

cy.wait('@delayedRequest')  
1
Oleksandr Hrin On

My example of slowing down requests with intercept/middleware, according to Throttle or delay response all incoming responses

   cy.intercept(
  {
    method: 'POST',
    pathname: `/route`,
    middleware: true,
  },
  (req) => {
    req.on('response', (res) => {
      res.setThrottle(50); // 50 Kbps speed
    });
  }
);