Cypress で html テストレポート (mochawesome) を出力する
Cypress には Cypress Dashboard というテスト実行と実行結果のレポートを生成する素晴らしいサービスがありますが、これを諸事情により使えないけど html テストレポートが欲しいという場合に、自前で生成する方法を説明します。 Dashboard 完全互換ではありません。
下準備
単純な状態を作るために Cypress だけを依存関係に追加したパッケージを作り、初期化します。
yarn init
yarn add --dev cypress
yarn cypress open
この記事では yarn
を使います。 npm
を利用される方は適宜読み替えてください。
これにより Cypress の設定ファイルである cypress.json
が直下に、テストファイル等が cypress
ディレクトリ以下に作成されます。
html レポートを出力する
mochawesome をレポーターとして設定する
Cypress は Mocha ベースで作られているため Mocha に対応したレポーターを利用することができます。
今回は mochawesome という html レポーターを利用します。
まずは mochawesome を依存関係に追加しますが、レポーターに peerDependencies
が指定されている場合、それも追加する必要があります。
mochawesome には mocha
が peerDependencies として指定されているため、 Mocha も追加します。
なお、本記事執筆時点での最新版の Mocha は 6 系ですが、使用すると Cannot read property 'passes' of undefined
というエラーが出てしまうため、 5 系 に落とす必要があります。1
yarn add --dev mochawesome mocha@^5.2.0
次に Cypress に mochawesome をレポーターとして設定します。
cypress.json
に追記します。
{
"reporter": "mochawesome"
}
この状態でテストを実行してみます。
yarn cypress run
テストが完了すると直下に mochawesome-report
というディレクトリができています。
これが、 mochawesome により作成された html レポートになります。
設定により出力ディレクトリを変更することが可能2ですが、今回は出力先を変更しません。
中身を見ると mochawesome.html
と mochawesome.json
と assets
というディレクトリができています。3
mochawesome.html
というのが出力された html レポートなのでこれを確認してみると、いくつかあるスペックファイルのうちの一つのスペックの結果しか出力されていません。
Cypress はスペック毎に出力を行い、出力のたびにレポートを 上書き するため4で、上書きしないようにする必要があります。
なお、 Cypress がレポートを出力する際、既存のレポートを消すことはないので、テスト実行前に自前でレポートを必ず消す必要があります。
スペック毎にレポートを出力する
スペック毎にレポートを出力するには cypress.json で設定をします。
{
"reporter": "mochawesome",
"reporterOptions": {
"overwrite": false
}
}
この状態で再度テストを実行してみると、 mochawesome-report 以下に連番の html ファイルと json ファイルが作成されます。
中身を確認するとスペック毎に結果が出力されていますが、これだとスペックファイルが増えるたびに参照先が増えることになってしまうので、一つのファイルにまとめるようにします。
mochawesome のレポートをマージする
中間ファイルをマージする
mochawesome のレポートを一つにまとめるには mochawesome-merge というツールを使います。
まずは、依存関係に追加します。
yarn add --dev mochawesome-merge
そして、 cypress.json の設定を変更します。
mochawesome-merge で中間ファイルの json を一つにまとめた後に、別途 html レポートを生成するため、 html の出力を無効にし、 json だけを出力するように変えます。
{
"reporter": "mochawesome",
"reporterOptions": {
"overwrite": false,
"html": false,
"json": true
}
}
この状態でテストを実行すると mochawesome-report 下に json がいくつか作成されます。
これを mochawesome-merge で一つの json にまとめます。
まとめる方法として、 js のスクリプトを書く方法とコマンドラインで実行する方法がありますが、ここではコマンドラインで実行する方法を利用します。5
yarn --silent mochawesome-merge > mochawesome.json
ここでの注意点として --silent
オプションを yarn に渡すのを忘れないようにしてください。
渡さないと yarn 自体の出力が json に書き込まれてしまい、 json を読み込もうとした時に文法エラーになってしまいます。
npm scripts の場合には mochawesome-merge > mochawesome.json
で問題ありません。
このコマンドを実行すると mochawesome-report 以下の json に出力された結果が、直下の mochawesome.json
という一つの json にマージされます。
出力先を変更する場合にはリダイレクト先を変更します。
また、レポート出力先ディレクトリを変更している場合には、 --reportDir
という引数にそのディレクトリのパスを渡します。
マージされた中間ファイルから html レポートを出力する
中間ファイルからレポートを出力します。レポートを出力するのに mochawesome-report-generator(marge) を利用します。
marge は mochawesome-report が依存しているため依存関係に追加せずに利用できます。
yarn marge mochawesome.json
引数に html レポートの元となる json ファイルを指定して実行します。
実行すると mochawesome-report 下に mochawesome.html
と assets
ディレクトリができ、 mochawesome.html を参照するとすべてのスペックがマージされた結果が出力されていることが確認できます。
出力先の変更
mochawesome-report 下の assets と mochawesome.html をホストすれば結果を公開できるのですが、 mochawesome-report 下には中間ファイルのスペック毎の json があり邪魔です。
邪魔なファイルを消すという手もありますが、 marge には出力先を変更するオプション -o
がある6ので、これを利用して mochawesome-report ではないところに出力するようにします。
この後に利用するスクリーンショットや動画の添付の際に相対パスを利用するため cypress 下にレポートを出力するようにします。
mkdir cypress/report
yarn --silent mochawesome-merge > cypress/report/mochawesome.json
yarn marge cypress/report/mochawesome.json -o cypress/report
スクリーンショットや動画をレポートに添付する
Cypress は cypress run
での実行時に、テスト失敗時のスクリーンショットおよびテスト結果に関わらずテスト開始から終了までの動画を自動で cypress ディレクトリ以下に保存します。7
しかし、単にレポート出力を行っただけだとレポートには添付されないため、レポートに添付できるようにします。
mochawesome のテスト結果に情報を追加する
mochawesome には各テスト結果に情報を追加する addContext
というメソッドがあります。
このメソッドは様々な種類の情報を添付することができる8ので、このメソッドを利用してスクリーンショットおよび動画をテスト結果に添付します。
Cypress で mochawesome の addContext を呼び出す
イベントで addContext を呼び出す
Cypress では Cypress の機能を拡張するプラグインの仕組み9が用意されていますが、今回の目的に適した拡張できるイベントがありません。
after:screenshot
というイベントがありますが、スクリーンショットが取得された時だけで動画には対応できませんし、 addContext に渡すテストオブジェクトが取得できません。
そこで今回はデバッグ目的10とされているイベントフックを利用します。
イベントは cypress/support/index.js
から以下のようにフックします。11
Cypress.on(イベント名, コールバック);
利用できるイベントの中にテスト実行後に呼び出される test:after:run
というのがあり、
このイベントはテストの各種属性と Mocha の runnable を引数として受け取ります。
このコールバックの中で先ほどの addContext を呼び出します。
スクリーンショットは失敗時のみ取得されるためテスト結果を判定する必要があります。
テスト結果はコールバックの第一引数のオブジェクトの state
プロパティが failed
かどうかで判定できます。
addContext の第一引数のテストオブジェクトの test
というプロパティにコールバックの第一引数をセットしたオブジェクトを渡します。
addContext の第二引数にはスクリーンショットへのパスと動画へのパスを渡します。
import addContext from 'mochawesome/addContext';
Cypress.on('test:after:run', (test, runnable) => {
if (test.state === 'failed') {
addContext({ test }, 'スクリーンショットへのパス');
}
addContext({ test }, '動画へのパス');
});
スクリーンショットおよび動画のパスの取得
スクリーンショットが保存されるパスはデフォルトでは以下のようになっています。12
{screenshotsFolder}/{specPath}/{testName} (failed).png
各値は以下のように取得できます。
- screenshotsFolder: スクリーンショットが保存されるベースとなるディレクトリ。設定により変更可能 13 で、デフォルトでは
cypress/screenshots
。Cypress.config('screenshotsFolder')
で取得可能だが、絶対パスになるため相対パス化が必要。今回の例ではデフォルト値を利用し起点となるのが cypress/report なので、../screenshots
になる。 - specPath: スペックファイルのファイル名。
location.pathname
からディレクトリ付きで取得可能だが、/__cypress/iframes/integration/ディレクトリ/ファイル
というような形になるので変換には若干工夫が必要。 - testName: コールバックの第二引数のプロパティ
parent.title
およびtitle
から取得可能。
動画が保存されるパスは以下のようになっています。
{videosFolder}/{specPath}.mp4
こちらも各値は以下のようになっています。
- videosFolder: スクリーンショットが保存されるベースとなるディレクトリ。設定により変更可能 13 。
Cypress.config('videosFolder')
で取得可能だが、絶対パスになるため相対パス化が必要。 - specPath: スペックファイルのファイル名。
location.pathname
からディレクトリ付きで取得可能だが、/__cypress/iframes/integration/ディレクトリ/ファイル
というような形になるので変換には若干工夫が必要。
上記のようなことから cypress/support/index.js の中は最終的に以下のようになります。
import addContext from 'mochawesome/addContext';
Cypress.on('test:after:run', (test, runnable) => {
if (test.state === 'failed') {
addContext({ test }, `../screenshots/examples/${location.pathname.replace(/(.*)\//, '')}/${runnable.parent.title} -- ${test.title} (failed).png`);
}
addContext({ test }, `../videos/examples/${location.pathname.replace(/(.*)\//, '')}.mp4`);
});
注意点
- 上記のパス指定の仕方だとテストのネストの仕方によっては上手く行かないかもしれません。
- スペックのディレクトリおよびファイル名の取得は手抜きです。
- 上記はエラー時に自動で取得されるスクリーンショットだけを考慮しており、自前でスクリーンショットを取得する場合14は考慮していません。自前でスクリーンショットを取得したものをレポートに追加するのは、フックできるのが after:screenshot しかなく、前述したように test オブジェクトを取得することができなさそうなので、無理なように思えます。
実行コマンド
最終的な実行コマンドは以下のようになります。
rm -rf mochawesome-report cypress/report
yarn cypress run
mkdir cypress/report
yarn --silent mochawesome-merge > cypress/report/mochawesome.json
yarn marge cypress/report/mochawesome.json -o cypress/report
これであとは以下のディレクトリをホストすればテスト結果をスクリーンショットおよび動画付きで公開することができます。
- cypress/report
- cypress/screenshots
- cypress/videos
サンプル
ここまでをまとめたサンプルは以下のリポジトリにおいてあります。
-
cypress.json の
reporterOptions.reportDir
で設定。 ↩ -
https://docs.cypress.io/guides/tooling/reporters.html#Report-per-spec を参照。 ↩
-
スクリプトで実行する方法は https://github.com/Antontelesh/mochawesome-merge#cypress を参照。 ↩
-
その他のオプションは https://github.com/adamgruber/mochawesome-report-generator#options を参照。 ↩
-
詳細は https://docs.cypress.io/guides/guides/screenshots-and-videos.html を参照。オプションにより挙動を変えることができます。 ↩
-
https://github.com/adamgruber/mochawesome#adding-test-context を参照。 ↩
-
https://docs.cypress.io/api/plugins/writing-a-plugin.html を参照。 ↩
-
https://docs.cypress.io/api/events/catalog-of-events.html を参照。 ↩
-
設定により変更可能。 https://docs.cypress.io/guides/references/configuration.html#Folders-Files を参照。 ↩
-
https://docs.cypress.io/api/commands/screenshot.html#Naming-conventions を参照。 ↩
-
https://docs.cypress.io/guides/references/configuration.html#Screenshots を参照。 ↩ ↩2