-
Notifications
You must be signed in to change notification settings - Fork 24.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
aio: DISCONNECTED errors with Chrome + Karma + jasmine #17543
Comments
This should be fixed by jasmine/jasmine@c60d669. Closing, since this is not actionable on the Angular side anyway. |
gkalpak
referenced
this issue
in jasmine/jasmine
Jun 18, 2017
- Allows the CPU to run other things that used the real `setTimeout` - Fixes #1327 - See #1334 - Fixes jasmine/gulp-jasmine-browser#48
gkalpak
added a commit
to gkalpak/angular
that referenced
this issue
Jun 18, 2017
This version fixes the DISCONNECTED errors (described in angular#17543) and removes the need to the workaround (8af203c). The relevant jasmine commit is jasmine/jasmine@c60d66994.
gkalpak
added a commit
to gkalpak/angular
that referenced
this issue
Jun 19, 2017
This version fixes the DISCONNECTED errors (described in angular#17543) and removes the need to the workaround (8af203c). The relevant jasmine commit is jasmine/jasmine@c60d66994.
hansl
pushed a commit
that referenced
this issue
Jun 19, 2017
This version fixes the DISCONNECTED errors (described in #17543) and removes the need to the workaround (8af203c). The relevant jasmine commit is jasmine/jasmine@c60d66994.
hansl
pushed a commit
that referenced
this issue
Jun 19, 2017
This version fixes the DISCONNECTED errors (described in #17543) and removes the need to the workaround (8af203c). The relevant jasmine commit is jasmine/jasmine@c60d66994.
asnowwolf
pushed a commit
to asnowwolf/angular
that referenced
this issue
Aug 11, 2017
This version fixes the DISCONNECTED errors (described in angular#17543) and removes the need to the workaround (8af203c). The relevant jasmine commit is jasmine/jasmine@c60d66994.
juleskremer
pushed a commit
to juleskremer/angular
that referenced
this issue
Aug 28, 2017
This version fixes the DISCONNECTED errors (described in angular#17543) and removes the need to the workaround (8af203c). The relevant jasmine commit is jasmine/jasmine@c60d66994.
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Since upgrading to Chrome 59 on Travis, we started seeing unit test failures due to Chrome getting disconnected from Karma. We have worked around the issue with a39bf8b and 8af203c (which cause a slight slow-down).
(For reference, we are currently using Karma v1.7.0 and jasmine v2.6.3.)
I looked into it a bit more (since this is likely to affect many people given that our setup (jasmine+Karma+Chrome) is common) and here is what I believe is happening:
The Karma server uses socket.io to (among other things) get updates from the browser about the test results. Whenever the browser reports a test result, it refreshes the
noActivityTimer
, but if it doesn't hear from the browser for 10s it considers it disconnected.For whatever reason, socket.io uses it's XHR-based polling implementation instead of
WebSocket
(but the problem would arise withWebSocket
too). When the socket wants to emit a result, it will (after some hoops) call itsflush()
method, which will send the message, unless itsTransport
(i.e. the polling thingy) is currently not writable.So, what causes the
Transport
to not be writable?transport.send()
callstransport.write()
transport.write()
setstransport.writable = false
, creates a callback for setting it back totrue
, and passes the callback totransport.doWrite()
.Note: Until the callback is called,
transport.writable
will befalse
and the socket won't send anything to the Karma server.transport.doWrite()
calls [transport.request()][17] (which essentially [creates][18] and [sends][19] an
XMLHttpRequest) and binds the callback to the request's
successevent (long story short to the XHR's [
.onreadystatechangehandler][20] (for
readyState === 4`)).What this all means is that once the socket sends a message to the server, it has to wait for the XHR to complete before sending another message.
In the meantime, in Jasmine-land:
Jasmine is running the tests using its
QueueRunner
. Once it is gone through the whole queue (synchronously in our case), it will call itsclearStack()
method (and then continue running tests). TheclearStack()
method is what is passed to theQueueRunner
, which (in a nutshell) is based onMessageChannel
.Let's tie everything together :)
Jasmine runs some tests. Clears the stack. The socket sends a message to inform the Karma server about the test result. Jasmine runs more tests. Etc.
Now, if everything ran synchronously, the
readystatechange
event listener for the polling socket doesn't get a chance to fire and setTransport.writable
totrue
, in order to allow more messages to be sent to the Karma server. Our tests do run synchronously, but what about theclearStack()
method? It is not, but...It turns out that
MessageChannel.postMessage()
uses a task queue that gets processed before the one XHR events use. As a result, Jasmine will keep running tests and clearing the stack and running more tests, before the first XHR has a chance to complete. Thus, the socket'sTransport
will be non-writable all the time and Karma will not receive any updates from the browser.Why didn't it fail before?
It seems that there were some changes in Chrome 58 or 59 wrt
.postMessage()
(these two seem related, but are also kind of old 😕 : 04055dd, 05a1330). I.e. previously it would use the Timer queue (whatsetTimeout
uses), while now it uses a different queue that is processed before the Timer queue. Consider the following example:The output on Chrome 57 is different than on Chrome 59:
Chrome 57:
Chrome 59:
Why does
beforeEach(done => done())
work?By having an argument, the callback takes the async path. But because
done()
is called synchronously, it will be called beforecompletedAsynchronously
is set tofalse
, which will in turn run the rest of the queued callbacks in asetTimeout()
, giving the XHR time to complete.The text was updated successfully, but these errors were encountered: