準備

Playwrightでネイティブアプリをテストするには、以下の準備が必要。

Android Studioのインストール

adbコマンドなどのエミュレータ操作に必要なAndroid SDK Platform Toolsをインストールするため、Android Studioをインストールする。
Android Studioをダウンロードして起動すると必要なツールは自動でインストールされる。

エミュレータか実機の準備

Androidエミュレータか実機を用意する。
エミュレータを使う場合はAndroid Studioをインストールしてエミュレータを起動するのが簡単。

Playwrightプロジェクトの作成

Playwrightプロジェクトを作成する。

npm init playwright@latest

メッセージに従ってプロジェクトを作成する。

本記事では言語にTypeScriptを選択し、テストコードを格納するディレクトリにはtestsを指定する。

設定ファイルの修正(playwright.config.ts)

Playwrightの設定ファイルplaywright.config.tsを修正する。

projectsにAndroidの設定を追加する。

  projects: [
    {
      name: 'android-emulator'
    }
  ],

ドライバのインストール

以下のコマンドを実行する。

npx playwright install android

テスト対象プログラムの作成

本記事では確認のため、Android Studioでテストアプリを作成する。
既存アプリがある場合は不要。

パッケージ名はcom.example.sampleapp、アプリ名はSampleAppとする。

テンプレートはBasic Views Activityを選択する。

生成されたプロジェクトをエミュレータか実機で実行しておく。

Basic Views Activityは2画面から構成され、起動した画面のNextボタンをタップすると次の画面に遷移し、Previousボタンをタップすると前の画面に戻る。

テスト対象アプリ テスト対象アプリ

テストコードの作成

testsディレクトリにテストコードを作成する。
プロジェクトinit時にtests/example.spec.tsが作成されているので、そのファイルを修正する。

import { test, _android, expect } from '@playwright/test';

test('サンプルテスト', async ({ }) => {
  const [device] = await _android.devices();

  // アプリを落としてから起動
  await device.shell('am force-stop com.example.sampleapp');
  await device.shell('am start com.example.sampleapp/.MainActivity');
  await device.wait({ enabled: true });

  // スクリーンショットを保存する
  await device.screenshot({ path: 'images/sample1.png' });

  // Nextボタンをタップ
  await device.tap({
    text: 'Next',
    clickable: true,
  })
  await device.wait({ enabled: true });

  // Previousボタンが表示されていることを確認
  await expect(
    (await device.info({ res: 'com.example.sampleapp:id/button_second' })).text
  ).toContain('Previous');

  // スクリーンショットを保存する
  await device.screenshot({ path: 'images/sample2.png' });

  // Previousボタンをタップ
  await device.tap({
    text: 'Previous',
    clickable: true,
  })
  await device.wait({ enabled: true });

  // Nextボタンが表示されていることを確認
  await expect(
    (await device.info({ res: 'com.example.sampleapp:id/button_second' })).text
  ).toContain('Previous');

  // スクリーンショットを保存する
  await device.screenshot({ path: 'images/sample3.png' });
});

アプリの起動

以下のコードでアプリを起動している。

  await device.shell('am force-stop com.example.sampleapp');
  await device.shell('am start com.example.sampleapp/.MainActivity');
  await device.wait({ enabled: true });

既にアプリが起動しているとエラーになるので、am force-stopコマンドでアプリを落としてから起動している。
引数にはアプリのパッケージ名を指定する。
今回はプロジェクト作成時にcom.example.sampleappを指定したのでこのパッケージ名を指定している。

既存のアプリなどで端末にインストールされているパッケージ名の一覧は以下のコマンドで確認できる。

adb shell pm list packages

am startコマンドの引数には<パッケージ名>/<アクティビティ名>を指定する。

アクティビティ名はAndroidManifest.xml<application>タグ内の<activity>タグのandroid:name属性の値を確認する。
Basic Views Activityの場合はMainActivityが指定されている。

waitメソッドで待たせないとアプリが起動する前に次の処理が実行されるため、アプリが起動するまで待機させている。

スクリーンショットの保存

スクリーンショットを保存するにはscreenshotメソッドを使用する。

  await device.screenshot({ path: 'images/sample1.png' });

呼び出したタイミングの端末の画面をスクリーンショットとしてpathに指定したパスへ保存する。

画面操作

tapメソッドで画面をタップする。

  await device.tap({
    text: 'Next',
    clickable: true,
  })
  await device.wait({ enabled: true });

ta@メソッドの引数にはタップしたい要素を指定する。
引数の型はAndroidSelectorで以下のように定義されている。

export type AndroidSelector = {
  checkable?: boolean,
  checked?: boolean,
  clazz?: string | RegExp,
  clickable?: boolean,
  depth?: number,
  desc?: string | RegExp,
  enabled?: boolean,
  focusable?: boolean,
  focused?: boolean,
  hasChild?: { selector: AndroidSelector },
  hasDescendant?: { selector: AndroidSelector, maxDepth?: number },
  longClickable?: boolean,
  pkg?: string | RegExp,
  res?: string | RegExp,
  scrollable?: boolean,
  selected?: boolean,
  text?: string | RegExp,
};

今回はNextボタンが現れるまでを条件とした。

タップ後はwaitメソッドで次の画面が表示されるまで待たせている。

tap以外のメソッドについては APIドキュメント(AndroidDevice | Playwright) を参照。

アサーション

expectメソッドでアサーションを行う。

  await expect(
    (await device.info({ res: 'com.example.sampleapp:id/button_second' })).text
  ).toContain('Previous');

infoメソッドで指定した要素の情報を取得できる。
引数はtapメソッドと同じくAndroidSelectorを指定する。
ここではresでリソースIDを指定している。

テストの実行

以下のコマンドでテストを実行する。

npx playwright test

成功すれば以下のようなメッセージが表示される。

Running 1 test using 1 worker
  1 passed (3.0s)

To open last HTML report run:

  npx playwright show-report