この記事は、ソフトウェアテスト Advent Calendar 2022の11日目の記事となります。
前日11日の記事は、@gremito さんによる「Appium on Azure Pipelines」でした。本日の記事もアプリの自動操作関連です。
概要
ChromeやWebKitを自動操作できるPlaywrightはもう皆さんご存知ですよね?
PlaywrightにはAndroidを自動操作する機能が実は備わっていて、AndroidネイティブアプリケーションもChromeブラウザも自動操作することができます。
ただ、これまではPCに直接ADB接続されているAndroidデバイスしか自動操作することができませんでした。
ところが、割と最近リリースされたv1.28では launchServer
(ADB接続したAndroidデバイスをWebSocket経由で自動操作する機能)が追加されました。これにより、デバイスファームのような使い方もできるようになりました。
「これはAppium以外の選択肢がもう一つできたのでは?」と思い、実際に触ってみました。
インストール&準備
$ npm install playwright-core
するだけです。(ブラウザをダウンロードする必要がないのでplaywrightではなくplaywright-coreを選択しています。)
https://playwright.dev/docs/api/class-android の冒頭に書かれているように
まずはAndroidはエミュレータでも実機でもいいのでADB接続できる状態にしておきます。
% adb devices
List of devices attached
emulator-5554 device
そして、AndroidのChrome上で chrome:flags
を打ち、コマンドラインアクセスを有効化します。
まずは単体で自動操作してみる
const playwright = require('playwright-core')
playwright._android.devices().then(async ([device]) => {
const browserContext = await device.launchBrowser()
const page = await browserContext.newPage()
await page.goto('https://playwright.dev/')
console.log('Taking browser screenshot')
await page.screenshot({ path: 'playwright.dev.png' })
console.log('Taking device screenshot')
await device.screenshot({ path: 'device.png' })
await browserContext.close()
await device.close()
})
% node standalone.js
Taking browser screenshot
Taking device screenshot
playwright.dev.png | device.png |
---|---|
page.screenshotはブラウザのキャプチャなのに対し、device.screenshotはADBのスクリーンショット機能を使っているようですね。
サーバーを起動する
いよいよネットワーク越しに自動操作するためのサーバーを立てます。
とはいえ、全然大したコードではありません。
const playwright = require('playwright-core')
playwright._android.launchServer({ port: 12345, wsPath: 'my-emulator' }).then(server => {
console.log(`Android server is now available! -> ${server.wsEndpoint()}`)
})
% node server.js
Android server is now available! -> ws://127.0.0.1:12345/my-emulator
ちなみに、portもwsPathも省略できますが、省略すると以下のようにランダムなポート、ランダムなパス文字列になります。
% node server.js
Android server is now available! -> ws://127.0.0.1:60633/159d66315e21098a73ce0f0142c12fc7
ランダムでは、クライアント側のコードをいちいち変えないといけないので、デバイスファームのような使い方をするにはちょっと面倒です。なので(Playwright公式のグリッド機能を使わないなら)portとwsPathオプションは付けておくと良さそうです。
クライアントから接続する
まずは、さっきの単体実行のコードをベースに、WebSocket接続で同じことをやってみます。
const playwright = require('playwright-core')
playwright._android.connect('ws://localhost:12345/my-emulator').then(async (device) => {
const browserContext = await device.launchBrowser()
const page = await browserContext.newPage()
await page.goto('https://playwright.dev/')
console.log('Taking browser screenshot')
await page.screenshot({ path: 'playwright.dev.png' })
console.log('Taking device screenshot')
await device.screenshot({ path: 'device.png' })
await browserContext.close()
await device.close()
})
% node client.js
Taking browser screenshot
Taking device screenshot
playwright.dev.png | device.png |
---|---|
まぁ当然同じ結果です。何の面白みもありません。
Dockerコンテナでサーバーに接続してみる
どうせならADBの入っていない環境で違うクライアントから接続してみましょう。
Playwright公式のDockerイメージを取ってきます。
% docker pull mcr.microsoft.com/playwright:v1.28.0-focal
% docker run -it --rm -v $(pwd):/app -w /app mcr.microsoft.com/playwright:v1.28.0-focal bash
root@8313fa40b980:/app# npm install playwright-core
接続先だけ、Dockerから見たサーバーの場所に変えます。
const playwright = require('playwright-core')
playwright._android.connect('ws://host.docker.internal:12345/my-emulator').then(async (device) => {
あとは、実行してみると...
root@8313fa40b980:/app# adb
bash: adb: command not found
root@8313fa40b980:/app# node client.js
Taking browser screenshot
Taking device screenshot
ADBのない環境でも無事、自動操作でスクリーンショットがとれました。
playwright.dev.png | device.png |
---|---|
まとめ
Playwrightを使うと、SeleniumやAppiumを使うのにに比べて、とてもかんたんにAndroidのアプリ/ブラウザを操作することができます。
また、Playwright 1.28以降ではWebSocket接続でサーバー/クライアント接続ができるようになり、クライアント側にはADB不要で、サーバーをデバイスファームのようにして使うことができるようになりました。
まだ知らなかった方は一度ためしてみてはいかがでしょうか。