尝试将Jest引入Angular7.2

简而言之

这是关于在Angular 7中尝试引入Jest时的笔记。
有些网站上写着只需运行四个命令就可以运行,但实际上并非如此,我通过反复试错找到了解决方法并进行了整理。

有两种导入的方式。

    • 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

将已经创建的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

一. 编辑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. 添加 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.1 编辑 package.json 文件

参考以 A 已经获得成就的 package.json 文件来导入。

比较 package.json 文件比较 –git a/list-server-nohttp/package.json b/list-server-nohttp/package.json
索引 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”: [
+ “/src/setup-jest.ts”
+ ],
+ “moduleNameMapper”: {
+ “@app/(.*)”: “/src/app/$1”,
+ “@assets/(.*)”: “/src/assets/$1”,
+ “@core/(.*)”: “/src/app/core/$1”,
+ “@env”: “/src/environments/environment”,
+ “@src/(.*)”: “/src/src/$1”,
+ “@state/(.*)”: “/src/app/state/$1”
+ },
+ “globals”: {
+ “ts-jest”: {
+ “tsConfig”: “/src/tsconfig.spec.json”,
+ “stringifyContentPathRegex”: “\\.html$”,
+ “astTransformers”: [
+ “jest-preset-angular/build/InlineFilesTransformer”,
+ “jest-preset-angular/build/StripStylesTransformer”
+ ]
+ }
+ }
}
}

B.2. 修改 angular.json

    angular.json の修正 (Aに同じ)

在Chinese的native version中,B.3. src/jest.config.js 的追加 可以是:“增加src/jest.config.js文件”。

参考A的步骤,并融入有成果的元素。

src/jest.config.jsmodule.exports = {
“transform”: {
“^.+\\.(ts|js|html)$”: “ts-jest”,
“^.+\\.[t|j]sx?$”: “babel-jest”
},
moduleFileExtensions: [‘ts’, ‘html’, ‘js’, ‘json’],
moduleNameMapper: {
‘^src/(.*)$’: ‘/src/$1’,
‘^app/(.*)$’: ‘/src/app/$1’,
‘^assets/(.*)$’: ‘/src/assets/$1’,
‘^environments/(.*)$’: ‘/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]
}
}
}
};

src/jest.config.js

module.exports = {
“transform”: {
“^.+\\.(ts|js|html)$”: “ts-jest”,
“^.+\\.[t|j]sx?$”: “babel-jest”
},
moduleFileExtensions: [‘ts’, ‘html’, ‘js’, ‘json’],
moduleNameMapper: {
‘^src/(.*)$’: ‘/src/$1’,
‘^app/(.*)$’: ‘/src/app/$1’,
‘^assets/(.*)$’: ‘/src/assets/$1’,
‘^environments/(.*)$’: ‘/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]
}
}
}
};

添加 src/setup-jest.ts

根据A的步骤参考并吸收有成就的事例。

src/setup-jest.tsimport ‘jest-preset-angular’;

/* 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,
};
},
});

/* 输出更简短和更有意义的Zone错误堆栈跟踪 */
// Error.stackTraceLimit = 2;

添加 src/test-config.helper.ts 到 B.5

参考A的步骤,并借鉴其中的成功经验。

在 src/test-config.helper.ts 文件中,我们导入了 TestBed 模块,定义了 CompilerOptions 类型和 ConfigureFn 类型。然后,我们导出了 configureTests 函数,该函数接受一个 configure 参数和一个 compilerOptions 参数,并且有一个默认值为空对象的 compilerOptions。在函数内部,我们先创建了一个 compilerConfig 对象,该对象的 preserveWhitespaces 属性值为 false,然后使用 spread 操作符将 compilerOptions 对象的属性合并到 compilerConfig 对象中。接下来,我们使用 TestBed.configureCompiler 方法传入 compilerConfig 对象来配置 TestBed,并将配置后的 TestBed 赋值给 configuredTestBed。然后,我们调用 configure 函数,并将 configuredTestBed 作为参数传入。最后,我们调用 configuredTestBed 的 compileComponents 方法编译组件,并在编译完成后返回 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"
     ]
   },

故障排查

找不到模块“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>

验证错误:…在snapshotSerializers选项中未找到node_modules\jest-preset-angular\AngularSnapshotSerializer.js。

没有找到 jest.config.js。
另外,如果 jest-preset-angular 的版本是 7 系列,可能会出现 “AngularSnapshotSerializer.js in the snapshotSerializers option was not found.” 的错误。在这种情况下,可能会通过 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>
    javascript – Angular 7 & Jest & Babel Integration over Jasmine/Karma – AngularSnapshotSerializer.js in the snapshotSerializers option was not found – Stack Overflow

验证错误:在setupFilesAfterEnv选项中未找到模块/src/setup-jest.ts。

缺少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>

参考文献

    • 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

File not found: jest-preset-angular/InlineHtmlStripStylesTransformer.js · Issue #332 · thymikee/jest-preset-angular
2019-11-04 現在、次の Issue でうまくいかない模様。
Add Support for jest-preset-angular 8.0 · Issue #596 · just-jeb/angular-builders

How I do configure Jest to test my Angular 8 Project – itnext

Nrwl Nx
Angular 8 に関しては、npm test で動かすことはできるものの ng generate などのコマンドが未対応で Angular CLI を捨てるのに似た状況。Nrwl Nxの拡張機能を使うほうが正道かもしれませんね。

Nx 6.3: Faster Testing with Jest – Nrwl
Create Workspace with Angular defaults to Jest for testing · Issue #1698 · nrwl/nx
How to Set Up Angular Unit Testing with Jest – Amadou Sall

闲聊

    • 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を使い込んでみて比較するのがいいか。

bannerAds