Create-React-Appで作ったReactアプリのTest結果をCodeBuildでレポート出力する方法


はじめに

最近インフラ関係をAWSに移し、CodeBuildを使い始めたのですが、AWSの公式ガイドに書いてある内容通りにやってみてもテストレポートが出力されなかったので、今回自力で設定したことを備忘録もかねて残しておきます。

想定読者

CodeBuildのプロジェクト設定等はあらかた終わっていて、ビルドができるようになったので、テストレポートを出力したい人

1.React側の設定

まず公式ガイドにも書いてある通り、xml形式でファイルを出力するため、jest-junitを追加します。

console
yarn add jest-junit

そして公式ガイド通りにjestのreportersを設定しようとするとエラーが出ます。
プロジェクトルート直下のpackage.jsonに以下を記述してみてください。

公式ガイド

module.exports = {
  reporters: [
    'default',
    [ 'jest-junit', {
      outputDirectory: <test report directory>,
      outputName: <report filename>,
    } ]
  ]
};
package.json
....

 "jest": {
    "reporters": [
      "default",
      [
        "jest-junit",
        {
          "outputDirectory": "reports/results(結果を出力したい任意のディレクトリ)",
          "outputName": "test-results.xml(出力したいファイル名)"
        }
      ]
    ]
  }

These options in your package.json Jest configuration are not currently supported by Create React App:

・reporters
If you wish to override...

Create-React-Appではその設定は認めません!と怒られてしまいました。

そこで、もう一度package.jsonを開き、scriptsの部分を編集し直接reportersを記述してやります。

package.json

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom --verbose",
 ++ "test:ci": "react-scripts test --watchAll=false --ci --reporters=default --reporters=jest-junit",
    "eject": "react-scripts eject"
  },

reporters以外の各optionは公式サイトに詳しく書いてあるのでここでは割愛します。
また、CodeBuildにCodePipelineなどを使ってCI/CD環境を導入することも多いと思うのでここではtest:ciコマンドを編集しています。自分がわかりやすいscript名で問題ありません。
consoleに戻って、test:ciコマンドを実行します。

console
yarn test:ci 

...
yarn run v1.22.5
$ react-scripts test --ci --reporters=default --reporters=jest-junit

PASS  src/tests/Main.test.js (7.653 s)
  Main's debug test
    √ should show all contents (645 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.971 s, estimated 10 s
Ran all test suites related to changed files.

Watch Usage
 › Press a to run all tests.
 › Press f to run only failed tests.
 › Press q to quit watch mode.
 › Press p to filter by a filename regex pattern.
 › Press t to filter by a test name regex pattern.
 › Press Enter to trigger a test run.

うまくいきました。
これでプロジェクトルートにjunit.xmlというファイルが出力されていると思います。
出力先やファイル名を変更したい場合は、再度package.jsonを開き、以下の記述を追加します。

package.json
   "jest-junit": {
    "outputDirectory": "任意のディレクトリ",
    "outputName": "任意のファイル名"
  }

このディレクトリ名とファイル名はbuildspec.ymlでも使うので覚えておきましょう。

2 CodeBuild側の設定

buildspec.ymlの末尾に以下を追記すれば終わりです。便利!

buildspec.yml
reports:
  jest_reports:
    files:
      - "package.jsonで指定したファイル名"
    file-format: JUNITXML
    base-directory: "package.jsonで指定したディレクトリ"

後はCodeBuildページからレポート履歴を見ていただければレポートがあると思います。

余談ですが2020年12月17日現在、buildspec.ymlのpre_build phaseでtestを実行してしまうと、
テストが失敗したときにレポートがうまく生成されない仕様となっているようです。

必ずbuildかpost_build phaseでtestは実行しようと思いました。こえー

また、test scriptsの実行に失敗するとその後のcommandsがスキップされるので
phases/build/commandsの順序には気を付ける、場合によってはtest fail時にも必要な処理はfinallyブロックに分けて記述するべきだなあと感じました。
(そもそもローカル環境でテスト通してからgit pushするからあまり想定しなくても良いことかもですが・・・)

buildspec.yml
意図的にエラーを出し、その後のdocker build等が行われないことを確認する。
以下は手元にあったtest後にdocker buildするymlファイル

build:
    commands:
      - yarn install
      - yarn test:ci --watchAll=false 
      - docker build -t $ACCOUNT_ID.dkr.ecr.$DEFAULT_REGION.amazonaws.com/failedtest:latest .
      - docker push $ACCOUNT_ID.dkr.ecr.$DEFAULT_REGION.amazonaws.com/failedtest:latest
Errorlog
[Container] 2020/12/17 09:26:21 Command did not exit successfully yarn test:ci --watchAll=false exit status 1
[Container] 2020/12/17 09:26:21 Phase complete: BUILD State: FAILED  ##以降のdockerの処理が行われない
[Container] 2020/12/17 09:26:21 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: yarn test:ci --watchAll=false. Reason: exit status 1
[Container] 2020/12/17 09:26:21 Entering phase POST_BUILD

3.最後に

ここまで見てくださってありがとうございました。
初投稿なので緊張しました。何か間違っていたり、もっと良い方法がございましたら教えて頂けると幸いです