AWS Device Farm で Appium を使って 実行時のスクリーンショットレポートを取得してみた

2021.06.18

いわさです。

AWS Device Farm の実行結果画面にはスクリーンショットを確認するエリアが存在します。

特別な実装を行わなくてでもデバイスでの自動操作の様子を動画で保存してくれるため確認することが可能です。
しかし、デバイスの数が多いと1台1台の動画を再生するのはなかなかつらいです。

上記画像では、"No screenshots found" となっています。
Device Farm でレポート画面にスクリーンショットを表示するためには、テストコードへの明示的な実装が必要です。
今回は Device Farm + Appium + Node.js 環境で、スクリーンショットを取得し、AWSマネジメントコンソールで取得出来るようにしましょう。

この記事ではコード最適化については追求していないのでその点だけご注意ください。

スクリーンショットが取得できない、誤った実装

上記には以下のように案内されています。

Android UI Automator テストの一部としてスクリーンショットを撮ることができます。
スクリーンショットを取得するには、takeScreenshot メソッドを呼び出します (例 :takeScreenshot("/sdcard/uiautomator-screenshots/home-screen-1234.png");)。

当初ひたすらこれに従ってトライ&エラーを繰り返していました。 いま考えると、Appiumクライアントに対して "sdcard" というのはおかしいですよね。もっと早く気づくべきでした。

以下のような実装を行い、保存されない。という状態です。

index.js

  await client.saveScreenshot("/sdcard/uiautomator-screenshots/screenshot_1.png");
  await client.takeScreenshot().then(image => ...省略... );
  await client.saveScreenshot("/mnt/sdcard/uiautomator-screenshots/screenshot_3.png");
iwasa.takahito@xxx appium-hellohello % npm-bundle
appium-hellohello-1.0.0.tgz
iwasa.takahito@xxx appium-hellohello % zip -r test.zip *.tgz
updating: appium-hellohello-1.0.0.tgz (deflated 0%)
(node:3987) UnhandledPromiseRejectionWarning: Error: directory (/sdcard/uiautomator-screenshots) doesn't exist

もちろんスクリーンショットは取得されていませんね。

正しくは以下に答えが記されていました。

Device Farm は、SCREENSHOT_PATH プロパティをローカルファイルシステム上の完全修飾パスに設定します。Device Farm は、そのパスを Appium スクリーンショットの保存先とみなします。スクリーンショットが保存されているテスト固有のディレクトリは、実行時に定義されます。スクリーンショットは Device Farm レポートに自動的に取り込まれます。

スクリーンショットが取得できる、正しい実装

Device Farm が Appiumクライアントを起動するのですが、実行時にスクリーンショットの保存先を設定します。
この文脈からすると環境変数でしょう。
このパスに保存されたスクリーンショットは完了時にレポートに取り込まれるという仕組みです。

最終的には以下の実装で取得することが出来ました。

index.js

async function main () {
  const client = await wdio.remote(opts);
  const txt1 = await client.$(await client.findElement("id", "com.tak1wa.hellohello:id/txtParam1"));
  await txt1.setValue("2");
  await client.saveScreenshot(process.env.SCREENSHOT_PATH + "/1.png");

  const txt2 = await client.$(await client.findElement("id", "com.tak1wa.hellohello:id/txtParam2"));
  await txt2.setValue("3");
  await client.saveScreenshot(process.env.SCREENSHOT_PATH + "/2.png");
  
  const btn = await client.$(await client.findElement("id", "com.tak1wa.hellohello:id/btnInput"));
  await btn.click();
  await client.saveScreenshot(process.env.SCREENSHOT_PATH + "/3.png");
  
  const lbl = await client.$(await client.findElement("id", "com.tak1wa.hellohello:id/lblOutput"));
  const value = await lbl.getText();
  assert.strictEqual(value,"5");

  await client.deleteSession();
}

まとめ

  • スクリーンショット取得方法は Appium 標準の saveScreenshot で良い
  • ただし、Device Farm 用のスクリーンショット保存先が用意(process.env.SCREENSHOT_PATH)されているので、保存先に注意すること

余談ですが、テストに失敗しても結果がグリーンになるのはちょっと問題です。
これについては別途対策をしてみたいと思います。