6
votes

I created a test where I setup a route, try to visit a page which makes an API request to the route and then wait for the route response:

cy
    .server()
    .route('GET', '/api/testing')
    .as('testing');
cy.visit('/index.html', { timeout: 60000 });
cy.wait('@testing', { timeout: 60000 });

This only waits for the Cypress global default responseTimeout of 30 seconds and then fails the API request.

Here's the error message logged by Cypress in the console:

Cypress errored attempting to make an http request to this url: https://localhost:4200/api/testing

The error was:

ESOCKETTIMEDOUT

The stack trace was:

Error: ESOCKETTIMEDOUT
at ClientRequest. (…\node_modules\cypress\dist\Cypress\resources\app\packages\server\node_modules\request\request.js:778:19)
at Object.onceWrapper (events.js:314:30)
at emitNone (events.js:105:13)
at ClientRequest.emit (events.js:207:7)
at TLSSocket.emitTimeout (_http_client.js:722:34)
at Object.onceWrapper (events.js:314:30)
at emitNone (events.js:105:13)
at TLSSocket.emit (events.js:207:7)
at TLSSocket.Socket._onTimeout (net.js:402:8) at ontimeout (timers.js:469:11)
at tryOnTimeout (timers.js:304:5)
at Timer.listOnTimeout (timers.js:264:5)

Adding a responseTimeout to the global config of Cypress will increase the timeout, but why isn't the timeout for either the visit or the wait occurring?

2
I presume you've set a baseUrl in cypress.json? since cy.visit('/index.html') by itself will probably not navigate to the home page.Richard Matsen
The timeout works ok for me - if I throw in a bogus route(), it waits the full 60s then fails. Clicking the failed command shows Error: CypressError: Timed out retrying: cy.wait() timed out waiting 60000ms for the 1st request to the route: 'testing'. No request ever occurred in the console.Richard Matsen
Correct, a baseUrl is being used. Trying a bogus route it also waits for me. But when using a legitimate route and pausing the server response, using a debugger in the server code, it only wait for the responseTimeout.chris
Cheers, that clarifies some things. I'm wondering how you stop the particular route without stopping the whole app under test (since the route in question looks relative to the app). Sorry if I missed something obvious.Richard Matsen
The server app is .Net Core running inside of Visual Studio. A break point is set in the API controller which is called by JavaScript on the index.html page. So the entire page is served to the browser, JavaScript executes, sends a request back to the API controller on the server, hits the break point and I never continue, so a timeout occurs. Does that help? Thank you for your time thinking about this.chris

2 Answers

3
votes

See the code example on this page commands - wait - Alias

// Wait for the route aliased as 'getAccount' to respond
// without changing or stubbing its response
cy.server()
cy.route('/accounts/*').as('getAccount')
cy.visit('/accounts/123')
cy.wait('@getAccount').then((xhr) => {
  // we can now access the low level xhr
  // that contains the request body,
  // response body, status, etc
})

I would add the then((xhr) => to your code and see what response is coming through.

Logic says that if a bogus route waits the full timeout, but a 'failed legitimate route' does not, then a response with failure code is being sent back from the server within the timeout period.


The block of code in request.js where the error comes from has an interesting comment.

self.req.on('socket', function(socket) {
  var setReqTimeout = function() {
    // This timeout sets the amount of time to wait *between* bytes sent
    // from the server once connected.
    //
    // In particular, it's useful for erroring if the server fails to send
    // data halfway through streaming a response.
    self.req.setTimeout(timeout, function () {
      if (self.req) {
        self.abort()
        var e = new Error('ESOCKETTIMEDOUT')  <-- LINE 778 REFERENCED IN MESSAGE
        e.code = 'ESOCKETTIMEDOUT'
        e.connect = false
        self.emit('error', e)
      }
    })
  }

This may be a condition you want to test for (i.e connection broken mid-response).
Unfortunately, there seems to be no syntax cy.wait().catch(), see Commands-Are-Not-Promises

You cannot add a .catch error handler to a failed command.

You may want to try stubbing the route instead of setting the breakpoint on the server, but I'm not sure what form the fake response should take. (Ref route with stubbing)

1
votes

.vist() and .wait() didn't work for me, error logs on cypress suggested using .request() instead which works fine.

cy.server(); 
cy.request('/api/path').then((xhr) => {
  console.log(xhr.body)
})