概要
Angular7で、Jestを試しに導入したときのメモです。
サイトによっては、大体4コマンドだけ打てば動くみたいな書き方がしてあるが、
実際そうではないみたいで、試行錯誤で対処したものを参考にまとめる。
導入の仕方は2通りある。
- A. もう作ってある Karma環境を
@briebug/jest-schematic
で変換する - B. パッケージがないところから、環境を作る
A.のついでに、試して動いたので手順を一応メモを残す。
環境
- Angular CLI: 7.2.4
- Node: 11.13.0
- OS: win32 x64
- Angular: 7.2.15
- Jest
@angular-builders/jest@7.4.4
jest-preset-angular@8.0.0
jest@24.9.0
A. もう作ってあるKarma環境を変換する
npm install -g @briebug/jest-schematic
ng g @briebug/jest-schematic:add
ng add @briebug/jest-schematic
npm i -D @angular-builders/jest@7.4.4
A.1 package.json の編集
エラーになるみたいで astTransformers の部分を書き換える。
"jest": {
"preset": "jest-preset-angular",
"roots": [
"src"
],
"transform": {
"^.+\\.(ts|js|html)$": "ts-jest"
},
"setupFilesAfterEnv": [
"<rootDir>/src/setup-jest.ts"
],
"moduleNameMapper": {
"@app/(.*)": "<rootDir>/src/app/$1",
"@assets/(.*)": "<rootDir>/src/assets/$1",
"@core/(.*)": "<rootDir>/src/app/core/$1",
"@env": "<rootDir>/src/environments/environment",
"@src/(.*)": "<rootDir>/src/src/$1",
"@state/(.*)": "<rootDir>/src/app/state/$1"
},
"globals": {
"ts-jest": {
"tsConfig": "<rootDir>/src/tsconfig.spec.json",
"stringifyContentPathRegex": "\\.html$",
"astTransformers": [
"jest-preset-angular/build/InlineFilesTransformer",
"jest-preset-angular/build/StripStylesTransformer"
]
}
}
A.2 angular.json の編集
"test": {
- "builder": "@angular-devkit/build-angular:karma",
+ "builder": "@angular-builders/jest:run",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
A.3 src/jest.config.js の追加
snapshotSerializers の部分に注意。
module.exports = {
"transform": {
"^.+\\.(ts|js|html)$": "ts-jest",
"^.+\\.[t|j]sx?$": "babel-jest"
},
moduleFileExtensions: ['ts', 'html', 'js', 'json'],
moduleNameMapper: {
'^src/(.*)$': '<rootDir>/src/$1',
'^app/(.*)$': '<rootDir>/src/app/$1',
'^assets/(.*)$': '<rootDir>/src/assets/$1',
'^environments/(.*)$': '<rootDir>/src/environments/$1',
},
transformIgnorePatterns: ['node_modules/(?!@ngrx)'],
snapshotSerializers: [
'jest-preset-angular/build/AngularSnapshotSerializer.js',
'jest-preset-angular/build/HTMLCommentSerializer.js',
],
};
A.4 src/tsconfig.spec.json の編集
diff --git a/list-server-nohttp/src/tsconfig.spec.json b/list-server-nohttp/src/tsconfig.spec.json
index de77336..400bd63 100644
--- a/list-server-nohttp/src/tsconfig.spec.json
+++ b/list-server-nohttp/src/tsconfig.spec.json
@@ -3,8 +3,7 @@
"compilerOptions": {
"outDir": "../out-tsc/spec",
"types": [
- "jasmine",
- "node"
+ "jest"
]
},
B. パッケージがないところから環境を作る
B.1 package.json の編集
package.json を A で実績のあるものを参考に取り込む。
diff package.json
diff --git a/list-server-nohttp/package.json b/list-server-nohttp/package.json
index 1fbf179..e9b1bfd 100644
--- a/list-server-nohttp/package.json
+++ b/list-server-nohttp/package.json
@@ -5,9 +5,10 @@
"ng": "ng",
"start": "ng serve",
"build": "ng build",
- "test": "ng test",
+ "test": "jest",
"lint": "ng lint",
- "e2e": "ng e2e"
+ "e2e": "ng e2e",
+ "test:watch": "jest --watch"
},
"private": true,
"dependencies": {
@@ -19,12 +20,14 @@
"@angular/platform-browser": "~7.2.0",
"@angular/platform-browser-dynamic": "~7.2.0",
"@angular/router": "~7.2.0",
+ "@briebug/jest-schematic": "^2.1.0",
"core-js": "^2.5.4",
"rxjs": "~6.3.3",
"tslib": "^1.9.0",
"zone.js": "~0.8.26"
},
"devDependencies": {
+ "@angular-builders/jest": "^7.4.4",
"@angular-devkit/build-angular": "~0.12.0",
"@angular/cli": "~7.2.4",
"@angular/compiler-cli": "~7.2.0",
@@ -32,17 +35,45 @@
"@types/node": "~8.9.4",
"@types/jasmine": "~2.8.8",
"@types/jasminewd2": "~2.0.3",
+ "@types/jest": "24.0.21",
"codelyzer": "~4.5.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
- "karma": "~3.1.1",
- "karma-chrome-launcher": "~2.2.0",
- "karma-coverage-istanbul-reporter": "~2.0.1",
- "karma-jasmine": "~1.1.2",
- "karma-jasmine-html-reporter": "^0.2.2",
+ "jest": "24.9.0",
+ "jest-preset-angular": "8.0.0",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "~3.1.6"
+ },
+ "jest": {
+ "preset": "jest-preset-angular",
+ "roots": [
+ "src"
+ ],
+ "transform": {
+ "^.+\\.(ts|js|html)$": "ts-jest"
+ },
+ "setupFilesAfterEnv": [
+ "<rootDir>/src/setup-jest.ts"
+ ],
+ "moduleNameMapper": {
+ "@app/(.*)": "<rootDir>/src/app/$1",
+ "@assets/(.*)": "<rootDir>/src/assets/$1",
+ "@core/(.*)": "<rootDir>/src/app/core/$1",
+ "@env": "<rootDir>/src/environments/environment",
+ "@src/(.*)": "<rootDir>/src/src/$1",
+ "@state/(.*)": "<rootDir>/src/app/state/$1"
+ },
+ "globals": {
+ "ts-jest": {
+ "tsConfig": "<rootDir>/src/tsconfig.spec.json",
+ "stringifyContentPathRegex": "\\.html$",
+ "astTransformers": [
+ "jest-preset-angular/build/InlineFilesTransformer",
+ "jest-preset-angular/build/StripStylesTransformer"
+ ]
+ }
+ }
}
}
B.2. angular.json の修正
- angular.json の修正 (Aに同じ)
B.3. src/jest.config.js の追加
Aの手順で実績のあるものを参考に取り込む。
src/jest.config.js
module.exports = {
"transform": {
"^.+\\.(ts|js|html)$": "ts-jest",
"^.+\\.[t|j]sx?$": "babel-jest"
},
moduleFileExtensions: ['ts', 'html', 'js', 'json'],
moduleNameMapper: {
'^src/(.*)$': '<rootDir>/src/$1',
'^app/(.*)$': '<rootDir>/src/app/$1',
'^assets/(.*)$': '<rootDir>/src/assets/$1',
'^environments/(.*)$': '<rootDir>/src/environments/$1',
},
transformIgnorePatterns: ['node_modules/(?!@ngrx)'],
snapshotSerializers: [
'jest-preset-angular/build/AngularSnapshotSerializer.js',
'jest-preset-angular/build/HTMLCommentSerializer.js',
],
globals: {
'ts-jest': {
diagnostics: {
ignoreCodes: [151001]
}
}
}
};
B.4. src/setup-jest.ts の追加
Aの手順で実績のあるものを参考に取り込む。
src/setup-jest.ts
import 'jest-preset-angular';
/* global mocks for jsdom */
const mock = () => {
let storage: { [key: string]: string } = {};
return {
getItem: (key: string) => (key in storage ? storage[key] : null),
setItem: (key: string, value: string) => (storage[key] = value || ''),
removeItem: (key: string) => delete storage[key],
clear: () => (storage = {})
};
};
Object.defineProperty(window, 'localStorage', { value: mock() });
Object.defineProperty(window, 'sessionStorage', { value: mock() });
Object.defineProperty(window, 'getComputedStyle', {
value: () => ['-webkit-appearance'],
});
Object.defineProperty(document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
};
},
});
/* output shorter and more meaningful Zone error stack traces */
// Error.stackTraceLimit = 2;
B.5 src/test-config.helper.ts の追加
Aの手順で実績のあるものを参考に取り込む。
src/test-config.helper.ts
import { TestBed } from '@angular/core/testing';
type CompilerOptions = Partial<{
providers: any[];
useJit: boolean;
preserveWhitespaces: boolean;
}>;
export type ConfigureFn = (testBed: typeof TestBed) => void;
export const configureTests = (
configure: ConfigureFn,
compilerOptions: CompilerOptions = {}
) => {
const compilerConfig: CompilerOptions = {
preserveWhitespaces: false,
...compilerOptions,
};
const configuredTestBed = TestBed.configureCompiler(compilerConfig);
configure(configuredTestBed);
return configuredTestBed.compileComponents().then(() => configuredTestBed);
};
B.6 src/tsconfig.spec.json の編集
Aの手順で実績のあるものを参考に取り込む。
diff --git a/list-server-nohttp/src/tsconfig.spec.json b/list-server-nohttp/src/tsconfig.spec.json
index de77336..400bd63 100644
--- a/list-server-nohttp/src/tsconfig.spec.json
+++ b/list-server-nohttp/src/tsconfig.spec.json
@@ -3,8 +3,7 @@
"compilerOptions": {
"outDir": "../out-tsc/spec",
"types": [
- "jasmine",
- "node"
+ "jest"
]
},
Trouble shooting
Could not find module "karma"
angular.json を修正していない。
list-server-nohttp> ng test
Could not find module "karma" from "~\\list-server-nohttp".
Error: Could not find module "karma" from "~\\list-server-nohttp".
at Object.resolve (~\list-server-nohttp\node_modules\@angular-devkit\core\node\resolve.js:141:11)
at resolveProjectModule (~\list-server-nohttp\node_modules\@angular-devkit\build-angular\src\angular-cli-files\utilities\require-project-module.js:13:19)
at Object.requireProjectModule (~\list-server-nohttp\node_modules\@angular-devkit\build-angular\src\angular-cli-files\utilities\require-project-module.js:22:20)
at Observable.rxjs_1.Observable.obs [as _subscribe] (~\list-server-nohttp\node_modules\@angular-devkit\build-angular\src\karma\index.js:28:52)
at Observable._trySubscribe (~\list-server-nohttp\node_modules\rxjs\internal\Observable.js:44:25)
at Observable.subscribe (~\list-server-nohttp\node_modules\rxjs\internal\Observable.js:30:22)
at ~\list-server-nohttp\node_modules\rxjs\internal\util\subscribeTo.js:22:31
at Object.subscribeToResult (~\list-server-nohttp\node_modules\rxjs\internal\util\subscribeToResult.js:10:45)
at MergeMapSubscriber._innerSub (~\list-server-nohttp\node_modules\rxjs\internal\operators\mergeMap.js:82:29)
at MergeMapSubscriber._tryNext (~\list-server-nohttp\node_modules\rxjs\internal\operators\mergeMap.js:76:14)
at MergeMapSubscriber._next (~\list-server-nohttp\node_modules\rxjs\internal\operators\mergeMap.js:59:18)
at MergeMapSubscriber.Subscriber.next (~\list-server-nohttp\node_modules\rxjs\internal\Subscriber.js:67:18)
at Observable._subscribe (~\list-server-nohttp\node_modules\rxjs\internal\observable\scalar.js:6:20)
at Observable._trySubscribe (~\list-server-nohttp\node_modules\rxjs\internal\Observable.js:44:25)
at Observable.subscribe (~\list-server-nohttp\node_modules\rxjs\internal\Observable.js:30:22)
at MergeMapOperator.call (~\list-server-nohttp\node_modules\rxjs\internal\operators\mergeMap.js:39:23)
list-server-nohttp>
Validation Error: ... node_modules\jest-preset-angular\AngularSnapshotSerializer.js in the snapshotSerializers option was not found.
jest.config.js が存在していない。
ほか、"AngularSnapshotSerializer.js in the snapshotSerializers option was not found." の方は、 jest-preset-angular
のバージョンが 7系の時にエラーになったりする。この場合、 npm install -D jest-preset-angular@8
でうまくいくようになるかもしれない。
list-server-nohttp> ng test
warning: unable to locate custom jest configuration file at path "~\list-server-nohttp\src\jest.config.js"
● Validation Error:
Module ~\list-server-nohttp\node_modules\jest-preset-angular\AngularSnapshotSerializer.js in the snapshotSerializers option was not found.
<rootDir> is: D:\develop\angular\angular7.x-jest\angular-examples\list-server-nohttp
Configuration Documentation:
https://jestjs.io/docs/configuration.html
list-server-nohttp>
Validation Error: Module /src/setup-jest.ts in the setupFilesAfterEnv option was not found.
setup-jest.ts が存在していない。
list-server-nohttp> ng test
● Validation Error:
Module <rootDir>/src/setup-jest.ts in the setupFilesAfterEnv option was not found.
<rootDir> is: ~\list-server-nohttp
Configuration Documentation:
https://jestjs.io/docs/configuration.html
list-server-nohttp>
References
- briebug/jest-schematic: Angular schematic for adding Jest and the required files to an Angular CLI project
- Snapshot Testing · Jest
- module: esnext triggers the module warning diagnostic · Issue #748 · kulshekhar/ts-jest
-
Jest with Angular | Anders Skarby
typescript toMatchSnapshot fixture import angular jest - Tried to introduce Jest on Angular 7 - Tomohiro Uemura - Medium
- Angular CLI: “ng test” with Jest in 3 minutes - codeburst
- 【Jest】AngularでJestを使用する - 開発覚書はてな版
- Use Jest instead of Karma and Jasmine for your Angular project
- Angular8
- Nrwl Nx
Angular 8 に関しては、npm test で動かすことはできるものの ng generate などのコマンドが未対応で Angular CLI を捨てるのに似た状況。Nrwl Nxの拡張機能を使うほうが正道かもしれませんね。
余談
- Node.js を触り始めて日が浅いが、semantic versioning の major.minor.patch の minor あたりは割と破綻してるんじゃないかなと思う
- 結局、依存VL合わせはうまくいかず、テストで動けばよいぐらい考えでよい気がしてきた
GitHub の@angular-builders/jest
の package.json の dependency にある要求VLを見る限り、警告の出ない組み合わせは無理
→ どうあるべきかなと考えて GNU autoconf を思い出した。
- 結局、依存VL合わせはうまくいかず、テストで動けばよいぐらい考えでよい気がしてきた
- Jest vs Karma
- 対比してみて、Karma の知識が高まった。良くも悪くも、Karma の方がブラウザを使ったテストができる分、趣旨が異なる
- Jest の方は、機能的なリグレッションテストに特化する使い方かな?
ブラウザ非互換とかの目的には使えない。スナップショットの管理は便利かなという印象。 - Karma のサポートブラウザに JSDOM とかある。スピードだけで言えば、Karma も時間短縮なのかもしれない
- Google と Facebook のアプローチがツールにも出ている気はする
- Google(Karma) ... ブラウザやデバイス依存の機能など最新機能をどんどんリリースする
- Facebook(Jest) ... あまり最新機能を追う必要のないから、ブラウザの互換のテストはそこまで頑張らなくてよい
- Angular8 は2019-11-04 現在、うまくいかなかった
- 今、この瞬間に Jestが超使いたい! ……というわけでもないので、別に良い
- Jest押しの記事が増えているけれども、ちょっと一歩引いてみたほうが良さげな印象
もう少し、Karmaを使い込んでみて比較するのがいいか。