TypeScriptとjestでカバレッジを取る

前置き

この記事は下記の記事を補足する形で書いていきます。

React + TypeScriptでjestを使ったテストをする - かずきのBlog@hatena

この記事で行うのはTypeScriptのテストを行って、jestでカバレッジを取るまでです。

足回り

まずはtsconfig.jsonです。とりあえず使いまわししてるので変なところがあれば教えてください。

{  
  "compilerOptions": {  
    "module": "commonjs",  
    "moduleResolution": "node",  
    "target": "es6",  
    "lib": [  
      "dom",  
      "es2016",  
      "es2017"  
    ],  
    "noImplicitAny": true,  
    "strictNullChecks": true,  
    "noFallthroughCasesInSwitch": true,  
    "noImplicitReturns": true,  
    "noImplicitThis": true,  
    "noUnusedLocals": true,  
    "noUnusedParameters": true,  
    "noImplicitUseStrict": true,  
    "sourceMap": false,  
    "emitDecoratorMetadata": true,  
    "experimentalDecorators": true,  
    "forceConsistentCasingInFileNames": true,  
    "listFiles": false,  
    "stripInternal": true,  
    "skipDefaultLibCheck": true,  
    "pretty": false,  
    "noEmitOnError": true  
  },  
  "exclude": [  
    "node_modules"  
  ]  
}  

モジュールのインストール

今回はほとんど使わないですが@typesで型定義を読み込みます。
tsconfig.jsonのcompilerOptions.typesの定義をしていない場合に自動で読み込まれます。
もちろん自分で記述することもできますが。

yarn add @types/jest @types/react @types/react-dom ts-jest jest typescript -D  
yarn add react react-dom  

今回、この型定義の読み分けをsrcとtestで切り分けしようかと思ったのですが
できませんでしたので、実装コード側でもjestの型定義が読まれることになります。
babelとESLintの組み合わせだとフォルダで切り分けとかできるんですが・・・
(eslint-plugin-mochaとかその辺使うイメージです)

jestの設定とtestの設定

package.jsonに以下の設定を記述します。
ちなみに、testMatchというキーのほかにtestRegexというキーでテストのファイルを指定することができます。
どちらか片方しか使えません。

今回はjestはnpm scriptsで動かします。
また、今回はTypeScriptを使うため、preprocessorを指定しています。
読み込み前に変換するモジュールですね。

カバレッジはcollectCoverageをtrueにするだけで取ることができます。
カバレッジの対象を実装コードのみにcolelctCoverageFromで絞ってあげましょう。

  "scripts":{  
    "test":"jest"  
  },  
  "jest": {  
    "moduleFileExtensions": [  
      "ts",  
      "tsx",  
      "js"  
    ],  
    "transform": {  
      "\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"  
    },  
    "testMatch": [  
      "**/src/test/front/**/*.ts?(x)"  
    ],  
    "collectCoverage": true,  
    "collectCoverageFrom": [  
      "src/main/front/**/*.ts?(x)"  
    ]  
  }  

とりあえずのテストコード

サンプルソースです。

console.log("hellox")  
export default function () {  
  console.log("test")  
  if (typeof window == "object") {  
    console.log("not reached")  
  }  
}  

で、こちらがテストコードです。
エラーが発生しないことを確認するだけの簡単なテストです。
unmockで実装がしっかり呼ばれるようにしておきます。

import x from "../../main/front/test"  
jest.unmock("../../main/front/test")  
  
describe("test", () => {  
  it("no error", function () {  
    x()  
  })  
})  

テストを実行してカバレッジを取ってみる。

初めにnpm scriptsで設定したので
npm testで動作するはずです。

${project}/coverage/lcov-report/index.htmlにカバレッジが吐き出されているので見てみます。

f:id:reteria:20170310055817p:plain
f:id:reteria:20170310055838p:plain

カバレッジが取れています。
やったね!100%カバレッジだ!!()

は?本来、通らないはずなんだけど???

なぜカバレッジ100%になったのか

jestはnode上で実行されているため、本来window objectはglobalに定義されていないはずですが
定義されているため、通らないと思っていたコードが実行されています。

これはjsdomのwindowオブジェクトによってmock化されています。

詳しくは以下の記事にどうぞ。
なぜJestが全てをモックできるのか - Qiita

まとめ

jestでカバレッジを取るために、駆け足でブログを書きました。
おかしなところがあれば教えてください。