CircleCI で Jest のテスト結果を保存する

# はじめに

テストを実行するに当たって、テストカバレッジやテストの実行時間を計測してテスト戦略を立てていくことは重要です。
ここでは CircleCI で Jest を使ったテストにおける設定項目をまとめます。

# 環境

CircleCI 2.1

# Jest の設定

## カバレッジを取得する設定

`jest.config.js` に以下の設定を追加します。
`collectCoverage` を有効にし、`coverageDirectory` でカバレッジレポートの出力先を指定しています。
プロダクションコードが `src` ディレクトリ配下にあり、JavaScript、TypeScript が存在するプロジェクトを想定しています。

```js:jest.config.js
  collectCoverage: true,
  collectCoverageFrom: ['src/**/*.{js,ts}'],
  coverageDirectory: 'coverage',
```

これでテストを実行するとカバレッジレポートが出力されます。

## テスト結果を取得する設定

プロジェクトに `jest-junit` を追加します。

```bash
$ npm install --save-dev jest-junit
```

`jest-junit` は Jest で実行したテスト結果を JUnit 形式にレポートを出力するライブラリです。
`jest.config.js` に以下の設定を追加します。

```js:jest.config.js
  reporters: [
    'default',
    [
      'jest-junit',
      {
        suiteName: 'jest tests',
        outputDirectory: 'reports/jest',
        outputName: 'js-test-results.xml',
        classNameTemplate: '{classname}-{title}',
        titleTemplate: '{classname}-{title}',
        ancestorSeparator: ' › ',
      },
    ],
  ],
```

いくつか設定に使った項目について触れていきます。
他の設定項目に関しては、[README](https://github.com/jest-community/jest-junit) を参照してください。

- suiteName
  `testsuites` タグの `name` 属性に表示する名前を指定します。

- outputDirectory
  テスト結果の出力ディレクトリを指定します。

- outputName
  テスト結果のファイル名を指定します。

- classNameTemplate
  `testcase` タグの `classname` 属性に表示する名前を指定します。

- titleTemplate
  `testcase` タグの `name` 属性に表示する名前を指定します。

- ancestorSeparator
  Jest の `describe` ブロックを結合するために使用する文字を指定します。

通常のテストコマンドとは別に CircleCI 用に npm scripts を追加します。
`--ci` オプションで CI に最適化され、`--runInBand` オプションで実際の仮想化されたビルド環境のみを使用するようになります。

```json:package.json
    "test:ci": "jest -i --ci --runInBand"
```

# CircleCI の設定

## カバレッジを保存する設定

追加した `npm run test:ci` コマンドでテストを実行します。
`store_artifacts` キーに生成された `coverage` ディレクトリを指定すると CircleCI 上へと保存されます。

```yaml:.circleci/config.yml
version: 2.1
jobs:
  test:
    docker:
      - image: circleci/node:12
    steps:
      - checkout
      - run: npm install
      - run: npm run test:ci
      - store_artifacts:
          path: coverage
```

## テスト結果を保存する設定

`store_test_results` キーに `reports` ディレクトリを指定することで `Builds` ページの `Test Summary` タブに表示されます。
`store_artifacts` キーに指定することで `coverage` 同様 CircleCI 上へと保存されます。

```diff:.circleci/config.yml
 version: 2.1
 jobs:
   test:
     docker:
       - image: circleci/node:12
     steps:
       - checkout
       - run: npm install
       - run: npm run test:ci
+      - store_test_results:
+          path: reports
+      - store_artifacts:
+          path: reports
       - store_artifacts:
           path: coverage
```

実際に CircleCI 上で実行したテスト結果を確認すると `Test Summary` タブでは失敗したテストを見やすく表示してくれます。
成功した場合はスローテストを表示してくれます。

![Test Summary](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129299/6714f184-d4a9-3a1a-9df0-6356d4192be4.png)

`Artifacts` タブでは CircleCI 上に保存したテスト結果ファイルが確認できます。
カバレッジレポートでは HTML ファイルが生成されるため、開くとそのままブラウザから表示できます。

![Artifacts](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129299/bd4d17b2-53a1-ae0d-8fc2-bcebbf81aad7.png)

`Timing` タブでは、テストのタイミングデータを保存します。
これは、テストを並列実行した際のタイミング解析に用いることができます。
詳しくは[ドキュメント](https://circleci.com/docs/2.0/parallelism-faster-jobs/#splitting-by-timing-data)を参照してください。

![Timing](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129299/bf85bfe2-2fa9-6439-6f7f-8edbd804be50.png)

# さいごに

CircleCI で Jest のテスト結果を取り扱う方法について取り上げました。
デフォルトでは CircleCI 上で長いスクロールをしながら原因を特定する必要がありましたが、これらの設定をすることでテスト結果をページ上部から確認できるようになりとても分かりやすくなりました。
是非これらの設定をしてテストの改善に役立ててみてください。

# 参考

[Generating Code Coverage Metrics - CircleCI](https://circleci.com/docs/2.0/code-coverage/)
[Configuring CircleCI - CircleCI](https://circleci.com/docs/2.0/configuration-reference/)
[jest-community/jest-junit: A Jest reporter that creates compatible junit xml files - GitHub](https://github.com/jest-community/jest-junit)