Cypress: Explicit wait doesn't work with regular expression and glob

Created on 20 Jul 2017  路  18Comments  路  Source: cypress-io/cypress

Is this a Feature or Bug?

Bug

Current behavior:

CypressError: Timed out retrying: cy.wait() timed out waiting 5000ms for the 1st request to the route: 'submit'. No request ever occured.

Desired behavior:

Explict wait should work

How to reproduce:

Test code:

The endpoint on which I want to apply explicit wait is
api/v1/account/a5f35b5f-bc8f-4c7b-a79d-68950dc2fcb7/submit
api/v1/account/<unique application id for every request>/submit

cy.server()

//Tried Regex and Glob one at a time and not all together
cy.route(/\/api\/v1\/account\/.\/submit/).as('submit')
cy.route('/api/v1/account/
').as('submit')
cy.route('/api/v1/account/
/submit').as('submit')
cy.get('button').click()
cy.wait('@submit').its('url').should('verify/complete')

Additional Info (images, stack traces, etc)

Most helpful comment

If your application is making a POST, that's why it's not working.

You need to tell cy.route you expect a POST because the default it stubs is a GET.

cy.route("POST", "api/v1/identity/**").as("identity")

All 18 comments

Hi @behlrattan, it's helpful when using globs to test your Globs in globtester or Regex in a regex checker like regex101. I was able to get the endpoint you specified to work with /api/v1/account/**/submit. Could you double check to see that this works in your example?

My globtester example

Also, I notice you are not defining a chainer in your final assertion:

cy.wait('@submit').its('url').should('verify/complete')  // incorrect

You need to define a chainer. You'll notice that the assertion will usually sound like a sentence "its url should include 'verify/complete'" like so:

cy.wait('@submit').its('url').should('include', 'verify/complete')  // correct 

Thanks @jennifer-shehane for the quick response. But, i'm afraid i'm still having issues (Timeout after 5 seconds on requestResponse.
On -- cy.wait('@submit').its('url').should('verify/complete') // incorrect
I agree, it was a typo from me.

As per the documentation https://docs.cypress.io/api/commands/wait.html#Timeouts

The first period waits for a matching request to leave the browser. This duration is configured by requestTimeout - which has a default of 5000 ms.

This means that when you begin waiting for an aliased XHR, Cypress will wait up to 5 seconds for a matching XHR to be created. If no matching XHR is found, you will get an error message that looks like: CypressError: Timed out retrying: cy.wait() timed out waiting 5000ms for the 1st request to the route: 'submit'. No request ever occured.

And that made me believe the request that i'm trying to build using glob is not working.
Please do note other place in my script i have successfully managed to use the explicit wait but without glob. I know the globtester example that you shared looks fine so at this moment i'am not sure what's wrong.

Take a screenshot of your command log.

Cypress will indicate when an XHR matches an alias. You can also click on the XHR request and get more details.

Post that command log and a screenshot of the console output after clicking on the XHR.

This is piece of code:
`cy.route('/api/v1/invest/**').as('submit')

cy.route('/api/v1/identity/**').as('identity')

cy.get('Button').click()

cy.wait(['@submit','@identity'])`

command log
xhr request endpoint
screen shot 2017-07-23 at 11 10 05 pm

If your application is making a POST, that's why it's not working.

You need to tell cy.route you expect a POST because the default it stubs is a GET.

cy.route("POST", "api/v1/identity/**").as("identity")

Thanks!, couple of things

  • POST worked for submit endpoint-
cy.route('POST', '/api/v1/invest/*/submit').as('submit')
cy.get('Button').click()
cy.wait('@submit')
  • But, POST call for identity endpoint doesn't work. After successful "submit" an immediate POST request is made to the identity endpoint. Following doesn't work
cy.route('POST', '/api/v1/invest/*/submit').as('submit')
cy.get('Button').click()
cy.wait('@submit')
cy.route('POST', '/api/v1/identity/*').as('identity')
cy.wait('@identity')

OR

cy.route('POST', '/api/v1/invest/*/submit').as('submit')
cy.route('POST', '/api/v1/identity/*').as('identity')
cy.get('Button').click()
cy.wait(['@submit','@identity'])

screen shot 2017-07-24 at 12 13 39 pm
screen shot 2017-07-24 at 12 21 31 pm

The XHR you are highlighting in the dev tools is not the one that matches what Cypress logged.

I am 100% confident there is not a bug with Cypress's stubbing behavior - all I think the problem is that you're not correctly writing your cy.route to match the URL that your request is making. If you did, Cypress would match it up.

You should use http://www.globtester.com/ to help you write a correct glob pattern.

I'm going to close this issue as I don't believe there is anything wrong on our end. If you believe something needs to be changed please create a reproducible repo with the incorrect behavior.

The screenshot of XHR in the dev tools does match with what Cypress has logged. Its api/v1/identity/application id

Hi @behlrattan.
I came across this issue while trying to find a solution for a similar situation...
At first I thought it was something related to the URL, but I've tried lot of options and I always get the same response (Timed out retrying: cy.wait() timed out ...).
have you managed to work this out?
If so, may you please let me know what the right approach would be?
This is my piece of code:

        cy.server();
        cy.fixture("myData.json").then( myData => {

            const myDataArray = [ myData ];

            cy.route("GET", "/alerts**", myDataArray)
                .as("getDataArray");
        });

        cy.visit("/");

        cy.wait("@getDataArray").its("responseBody")
          .should("have.property", "type");

Thanks in advance.

I'm assuming its timing out because your assertion is failing. Your assertion is failing because you're wrapping your myData object in an array and an array does not have a type property.

The assertion is failing because it should be failing :-P

Hi Brian.
Thanks a lot!

While you are right and I had to modify what you pointed out, I couldn't make the test work yet...
I'm using Cypress.minimatch to make sure my url matches. But when I pass it to route() I'm still getting the same error as before.

Cypress.minimatch("http://localhost:5000/v1/alerts", "**/alerts*", { matchBase: true });

Just for the sake of seeing what happen I tried "*" as my url and that way cy.wait() passes and I can see in the network info?t=1509676709990 containing the expected response, but the data doesn't appear to be available in my application.

Honestly, I'm a little bit at lost, so any suggestion is appreciated.
Thanks again.

@brian-mann Just a side-mention that the failure to match POST should probably be included in the intro-level documentation as a note/gotcha. As a Cypress newbie I got bitten by the same problem--my XHR was using POST--and only after stumbling upon this GitHub issue did I learn the default was GET. (Better, perhaps, would be that if you don't specify, it would match either). Thank you

@cosmocracy I opened an issue in our docs for your suggestion here https://github.com/cypress-io/cypress-documentation/issues/217. Our docs are open source, so feel free to contribute. :)

@julian69 I suggest playing around with Globtester if you are trying to match globs using minimatch.

I was unable to get a match with the url and glob you posted, but the glob **/alerts does however match http://localhost:5000/v1/alerts.

Thanks @jennifer-shehane for your answer.

I've been playing around with Cypress for a few days now and I apologise beforehand if what I'm asking is not relevant for this issue.

I though at first that the error I was getting was due the URL, but I tried again with a couple of matching options and still the same. Roughly, what I'm trying to do is to mock the data I'm consuming in my components using fetch. I'm working on a test environment and, otherwise, I should load data to the db every time in order to be able to run the test. As to make sure there was nothing wrong with my environment, I downloaded the "cypress-tutorial-build-todo-starter" and created a similar but simpler scenario but got stuck in the same place (Timed out retrying: cy.wait() timed out ...).
Am I missing something?

This is kind of how I get the data (not my real service, but same idea):

fetch('https://jsonplaceholder.typicode.com/posts/1')
        .then((resp) => resp.json()) 
        .then(function(data) {
            console.log(data)
 });

and this is how I'm trying to mock it:

it('mocking fetch response', () => {
        // const match = Cypress.minimatch("https://jsonplaceholder.typicode.com/posts/1", "**/posts/*", { matchBase: true });
        // match returns true
        cy.server();
        cy.route("GET", "**/posts/*", "fixture:example.json").as("getExample");
        cy.wait("@getExample").its("responseBody")
            .should("have.property", "name");
        cy.visit('/');
});

Thanks heaps!

window.fetch is not supported yet.

Here's the open issue including a simple workaround: https://github.com/cypress-io/cypress/issues/95#issuecomment-281273126

It will be supported once https://github.com/cypress-io/cypress/issues/687 has landed.

Thanks again for your time.
This last comment solved my problem.
Looking forward to the fetch support implementation.
Btw, congratulations, Cypress is awesome!

Was this page helpful?
0 / 5 - 0 ratings