LoginSignup
2
2

More than 3 years have passed since last update.

Angular7.2 に Jest を導入してみる

Last updated at Posted at 2019-11-04

概要

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

余談

  • Node.js を触り始めて日が浅いが、semantic versioning の major.minor.patch の minor あたりは割と破綻してるんじゃないかなと思う
    • 結局、依存VL合わせはうまくいかず、テストで動けばよいぐらい考えでよい気がしてきた
      GitHub の @angular-builders/jest の package.json の dependency にある要求VLを見る限り、警告の出ない組み合わせは無理
      → どうあるべきかなと考えて GNU autoconf を思い出した。
  • Jest vs Karma
    • 対比してみて、Karma の知識が高まった。良くも悪くも、Karma の方がブラウザを使ったテストができる分、趣旨が異なる
    • Jest の方は、機能的なリグレッションテストに特化する使い方かな?
      ブラウザ非互換とかの目的には使えない。スナップショットの管理は便利かなという印象。
    • Karma のサポートブラウザに JSDOM とかある。スピードだけで言えば、Karma も時間短縮なのかもしれない
    • Google と Facebook のアプローチがツールにも出ている気はする
      • Google(Karma) ... ブラウザやデバイス依存の機能など最新機能をどんどんリリースする
      • Facebook(Jest) ... あまり最新機能を追う必要のないから、ブラウザの互換のテストはそこまで頑張らなくてよい
  • Angular8 は2019-11-04 現在、うまくいかなかった
    • 今、この瞬間に Jestが超使いたい! ……というわけでもないので、別に良い
    • Jest押しの記事が増えているけれども、ちょっと一歩引いてみたほうが良さげな印象
      もう少し、Karmaを使い込んでみて比較するのがいいか。
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2