状況
- PHPで作ったアプリのE2EテストをBehat+Minkで実装している
- アプリがモバイルでも動くかどうか確認する必要が出てきた
- Behat+Minkで作ったE2Eテストを、Android上のChromeを使って動かして、動作確認をしたい
大まかな仕組み
以下のようになる。 すでにMacbook上でChrome Driverを使ってE2Eテストを動かしているので、adb -> Android -> Chromeのところを準備すればOK。
Behat -> Mink -> Selenium -> Chrome Driver -> adb -> Android -> Chrome
動かすためにやったこと
- AndroidをWifi経由で操作できるようにする
- behat.ymlにAndroid用のプロファイルを追加
- Androidからアクセスできるよう、BeforeScenarioでMinkとアプリの設定を切り替え
- Chromeでのみ発生する要素をクリックできない問題に対処
以下、それぞれの説明
AndroidをWifi経由で操作できるようにする
Android 11以降は、Wifi経由で操作ができるようになる。それ以前だとUSB接続のみ。
USBは面倒なのでWifiで接続できるようにした。
Android Debug Bridge(adb) | Android デベロッパー | Android Developers
ハマった点
- Android Studioを最新にアップデートする
- 苦労した覚えはあるんだけどなんだったか忘れた
- ADBの接続コマンド
- 公式ドキュメントを見てやれば大丈夫
behat.ymlにAndroid用のプロファイルを追加
extra_capabilitiesにgoog:chromeOptionsのandroidPackageを入れるのがポイント。 base_urlについては後述。
android: extensions: Behat\MinkExtension: base_url: http://#localhostIP#:8090 selenium2: browser: chrome capabilities: extra_capabilities: goog:chromeOptions: androidPackage: com.android.chrome
Androidからアクセスできるよう、BeforeScenarioでアプリの設定を切り替え
通常、Macbook上ではlocalhostを使って接続しているので、URLは常に http://localhost で良いのであるが、AndroidからWifi経由で接続する場合は、IPアドレスを使って接続する必要がある。で、MacbookのIPアドレスは常に変わる。(固定しろよって話もあるが...)
ちょっと面倒だけど、毎回実行時にIPアドレスを取得して、Minkとアプリの設定を書き換えることにした。
RawMinkContextを継承しているクラスで以下のコードを、@BeforeScenario で実行すればOK。
$baseUrl = $this->getMinkParameter('base_url'); if (strpos($baseUrl, "#localhostIP#") > 0) { // IPアドレスを取得 $ipAddressesRC = preg_grep("/^192\./", gethostbynamel(gethostname())); $ipAdderss = array_shift($ipAddressesRC); // URLを書き換え $newBaseUrl = str_replace("#localhostIP#", $ipAdderss, $baseUrl); // 全てのContextに設定を反映 $environment = $scope->getEnvironment(); foreach ($environment->getContexts() as $context) { if ($context instanceof \Behat\MinkExtension\Context\RawMinkContext) { $context->setMinkParameter('base_url', $newBaseUrl); } } }
ポイントは $environment = $scope->getEnvironment();
以降のコード。
利用している全てのContextに対して、設定を変更する必要がある。
上記で変更したURLを使って、アプリの設定を書き換えればOK。コードは省略。
Chromeでのみ発生する要素をクリックできない問題に対処
ここまでで実行するだけならできる...んだけど、テストが通るようにするために、Chrome特有の問題に対応する必要があった。
問題とは以下のもの。画面外にある要素をクリックしようとするとエラーになる。
seleniumにてButtonがクリックできない時の対処法 - Qiita
解決方法は難しくない。Clickの前に上記のエントリにあるようにスクロールをするか、フォーカスしてあげればOK。
カスタムのContextを使っている場合は、コードにスクロールなり、フォーカスするコードを追加すればよい。
私は、カスタムのContextに加えて、Behat\MinkExtension\Context\MinkContext も使っていたので、メソッドをオーバーライドしてフォーカスするコードを追加した。以下のような感じ。クラスの名前がやっつけすぎるな...。
class MyMinkContext extends MinkContext implements TranslatableContext { public function clickLink($link) { $link = $this->fixStepArgument($link); $elem = $this->getSession()->getPage()->findLink($link); $elem->focus(); $elem->click(); }