Skip to content
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

Karma hangs with jsdom #27

Open
fluky opened this issue Jan 28, 2019 · 8 comments
Open

Karma hangs with jsdom #27

fluky opened this issue Jan 28, 2019 · 8 comments

Comments

@fluky
Copy link

fluky commented Jan 28, 2019

I'm trying to add jsdom to an Angular CLI project and when I switch the browser to jsdom it just hangs indefinitely after building.

Steps to reproduce:

  1. generate a new Angular cli project "ng new testJsdom"
    Note: using Angular Cli version 7.1.4
  2. add karma-jsdom-launcher and jsdom
    43 "jsdom": "~13.2.0",
    44 "karma-jsdom-launcher": "~7.0.0",
  3. set browser to jsdom in src/karma.conf.js
  4. ng test

At this point the project will compile and then go to a blank screen where it sits until killed with Ctrl+C.

@badeball
Copy link
Owner

This is an interesting one. So, what's happening here is that something in your bundle attempts to perform a synchronous XHR. jsdom implements this by using child_process.spawnSync. This will spawn a node process running xhr-sync-worker.js, which in turn will request the subject.

This request is usually handled by Karma's server. In this case however, Node is blocking in spawnSync and won't respond to the request. In other words, there's a deadlock going on here.

There's unfortunately not much for karma-jsdom-launcher to do here. An option would be for it to spawn its own process. This would however prohibit users of passing all possible options to jsdom, as they would have to be serialized somehow. In a proper language one would simply fork (syscall), but we don't have the luxury of that in Node.

I don't have time to dig further into Angular og Webpack for you, but if you can find a way for it to not perform synchronous XHR, then this will hopefully work.

@badeball
Copy link
Owner

Leaving it open for a while, any tips as to how make Webpack cooperate are welcome.

@badeball badeball reopened this Jan 28, 2019
@badeball
Copy link
Owner

badeball commented Jan 30, 2019

I couldn't let this one go and did some more digging. It turns out that the synchronous requests are made by source-map-support.

There's an issue in angular-cli that prevents me from disabling it, which I've tried to outline below.

  1. Even though I specify "sourceMap": false in angular.json

  2. Config is normalized

  3. sourceMap option is further normalized

  4. Normalization of sourceMap always ends up with an object

  5. source-map-support is conditionally included, but the condition is always true

I suspect that angular/angular-cli#13062 introduced this behavior.

The good news is that source-map-support will ignore any errors thrown by XMLHttpRequest. Hence, as a temporary measure, you can apply the following patch to unclog your setup.

--- node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js
+++ node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js
@@ -425,6 +425,9 @@
     }
 
     open(method, uri, asynchronous, user, password) {
+      if (typeof asynchronous !== "undefined" && !asynchronous) {
+        throw new Error("Synchronous request prohibited.");
+      }
       if (!this._ownerDocument) {
         throw new DOMException("The object is in an invalid state.", "InvalidStateError");
       }

Sidenote: Having a proper way of patching 3rd party libraries is convenient when you can't be bothered to submit a patch yourself, either because you can't wait for it or because your request is too obscure. I've never been on a real project without ever having needed this. One approach I've found to work is having a postinstall script in package.json and a directory containing patches as that shown above.

// package.json
  "scripts": {
    "postinstall": "patches/apply.sh"
  }

// patches/apply.sh
#!/usr/bin/env bash

for f in patches/*.patch
do
  patch --reverse --dry-run --force --strip 0 < $f &>/dev/null

  if [ $? -ne 0 ]; then
    patch --forward --force --strip 0 < $f
  fi
done

// patches/01-jsdom-prohibit-synchronous-requests.patch
--- node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js
+++ node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js
@@ -425,6 +425,9 @@
     }
 
     open(method, uri, asynchronous, user, password) {
+      if (typeof asynchronous !== "undefined" && !asynchronous) {
+        throw new Error("Synchronous request prohibited.");
+      }
       if (!this._ownerDocument) {
         throw new DOMException("The object is in an invalid state.", "InvalidStateError");
       }

@fluky
Copy link
Author

fluky commented Jan 30, 2019

Brilliant! Thanks for the help. Glad you couldn't let it go 😄 .

As a suggestion you may want to add this to your README.md given the popularity of the platform.

@filipesilva
Copy link

@badeball regarding the patching of libs, just wanted to mention that https://github.com/ds300/patch-package helps with that problem as well. Exactly same concept though. It just sorta manages the patches and is cross platform.

@badeball
Copy link
Owner

badeball commented Feb 22, 2019

I've tried creating a fresh Angular project and configured "sourceMap": false in angular.json (in the test part). It now seems to run fine. @fluky, can you update your dependencies and confirm that it now works?

Edit: To specify further - it seems like the fix was published with v7.3.1, as shown by git tag --contains acc31ba.

@badeball
Copy link
Owner

I will furthermore see if I can warn users of synchronous requests to the Karma server, as it will never really work.

@tommyc38
Copy link

tommyc38 commented Mar 22, 2022

I was having issues with coverage reports with source maps set to false in an angular repo. Thanks @badeball for your workaround. I also had to increase NODE_OPTIONS=--max-old-space-size=8192 but it all works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants