cypressregex-lookaroundscypress-intercept

cypress intercept to catch everything except baseUrl calls


I have a single page application running in http://localhost:3001 and I have set the baseUrl as such.

Now, I would like to intercept all the external calls, so the ones going elsewhere than localhost:3001. How do I write this kind of single intercept in Cypress? Or am I doing this somehow "wrong" way around, design-wise?

I have tried following intercepts, but they all result in intercepting the http://localhost:3001/_nuxt files etc.

    cy.intercept("**!(localhost:3001)*", (req) => {
    cy.intercept("**!(localhost:3001)**", (req) => {
    cy.intercept(/^((?!http:\/\/localhost:3001).+)$/, (req) => {
    cy.intercept({ url: /^((?!.*localhost:3001).+)$/ }, (req) => {

The wacky part is that, the regex /^((?!.*localhost:3001).+)$/ is correct. It does not match the localhost files.

/^((?!.*localhost:3001).+)$/.exec("http://localhost:3001/_nuxt/components/Component.vue") => null

as it should be, and then

/^((?!.*localhost:3001).+)$/.exec("https://www.example.com")
(2) ['https://www.example.com', 'https://www.example.com', index: 0, input: 'https://www.example.com', groups: undefined]

So, is Cypress intercept doing something more than just a plain regex exec or am I missing something obvious out here?


Solution

  • You can use a partial path

    cy.intercept({url: /^((?!.*\/_nuxt).+)$/}, (req) => {
    

    or add the above negative lookahead to your existing regex

    cy.intercept({url: /^(?!.*localhost:3001.*)(?!.*\/_nuxt).+$/})
    

    As noted by @D.Nykl - it's better to intercept based on path rather than host & port, as these can change depending on where the page is served from.


    Explanation

    The bug is at this place in the Cypress code _doesRouteMatch.

    When you provide a url it also attempts to match against the path portion of the URL the app uses.

    Cypress source code abbreviated to show the relevant lines

    export function _doesRouteMatch (routeMatcher: RouteMatcherOptions, req: CypressIncomingRequest) {
    
      const matchable = _getMatchableForRequest(req)
     
      ...
    
      // for convenience, attempt to match `url` against `path`?    
      const shouldTryMatchingPath = field === 'url'
    
      ...
    
      if (matcher.test) {
        if (!matcher.test(value) && 
           (!shouldTryMatchingPath || !matcher.test(matchable.path))) {
                                   // ^ failing here
           return false
         }
         continue
       }
    

    The matchable resolved from http://localhost:3001/_nuxt/components/Component.vue in the first line is:

    Matchable object (partial) produced by _getMatchableForRequest(req)

    matchable: {
      url: 'http://localhost:3001/_nuxt/components/Component.vue',
      path: '/_nuxt/components/Component.vue',
    }
    

    So it also tries this match on the path

    /^((?!.*localhost:3001).+)$/.test('/_nuxt/components/Component.vue')
    

    but of course that fails, and _doesRouteMatch does not return false as you would expect it to.

    By including part of the path in the cy.intercept() regex you can avoid the bug.