Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save okunokentaro/2b7e958e8369361b99f906af4838aaff to your computer and use it in GitHub Desktop.
Save okunokentaro/2b7e958e8369361b99f906af4838aaff to your computer and use it in GitHub Desktop.
Angular v8とjest-preset-angularの相性が悪いので解決策をまとめた
2019/05/15 にQiitaに投稿した記事のアーカイブです
---
(190829追記)
久々に試してみたら[`jest-preset-angular v7.1.1`](https://github.com/thymikee/jest-preset-angular/releases/tag/v7.1.1)以降にて解決を感じました。このバージョン以降ならば`jest@24.x`と組み合わせても大丈夫そうです。
---
こんにちは、 @okunokentaro です。タイトルでなんの事を指しているのか分かる人向けに書いているので、 `jest-preset-angular`の詳細解説は割愛します。
- https://github.com/thymikee/jest-preset-angular
Angular v8 rc段階にて判明した問題と、そのworkaroundをまとめています。将来的に`jest-preset-angular`や`jest`自体のアップデートが入れば、この記事が不要になる可能性は大いにあります。
# 2019/5/15時点で何が起きているか
Angular v7まででjestを併用したければ`jest-preset-angular`を使うのが常でした。`jest-preset-angular@7.0.x`は`jest@24`系に乗ったことで、`transform`, `stringifyContentPathRegex`などの各種オプションの解釈が変わっている認識です。しかし、このままだとAngularテンプレート`html`、スタイル`scss`等の読み込みにて、jest実行時にエラーを起こします。
```
Error: connect ECONNREFUSED 127.0.0.1:80
at Object.dispatchError (/path/to/node_modules/jest-environment-jsdom-thirteen/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:60:19)
at Request.client.on.err (/path/to/node_modules/jest-environment-jsdom-thirteen/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:674:20)
at Request.emit (events.js:194:15)
at Request.onRequestError (/path/to/node_modules/request/request.js:881:8)
at ClientRequest.emit (events.js:189:13)
at Socket.socketErrorListener (_http_client.js:392:9)
at Socket.emit (events.js:189:13)
at emitErrorNT (internal/streams/destroy.js:82:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
at process._tickCallback (internal/process/next_tick.js:63:19) undefined
```
この問題の解決法は根気よくたどればあるのでしょうが、現状は`jest-preset-angular@6.0.2`を使うというworkaroundに落ち着いている方が多いと思います。
# jest-preset-angular@6.0.2の寿命が来た
Angular v8になるとこのworkaroundに問題が起きます。
Angular CLI v8では新規プロジェクト作成時に`core-js`がインストールされないようになりました。実際、v7初期まではインストールされていた`core-js`は、Angular CLI v7.x以降省かれるようになっています。モダンブラウザの多くがpolyfillを必要しなくなったため容量の削減が目的と推測されます。
`jest-preset-angular`は、特に`v6.0.2`に関してはこのpolyfillを必須として`peerDependencies`に組み入れています。そのため、Angular CLI v8にて作成したプロジェクトにて`jest-preset-angular@6.0.2`を併用すると、module不足としてテストの実行ができません。
さらなるworkaroundとして`core-js`をインストールすることも考えられますが、将来的なことを考えると、`jest-preset-angular@7.0.x`で起こっているテンプレートの読み込みに失敗する問題を解決させたほうがよさそうです。
`jest-preset-angular@7.0.x`にて起こっている問題の解決法は~~現在分かっておりません。~~下記参照。
# 問題の本質
切り分けの結果、`jest-preset-angular@7.0.x`自体が悪なのではなく、`jest@23.x`が`jest@24.x`になったことで問題になっているというところまでは掴めました。これは`jest@24.x`が依存している`jsdom`が`scss`を読めないことに起因しています。その証拠に上記エラーは`Object.dispatchError (jsdom/lib/jsdom/living/xhr-utils.js:60:19)`が発していますし、scssをやめてcssに変更したら`jest-preset-angular@7.0.x`上でオールグリーンとなりました。
# 解決法
これもworkaroundの一種ですが、比較的実行しやすい手段を見つけたのでお知らせします。
```
npm i -D jest@24.8.0 jest-preset-angular@7.1.0 identity-obj-proxy
```
インストール物は以上です。バージョンは執筆日2019/5/15時点のものなので、閲覧日と離れてる場合はアテにしてはいけません。
インストールしたら`jest-preset-angular`のために用意しているであろう`jest.config.js`に書き加えます。`moduleNameMapper`, `identity-obj-proxy`の箇所が増えています。
```jest.config.js
module.exports = {
preset: 'jest-preset-angular',
setupFilesAfterEnv: ['<rootDir>/src/setup-jest.ts'],
testPathIgnorePatterns: ['<rootDir>/src/test.ts'],
transform: {
'^.+\\.(ts|js|html)$': 'ts-jest',
},
moduleNameMapper: {
'\\.(css|scss)$': 'identity-obj-proxy',
},
globals: {
'ts-jest': {
tsConfig: 'tsconfig.test.json',
stringifyContentPathRegex: '\\.html$',
},
},
};
```
`identity-obj-proxy`はファイルの依存解決時に指定の拡張子をなにがしかのオブジェクトとして扱ってくれるライブラリのようです。深追いはしてないです。([本家](https://github.com/keyz/identity-obj-proxy)と[Qiita記事](https://qiita.com/chimame/items/f4d3d71d8156d97a839a)をざっと眺めた理解)
これによって、scssのファイル解決が失敗し`connect ECONNREFUSED`となる問題を解決できます。
なお、このworkaroundはNrwl/Nxの[Jestプラグイン](https://github.com/nrwl/nx/blob/master/packages/jest/plugins/resolver.ts#L49)実装より着想を得ました。(thx! 情報提供 @lacolaco )
そこまで筋の悪い解決法ではない気がするので、しばらく様子見つつAngular v8, Jest v24, jest-preset-angular構成で進めたい方はこの方法を試してみるとよいと思います。`jest-preset-angular`側には`core-js`が不要であるためpeerから除去してほしい[話](https://github.com/thymikee/jest-preset-angular/issues/266)と、`identity-obj-proxy`がないと`scss`で失敗する[旨](https://github.com/thymikee/jest-preset-angular/issues/267)を報告しま~~す~~した。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment