Cypress: Cannot read property "fireChangeEvent" of undefined when stubbing with route2 in Chrome

Created on 11 Nov 2020  路  12Comments  路  Source: cypress-io/cypress

Current behavior

I am stubbing many (all) server calls for testing our web-app without the real server. As the server is not reachable, I also have to stub OPTIONS-method http calls.

My code looks something like this:

const preflightHeaders = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Expose-Headers': '*',
    'access-control-allow-headers': '*',
    'Access-Control-Request-Headers': '*',
    'Access-Control-Request-Method': '*',
    'Access-Control-Allow-Methods': '*'
};


cy.route2({ url: this._urlMatch }, (req) => {

  if (req.method.toUpperCase() === 'OPTIONS') {
    req.reply(200, undefined, preflightHeaders);
    return;
  }

  // [...Actual stubs here]
}

In many cases this works without any problem. With one specific test, I get this error:
Cypress tells me that this error originates from my test code and not from cypress itself. If that is true, I am very sorry for opening this issue. But in this case, I think this might be a bug in the experimental full network stubbing feature, especially since this problem only occurs in Chromium!

TypeError: The following error originated from your test code, not from Cypress.

  > Cannot read property 'fireChangeEvent' of undefined

When Cypress detects uncaught errors originating from your test code it will automatically fail the current test.
    at sendContinueFrame (http://localhost:4200/__cypress/runner/cypress_runner.js:164493:17)
    at onRequestReceived (http://localhost:4200/__cypress/runner/cypress_runner.js:164497:12)
    at http://localhost:4200/__cypress/runner/cypress_runner.js:164283:14
From previous event:
    at $Cypress.<anonymous> (http://localhost:4200/__cypress/runner/cypress_runner.js:164281:56)
    at $Cypress.../driver/node_modules/eventemitter2/lib/eventemitter2.js.EventEmitter.emit (http://localhost:4200/__cypress/runner/cypress_runner.js:85136:19)
    at $Cypress.parent.<computed> [as emit] (http://localhost:4200/__cypress/runner/cypress_runner.js:172903:33)
    at Socket.<anonymous> (http://localhost:4200/__cypress/runner/cypress_runner.js:199515:17)
    at Socket.../socket/node_modules/component-emitter/index.js.Emitter.emit (http://localhost:4200/__cypress/runner/cypress_runner.js:187266:20)
    at Socket.../socket/node_modules/socket.io-client/lib/socket.js.Socket.onevent (http://localhost:4200/__cypress/runner/cypress_runner.js:193994:10)
    at Socket.../socket/node_modules/socket.io-client/lib/socket.js.Socket.onpacket (http://localhost:4200/__cypress/runner/cypress_runner.js:193952:12)
    at Manager.<anonymous> (http://localhost:4200/__cypress/runner/cypress_runner.js:187124:15)
    at Manager.../socket/node_modules/component-emitter/index.js.Emitter.emit (http://localhost:4200/__cypress/runner/cypress_runner.js:187266:20)
    at Manager.../socket/node_modules/socket.io-client/lib/manager.js.Manager.ondecoded (http://localhost:4200/__cypress/runner/cypress_runner.js:193450:8)
    at Decoder.<anonymous> (http://localhost:4200/__cypress/runner/cypress_runner.js:187124:15)
    at Decoder.../socket/node_modules/component-emitter/index.js.Emitter.emit (http://localhost:4200/__cypress/runner/cypress_runner.js:187266:20)
    at Decoder.../socket/node_modules/socket.io-circular-parser/index.js.Decoder.add (http://localhost:4200/__cypress/runner/cypress_runner.js:192098:12)
    at Manager.../socket/node_modules/socket.io-client/lib/manager.js.Manager.ondata (http://localhost:4200/__cypress/runner/cypress_runner.js:193440:16)
    at Socket.<anonymous> (http://localhost:4200/__cypress/runner/cypress_runner.js:187124:15)
    at Socket.../socket/node_modules/engine.io-client/node_modules/component-emitter/index.js.Emitter.emit (http://localhost:4200/__cypress/runner/cypress_runner.js:189743:20)
    at Socket.../socket/node_modules/engine.io-client/lib/socket.js.Socket.onPacket (http://localhost:4200/__cypress/runner/cypress_runner.js:187810:14)
    at WS.<anonymous> (http://localhost:4200/__cypress/runner/cypress_runner.js:187627:10)
    at WS.../socket/node_modules/engine.io-client/node_modules/component-emitter/index.js.Emitter.emit (http://localhost:4200/__cypress/runner/cypress_runner.js:189743:20)
    at WS.../socket/node_modules/engine.io-client/lib/transport.js.Transport.onPacket (http://localhost:4200/__cypress/runner/cypress_runner.js:188253:8)
logError @ cypress_runner.js:199876
(anonymous) @ cypress_runner.js:199531
emit @ cypress_runner.js:51548
(anonymous) @ cypress_runner.js:184636
emit @ cypress_runner.js:51548
emit @ cypress_runner.js:184676
onPrint @ cypress_runner.js:183587
_onPrintClick @ cypress_runner.js:183592
(anonymous) @ cypress_runner.js:184847
executeAction @ cypress_runner.js:49413
n @ cypress_runner.js:49413
ca @ cypress_runner.js:59945
ja @ cypress_runner.js:59946
ka @ cypress_runner.js:59946
wa @ cypress_runner.js:59948
Aa @ cypress_runner.js:59949
ya @ cypress_runner.js:59949
Da @ cypress_runner.js:59952
Ad @ cypress_runner.js:60015
Gi @ cypress_runner.js:60181
Kb @ cypress_runner.js:59970
Dd @ cypress_runner.js:60017
(anonymous) @ cypress_runner.js:60182
../../node_modules/scheduler/cjs/scheduler.production.min.js.exports.unstable_runWithPriority @ cypress_runner.js:64056
Ii @ cypress_runner.js:60182
Cd @ cypress_runner.js:60016

The error is thrown in this code excerpt in the cypress_runner.js:

  const sendContinueFrame = () => {
    if (continueSent) {
      throw new Error('sendContinueFrame called twice in handler');
    }

    continueSent = true;

    if (request) {
      request.state = 'Intercepted';
    }

    if (continueFrame) {
      // copy changeable attributes of userReq to req in frame
      // @ts-ignore
      continueFrame.req = { ...lodash__WEBPACK_IMPORTED_MODULE_0___default.a.pick(userReq, _types__WEBPACK_IMPORTED_MODULE_1__[/* SERIALIZABLE_REQ_PROPS */ "a"])
      };

      lodash__WEBPACK_IMPORTED_MODULE_0___default.a.merge(request.request, continueFrame.req);

      emitNetEvent('http:request:continue', continueFrame);
    }

    request.log.fireChangeEvent(); // <--- Error here
  };

Any idea why "log" is missing in some cases?

Desired behavior

No exception when (an OPTIONS) http call is intercepted.

Test code to reproduce

Sadly, I cannot share the project that this error occurred in, I might be able to reproduce this in a fresh repo, if required I will add that later.

Versions


Found in:
Cypress 5.6.0
Chrome 86 & Edge Dev 88
Windows 10

Works in Firefox 80

chromium internal-priority pknet-stubbing needs information bug

Most helpful comment

I have had the exact same problem with route2 in 5.6.0 and with intercept in 6.0.0
It seems to happen when I'm stubbing all requests, but am not waiting for them to complete before moving on to the next test
As an example, I am testing the login sequence, and don't care to wait for the requests on the next page to complete
If I use route, this is not a problem
If I use intercept/route2, it throws this error, sometimes
If I put a delay at the end of my tests, there is no error
This is what's keeping me using route at the moment, even if it requires more work on our end to maintain

All 12 comments

Interestingly enough this error does not occur every time!
I ran all of my 25 Tests 15 times now in Chrome. 13 times one test fails with the described error (always the same test) and 2 times everything succeeded without errors. Not that all 25 tests have the stub configured the same (all call the method with cy.route2 and the OPTIONS response etc.)
In Firefox I get a different error instead:

cy.click() failed because it requires a DOM element.

The subject received was:

  > undefined

The previous command that ran was:

  > cy.get()

Then with the automatic retry, it works again.
I am very confused about what causes those issues.

This error is being thrown from here: https://github.com/cypress-io/cypress/blob/develop/packages/driver/src/cy/net-stubbing/events/request-received.ts#L145:L145

Since this error is intermittent, it will be harder to track down. A reproducible example would be ideal to help us.

I know a repro repo would be nice, since this is one of those "sometimes" bugs it's very hard to reproduce in an isolated shareable use case. Whenever I have some spare time I will try to create a similar test case. But again, I call the exact same helper method in all tests and only for one specific test it sometimes fails on the first try (and only the first try). So reproducing that is really not easy I think...

a can reproduce this bug when i'm logging in to my app with different users via cypress and then waiting for same route2 aliases, then couple times stop test and begin again

Hi @IgorPahota
Thanks for the comment. Your app isn't open source or publicly available by any chance, is it? Would be great to have a reproduction app for the cypress team. Sadly I cannot share the one that I found the issue in as it belongs to the company I work at...

I have had the exact same problem with route2 in 5.6.0 and with intercept in 6.0.0
It seems to happen when I'm stubbing all requests, but am not waiting for them to complete before moving on to the next test
As an example, I am testing the login sequence, and don't care to wait for the requests on the next page to complete
If I use route, this is not a problem
If I use intercept/route2, it throws this error, sometimes
If I put a delay at the end of my tests, there is no error
This is what's keeping me using route at the moment, even if it requires more work on our end to maintain

That's a really good catch @fearhq!

This would also explain why the test always succeeds on the second try! My guess would be that the test breaks if a request of a preceding test hasn't terminated.

same issue here. waiting for some shiny fixes ;)

I wanted to add that this is not the only error I get with intercept
I notice that some queries can wind up hitting the real server at the end of my test.
Furthermore, even if there is no 'fireChangeEvent' error, it may screw up the intercepts of the next test

@fearhq I have similar issues (see #9362) and for me I got the test to reliably pass by clearing cookies after each test. I wonder if you might try that as well:

afterEach(() => {
  cy.clearCookies()
})

I am also seeing this same intermittent error since switching from route to intercept.

@MartijnHols Thank you for that suggestion. clearing the cookies so far seems to be working for me. I haven't had a failure since.

Was this page helpful?
0 / 5 - 0 ratings