angular / angular/angular-cli

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

Open
#17,547 0 comments 0 reactions 0 assignees View on GitHub
area: @angular-devkit/build-angular devkit/build-angular:karma help wanted
Dominant language
TypeScript
Stars
27k
Forks
11.8k
Avg merge
14h 23m
Merged PRs (30d)
162

Description

# 🐞 Bug report

### Command (mark with an `x`)

- [ ] new
- [ ] build
- [ ] serve
- [X] 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:

```js
const dom = new JSDOM(`

Hello

`, {
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:

```js
// 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](https://github.com/badeball/karma-jsdom-launcher/blob/3c364d8988a7a1bc8d4687ec76810cb530adfffe/index.js#L28-L40) 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

1.
```sh
$ ng new foo
$ cd foo
$ npm install karma-jsdom-launcher jsdom
```
2. Configure `angular.json` file as @badeball indicates [here ](https://github.com/badeball/karma-jsdom-launcher#i-am-using-angular-cli-and-the-test-suite-hangs-indefinitely) due to #11561 and #13580
3. Configure `karma.config.js` file as `karma-jsdom-launcher` docs indicates:
```js
// karma.config.js
...
plugins: [
....
require('karma-jsdom-launcher'),
....
],
...
browsers: ['jsdom'],
jsdomLauncher: {
jsdom: {
beforeParse(window) {
window.someCoolAPI = () => { /* ... */ };
}
}
},
...
```
4. 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
}
}
```
5.
```sh
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

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the failure with the documented angular.json and karma.config.js setup, then run ng test using karma-jsdom-launcher and the beforeParse shim. Trace how the jsdom environment reaches the test context; done means custom shims such as someCoolAPI or crypto are available during tests without breaking the existing launcher setup.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
cli, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.