cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
47.02k stars 3.18k forks source link

cy.intercept routematcher doesn't work with RegExp + template literals #25499

Closed JJ-Kamminga closed 1 year ago

JJ-Kamminga commented 1 year ago

Current behavior

When I try to use a routematcher with a valid RegExp with template literals, , it doesn't work.

cy.intercept('GET', `/.*\\/content\\/${id}\\/${id}_text_1/.*/`));

When I use the RegExp constructor, it does work.

cy.intercept('GET', new RegExp(`.*\\/content\\/${id}\\/${id}_text_1/.*`));

In the Cypress Routes overview table, the 2 show up exactly the same in the Route Matcher column (this makes it hard to debug why it doesn't work for a user!).

Desired behavior

I would like to be able to use RegExp literal with template literals as route matcher in cy.intercept().

To be clear, there are good workarounds as I described in "Current behavior".

However, I spent a considerable amount of time debugging (and reading the documentation) why my routematcher did not work. I would like to save others the time.

Test code to reproduce

/// <reference types="cypress" />
describe('page', () => {

  const googleAnalytics = 'google-analytics';

  it('works with a string', () => {
    cy.intercept('https://www.google-analytics.com/*').as('literal-string')

    cy.visit('https://docs.cypress.io/guides/overview/why-cypress')

    cy.wait('@literal-string')
  })

  it('works with a simple regex', () => {
    cy.intercept(/.*google-analytics.*/).as('simple-regex')

    cy.visit('https://docs.cypress.io/guides/overview/why-cypress')

    cy.wait('@simple-regex')
  })

  it('works with a RegExp constructor', () => {
    cy.intercept(new RegExp(`.*${googleAnalytics}.*`)).as('regex-constructor-with-template-literal');

    cy.visit('https://docs.cypress.io/guides/overview/why-cypress')

    cy.wait('@regex-constructor-with-template-literal')
  })

  it('doesnt work with a RegExp literal with a template literal', () => {
    cy.intercept(`/.*${googleAnalytics}.*/`).as('regex-literal-with-template-literal')

    cy.visit('https://docs.cypress.io/guides/overview/why-cypress')

    cy.wait('@regex-literal-with-template-literal')
  })

  it('doesnt work with a RegExp literal with a template literal in object arg', () => {
    cy.intercept({
      method: 'GET',
      url: `.*${googleAnalytics}.*`
    }).as('regex-literal-with-template-literal-in-obj')

    cy.visit('https://docs.cypress.io/guides/overview/why-cypress')

    cy.wait('@regex-literal-with-template-literal-in-obj')
  })

})

Cypress Version

11.2.0

Node version

18.8.0

Operating System

macOS 13.1

Debug Logs

page
    ✓ works with a string (3459ms)
    ✓ works with a simple regex (1684ms)
    ✓ works with a RegExp constructor (1647ms)
    1) doesnt work with a RegExp literal with a template literal
    2) doesnt work with a RegExp literal with a template literal in object arg

  3 passing (23s)
  2 failing

  1) page
       doesnt work with a RegExp literal with a template literal:
     CypressError: Timed out retrying after 5000ms: `cy.wait()` timed out waiting `5000ms` for the 1st request to the route: `regex-literal-with-template-literal`. No request ever occurred.

https://on.cypress.io/wait
      at cypressErr (https://docs.cypress.io/__cypress/runner/cypress_runner.js:161339:18)
      at Object.errByPath (https://docs.cypress.io/__cypress/runner/cypress_runner.js:161408:10)
      at checkForXhr (https://docs.cypress.io/__cypress/runner/cypress_runner.js:146476:92)
      at <unknown> (https://docs.cypress.io/__cypress/runner/cypress_runner.js:146499:28)
      at tryCatcher (https://docs.cypress.io/__cypress/runner/cypress_runner.js:11327:23)
      at Promise.attempt.Promise.try (https://docs.cypress.io/__cypress/runner/cypress_runner.js:8601:29)
      at whenStable (https://docs.cypress.io/__cypress/runner/cypress_runner.js:153099:65)
      at <unknown> (https://docs.cypress.io/__cypress/runner/cypress_runner.js:152508:14)
      at tryCatcher (https://docs.cypress.io/__cypress/runner/cypress_runner.js:11327:23)
      at Promise._settlePromiseFromHandler (https://docs.cypress.io/__cypress/runner/cypress_runner.js:9262:31)
      at Promise._settlePromise (https://docs.cypress.io/__cypress/runner/cypress_runner.js:9319:18)
      at Promise._settlePromise0 (https://docs.cypress.io/__cypress/runner/cypress_runner.js:9364:10)
      at Promise._settlePromises (https://docs.cypress.io/__cypress/runner/cypress_runner.js:9444:18)
      at Promise._fulfill (https://docs.cypress.io/__cypress/runner/cypress_runner.js:9388:18)
      at <unknown> (https://docs.cypress.io/__cypress/runner/cypress_runner.js:11002:46)
  From Your Spec Code:
      at Context.eval (webpack:///./cypress/e2e/spec.cy.js:35:7)

  2) page
       doesnt work with a RegExp literal with a template literal in object arg:
     CypressError: Timed out retrying after 5000ms: `cy.wait()` timed out waiting `5000ms` for the 1st request to the route: `regex-literal-with-template-literal-in-obj`. No request ever occurred.

https://on.cypress.io/wait
      at cypressErr (https://docs.cypress.io/__cypress/runner/cypress_runner.js:161339:18)
      at Object.errByPath (https://docs.cypress.io/__cypress/runner/cypress_runner.js:161408:10)
      at checkForXhr (https://docs.cypress.io/__cypress/runner/cypress_runner.js:146476:92)
      at <unknown> (https://docs.cypress.io/__cypress/runner/cypress_runner.js:146499:28)
      at tryCatcher (https://docs.cypress.io/__cypress/runner/cypress_runner.js:11327:23)
      at Promise.attempt.Promise.try (https://docs.cypress.io/__cypress/runner/cypress_runner.js:8601:29)
      at whenStable (https://docs.cypress.io/__cypress/runner/cypress_runner.js:153099:65)
      at <unknown> (https://docs.cypress.io/__cypress/runner/cypress_runner.js:152508:14)
      at tryCatcher (https://docs.cypress.io/__cypress/runner/cypress_runner.js:11327:23)
      at Promise._settlePromiseFromHandler (https://docs.cypress.io/__cypress/runner/cypress_runner.js:9262:31)
      at Promise._settlePromise (https://docs.cypress.io/__cypress/runner/cypress_runner.js:9319:18)
      at Promise._settlePromise0 (https://docs.cypress.io/__cypress/runner/cypress_runner.js:9364:10)
      at Promise._settlePromises (https://docs.cypress.io/__cypress/runner/cypress_runner.js:9444:18)
      at Promise._fulfill (https://docs.cypress.io/__cypress/runner/cypress_runner.js:9388:18)
      at <unknown> (https://docs.cypress.io/__cypress/runner/cypress_runner.js:11002:46)
  From Your Spec Code:
      at Context.eval (webpack:///./cypress/e2e/spec.cy.js:46:7)


### Other

_No response_
ZachJW34 commented 1 year ago

The documentation for matching a route shows that the argument can either be a string (with glob matching support) or a regex expression. You are passing in a string and expecting it to be converted into a regex for you which we do not support (there is no straightforward way to determine if the string you passed is a regex or just a plain ol' string).

We could possibly change the UI of the route matcher to make a visual distinction between a string and regex (color, quotes around the string etc...) as this would have helped you debug your issue faster. I can get this routed to our feature request list for consideration.

ZachJW34 commented 1 year ago

Going to close this issue, if you think the UI enhancement would be beneficial please leave a comment and I can get this officially routed to the feature list.

JJ-Kamminga commented 1 year ago

Oops, think I missed the notification for your previous reply. Apologies!

I suppose it is in the documentation indeed, but your explanation helps a lot to explain why.

For me, the visual change you suggest would indeed be beneficial. But I cannot say of course for how many people this is the case and if that is worth the effort.