Cypress: Route matching doesn't handle `%2F` (encoded `/`) as expected

Created on 19 Apr 2020  路  6Comments  路  Source: cypress-io/cypress

Current behavior:

cy.route('api/issue*') doesn't match XHR request sent to api/issue?param=%2Fpath%2Fto (where param value is encodeURIComponent('/path/to')).

Desired behavior:

Properly encoded / symbol (as %2F) will not be treated as a path separator by the cy.route command.

Test code to reproduce

See ikornienko/cypress-route-issue-repro.

Versions

Cypress 4.4.0

Most helpful comment

For anyone who stumbles upon it: to match a request with any query params to the route /api/issue (like /api/issue?param=plain and /api/issue?param=%2Fpath%2Fto%2Fsomething) you can pass to cy.route this one: /api/issue\\?{*,*/**}.

All 6 comments

Cypress uses minimatch to match the globs against the URL. The glob you are provided matches /api/issue?param=plain but does not match /api/issue?param=/path/to/something as shown below using Cypress.minimatch():

it('should match even with %2F in a query param value', () => {
  // logs true
  console.log(Cypress.minimatch('/api/issue?param=plain', '/api/issue*', {
    matchBase: true
  }))

  // logs false
  console.log(Cypress.minimatch('/api/issue?param=/path/to/something', '/api/issue*', {
    matchBase: true
  }))
});

You need to update your glob so that it matches additional / in your route like /api/issue*/** to match the 2nd route.

@jennifer-shehane I believe you misunderstood the issue. I do NOT have / in my route, I have %2F which is a properly encoded /. I updated the test in the repo to add console logging as you did, note how the test actually logs true when I use Cypress.minimatch directly:

  it('should match even with %2F in a query param value', () => {
    cy.server();
    cy.route('/api/issue*').as('api-issue');
    cy.visit('issue');

    cy.get('#button-plain').click(); // makes GET request to /api/issue?param=plain
    cy.wait('@api-issue'); // successfully waits

    // logs true
    console.log(Cypress.minimatch('/api/issue?param=%2Fpath%2Fto%2Fsomething', `/api/issue*`, {
      matchBase: true
    }));

    cy.get('#button-path').click(); // makes GET request to /api/issue?param=%2Fpath%2Fto%2Fsomething
    cy.wait('@api-issue'); // fails waiting here
  });

@jennifer-shehane if I take a wild guess, it looks like Cypress decodes URL to show it in a pretty way in UI and logs, yet it also uses decoded version of the URL to run minimatch against it, which isn't something expected.

Chrome Dev Tools don't do this "prettying" and it's clear that there is no extra / in the path
ChromeDevTools_request

Yes, we use the decoded version of the url and expect the decoded string: https://docs.cypress.io/api/commands/route.html#With-Stubbing

Ah, I missed that in the docs, thank you for pointing out!

Hm, ok, it does make it tricky then in my case. Parameter value, opposite to the route itself, is more dynamic in most of the UIs, therefore a capability to specify "any call to this route with any query parameter value" would be great, yet I struggle now to do it with glob patterns.

For anyone who stumbles upon it: to match a request with any query params to the route /api/issue (like /api/issue?param=plain and /api/issue?param=%2Fpath%2Fto%2Fsomething) you can pass to cy.route this one: /api/issue\\?{*,*/**}.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jennifer-shehane picture jennifer-shehane  路  3Comments

carloscheddar picture carloscheddar  路  3Comments

weskor picture weskor  路  3Comments

brian-mann picture brian-mann  路  3Comments

tahayk picture tahayk  路  3Comments