Skip to content

Karma with jsdom+custom shims/polyfills should create the right environment for the tests #17547

Open
@emartinpi

Description

@emartinpi

🐞 Bug report

Command (mark with an x)

  • new
  • build
  • serve
  • test
  • e2e
  • generate
  • add
  • update
  • lint
  • xi18n
  • run
  • config
  • help
  • version
  • doc

Is this a regression?

No, the previous mayor version (8.x.x) the issue was present as well.

Description

We are using `jsdom` as the target browser for unit testing in our Angular library. Our library uses the `crypto` API which is not implemented in `jsdom`, so we need a shim for this API. We did it as it's indicated in its docs:
const dom = new JSDOM(`<p>Hello</p>`, {
  beforeParse(window) {
    window.document.childNodes.length === 0;
    window.someCoolAPI = () => { /* ... */ };
  }
});

Luckely the karma-json-launcher offers the posibility to configure the jsdom instance throught karma.conf.js file:

// karma.conf.js
const jsdom = require("jsdom");
 
module.exports = function(config) {
  config.set({
    browsers: ['jsdom'],
    jsdomLauncher: {
      jsdom: {
        beforeParse(window) {
          window.someCoolAPI = () => { /* ... */ };
        }
      }
    }
  });
};

The karma plugin creates the jsdom instance correctly with the passed options, and it tries to parse the url where karma is running. But unfortunalety the someCoolAPI is not present in test context inside window property and test fails with a ReferenceError: someCoolAPI is not defined

On the other hand, when you try to manually create your own jsdom instance (same way karma-json-launcher does), with someCoolAPI polyfill, and parse any html document which use that API inside it works, jsdom parses the document and the scripst are executed correctly, so that makes me think is not a jsdom or karma-jsdom-launcher problem. Can be an issue with the CLI, or Karma itself?

🔬 Minimal Reproduction

$ ng new foo
$ cd foo
$ npm install karma-jsdom-launcher jsdom
  1. Configure angular.json file as @badeball indicates here due to karma jsdom launcher hangs #11561 and Inability to avoid including source-map-support in Karma tests #13580
  2. Configure karma.config.js file as karma-jsdom-launcher docs indicates:
// karma.config.js
...
plugins: [
  ....
  require('karma-jsdom-launcher'),
  ....
],
...
browsers: ['jsdom'],
jsdomLauncher: {
  jsdom: {
    beforeParse(window) {
        window.someCoolAPI = () => { /* ... */ };
     }
  }
},
...
  1. Create app.component.ts that uses that someCoolAPI in some way.
@Component({...})
export class AppComponent {
  constructor() {
    window.someCoolAPI();  //the test will fail here because someCoolAPI is not defined
  }
}
ng test

🔥 Exception or Error


> ng test
10% building 2/2 modules 0 active24 04 2020 23:56:59.854:WARN [karma]: No captured browser, open http://localhost:9877/
24 04 2020 23:56:59.871:INFO [karma-server]: Karma v4.4.1 server started at http://0.0.0.0:9877/
24 04 2020 23:56:59.873:INFO [launcher]: Launching browsers jsdom with concurrency unlimited
24 04 2020 23:56:59.911:INFO [launcher]: Starting browser jsdom
24 04 2020 23:57:12.239:WARN [karma]: No captured browser, open http://localhost:9877/
24 04 2020 23:57:12.552:INFO [Mozilla/5.0 (win32) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/16.2.2]: Connected on socket BdQYHk1WXZIxjHKdAAAA with id 85109278
Mozilla/5.0 (win32) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/16.2.2 AppComponent should create the app FAILED
        ReferenceError: crypto is not defined
            at 
            at new AppComponent (http://localhost:9877/_karma_webpack_/main.js:580:21)
            at NodeInjectorFactory.AppComponent_Factory [as factory] (ng:///AppComponent/ɵfac.js:5:10)
            at getNodeInjectable (http://localhost:9877/_karma_webpack_/vendor.js:41519:44)
            at instantiateRootComponent (http://localhost:9877/_karma_webpack_/vendor.js:47483:23)
            at createRootComponent (http://localhost:9877/_karma_webpack_/vendor.js:60827:23)
            at ComponentFactory$1.create (http://localhost:9877/_karma_webpack_/vendor.js:66890:25)
            at initComponent (http://localhost:9877/_karma_webpack_/vendor.js:82940:51)
            at ZoneDelegate.invoke (http://localhost:9877/_karma_webpack_/polyfills.js:3836:30)
            at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9877/_karma_webpack_/vendor.js:100670:43)
            at ZoneDelegate.invoke (http://localhost:9877/_karma_webpack_/polyfills.js:3835:36)
Mozilla/5.0 (win32) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/16.2.2: Executed 1 of 3 (1 FAILED) (0 secs / 0.294 secs)
Mozilla/5.0 (win32) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/16.2.2 AppComponent should create the app FAILED
        ReferenceError: crypto is not defined
            at 
            at new AppComponent (http://localhost:9877/_karma_webpack_/main.js:580:21)
            at NodeInjectorFactory.AppComponent_Factory [as factory] (ng:///AppComponent/ɵfac.js:5:10)
            at getNodeInjectable (http://localhost:9877/_karma_webpack_/vendor.js:41519:44)
            at instantiateRootComponent (http://localhost:9877/_karma_webpack_/vendor.js:47483:23)
            at createRootComponent (http://localhost:9877/_karma_webpack_/vendor.js:60827:23)
            at ComponentFactory$1.create (http://localhost:9877/_karma_webpack_/vendor.js:66890:25)
            at initComponent (http://localhost:9877/_karma_webpack_/vendor.js:82940:51)
            at ZoneDelegate.invoke (http://localhost:9877/_karma_webpack_/polyfills.js:3836:30)
            at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9877/_karma_webpack_/vendor.js:100670:43)

🌍 Your Environment


Angular CLI: 9.1.3
Node: 12.10.0
OS: win32 x64

Angular: 9.1.3
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.901.3
@angular-devkit/build-angular     0.901.3
@angular-devkit/build-optimizer   0.901.3
@angular-devkit/build-webpack     0.901.3
@angular-devkit/core              9.1.3
@angular-devkit/schematics        9.1.3
@ngtools/webpack                  9.1.3
@schematics/angular               9.1.3
@schematics/update                0.901.3
rxjs                              6.5.5
typescript                        3.8.3
webpack                           4.42.0

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions