はじめに
こんにちは、鷹野です。
本日、4月1日。社会人2年目に突入しました!
「新人なので!」という魔法の言葉が使えなくなる不安もありますが、そんなことも言っていられません。
新年度一発目のアウトプットを始めます!
今回のテーマは、PlaywrightによるAndroid実機テストです。
PlaywrightのAndroidサポートは、公式ドキュメントでも Experimental(実験的)な機能として位置付けられており、情報の少ない領域です。
情報が少ないからこそ、実際に試してわかったことをまとめました。
Androidサポートは「Experimental」です
上記でもあるようにPlaywrightのAndroidサポートは、公式ドキュメントでも Experimental(実験的)な機能として位置付けられています。APIの破壊的変更の可能性や、一部の高度な機能が未実装である場合があるため、その点をご理解の上、読み進めていただければ幸いです。
今回の取り組み:PlaywrightでAndroid実機を動かしたい!
改めてPlaywrightといえば「PCブラウザのテスト」というイメージが強いですが、実はAndroidの実機でe2eテストを動かすためのAPIが用意されているのはご存知でしょうか。
私自身配属されてから自動テスト導入のためにPlaywrightに関する調査や実装をしてきており、存在自体は知っていました。
しかし、ネットで調べても情報が少なく、あったとしても数年前の古い記事ばかりで後回しにしてきていました。
じゃあなぜ今やるのか
理由は大きく2つあります。
一つは現場の課題への挑戦、もう一つは極めて個人的な衝動です。
1. 膨大なサポート機種による「検証コスト」からの救済
昨年度のOJTでは「テスターの負担を減らしたい」という要望からPlaywrightの導入を目指して業務を進めていました。
今年度はさらなる自動化を目指そうと思った時に、以前にQAチームの方に言われた実機操作を取り組んでみようと思いました。
現在の案件では「え、その古いOSまだサポートしてるの!?」という状況下で、新機能のたびに多種多様な端末を手作業で確認するのは負荷が高くなってしまっています。全ての検証を自動化するのは魔法でもない限り不可能ですが、一部対象端末のテストだけでも自動化できれば、テスト工程の負担を劇的に減らせるはずです。そんな「現場の救済」の第一歩として、今回の調査を本格的に始めました。
2. 眠れる「かつての相棒たち」が、私を呼んでいたから
私は、スマホを持ち始めてから今日まで、Android一筋で生きてきました。
整理をしていたら、引き出しの奥から歴代の相棒たちがゾロゾロと出てきたのです。
「まだ動くのに、このまま眠らせておくのは忍びない……」
「Playwrightなら、彼らにテスト端末としての新しい命を吹き込めるのでは?」
「そこに相棒たちがいたから。やるしかねえ。」
2年目という節目に、自分自身のAndroid愛と向き合うための検証でもあります。
環境構築
1. Playwrightの導入
以下のコマンドでPlaywrightをインストールします。
npm init playwright@latest
TypeScriptかJavaScriptのどちらを使うか聞かれるので選択します。(自分はTypeScriptを選択) その後、色々聞かれますが、特にこだわりがなければそのまま承認し続けて良いです。 全て承認後にインストールが始まります。
インストールが完了したらplaywright.config.tsを編集します。デフォルトではchromiumやfirefox、webkitを利用してテストする設定が書かれていますが、今回は実機を用いてテストできるのかを検証するためその設定を削除します。
以下に自身の設定を記載します。
import { defineConfig, devices } from '@playwright/test';
/**
* Android実機テスト用の設定
*/
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: 3,
workers: 1,
reporter: [["html", { host: "0.0.0.0", port: "9324", open: "never" }]],
use: {
trace: 'on-first-retry',
screenshot: "only-on-failure",
},
});
Playwrightの準備は以上で完了です。
2. Android実機の用意
先ほども述べた通り、今回は自宅に眠っていたAndroid端末使用します。
今回の検証でのエントリーしたスマホたちは以下の通りです。
| 端末名 | OSバージョン | 備考 |
|---|---|---|
| Galaxy S24 Ultra | Android 16 | メイン機 |
| OPPO Find X3 Pro | Android 13 | 先代 |
| isai LGV35 | Android 9 | 先先代 |
| URBANO KYV34 | Android 5.1 | 先先先代 |
|
|
実機がない!という方へ
「iPhoneしかないよ!」という皆様、ご安心ください。
Android Studioのエミュレータでも、同様の手順で動かすことが可能です。
エミュレータを起動して、adb devicesで認識されていれば、Playwrightからは実機と同じように見えます。ぜひお試しくださいませ!
Android実機の下準備
① Android SDK(Platform-Tools)のインストール
あらかじめPCに ADB (Android Debug Bridge) をインストールし、パスを通しておいてください。
② 開発者オプションの解放
ここからの操作は自己責任でお願いします。
端末を「開発者モード」にします。ビルド番号を連打するアレですね。
開発者モードが解放されたら、開発者向けオプションからUSBデバッグをONにしてください。
接続確認
端末をPCに接続し、コマンドプロンプトやターミナルで adb devices と入力して、自分のデバイスが表示されるか確認しておきましょう。ここで認識されないと、Playwrightからも操作できません。
③ Chromeのコマンドライン有効化
ここが重要です。
AndroidのChromeで chrome://flags にアクセスし、「Enable command line on non-rooted devices」を Enabled に設定してください。これを行わないと、PlaywrightからChromeを制御できません。設定変更後は、必ず画面下の [Relaunch] を押して再起動するのを忘れずに!
実装・動作風景
準備ができたので、コードを書いていきます。
まずは、PlaywrightがAndroidデバイスを認識できるかテストします。
example.spec.tsの中身を以下のコードに書き換えます。
import { test, _android } from '@playwright/test';
test('デバイス接続テスト', async () => {
const devices = await _android.devices();
console.log(`接続デバイス数: ${devices.length}`);
for (const device of devices) {
console.log(`接続成功! モデル名: ${device.model()} シリアル: ${device.serial()}`);
await device.close();
}
});
PCとスマホを繋いで実際に実行してみます。
Playwrightのテスト実行は以下のコマンドで行います。
npx playwright test
ポートと自前のケーブルが許す限り多くの端末を接続した場合も全て認識してくれました。

ではここから実際にブラウザ操作をやってみましょう。
複数の端末でChromeを開き、Playwrightのドキュメントを検索する動作をさせてみます。
デモ用のコードはCopilotに実装してもらいました。
// tests/androidTest.spec.ts
import { test, _android, type Page } from '@playwright/test';
/**
* 接続中の全デバイスで Chrome を起動し、テスト関数を並列実行する
*/
async function onAllDeviceBrowsers(
testFn: (page: Page, deviceName: string) => Promise<void>,
) {
const devices = await _android.devices();
console.log(`接続デバイス数: ${devices.length}`);
await Promise.all(
devices.map(async (device, i) => {
const modelName = device.model();
const name = `device${i + 1}_${modelName}`;
console.log(`[${name}] テスト開始`);
await device.shell('am force-stop com.android.chrome');
const context = await device.launchBrowser({
args: ['--disable-blink-features=AutomationControlled'],
});
try {
const page = context.pages()[0] || await context.newPage();
await testFn(page, name);
} finally {
await context.close();
await device.close();
}
console.log(`[${name}] テスト完了`);
}),
);
}
test('Chromeで検索してスクリーンショットを撮る', async () => {
await onAllDeviceBrowsers(async (page, name) => {
// Google で検索
await page.goto('https://www.google.com');
await page.locator('textarea[name="q"]').fill('https://playwright.dev/docs/api/class-android');
await page.keyboard.press('Enter');
await page.waitForLoadState('load');
// 検索結果のスクリーンショットを保存(ファイル名に使える文字のみに調整)
const path = `test-results/android-search-result-${name}.png`;
await page.screenshot({ path });
console.log(`[${name}] スクリーンショット保存: ${path}`);
});
});
また、実機で動作させた場合でもテスト画面のスクリーンショットを撮影することができていました!

このほかにも色々コードを試してみた総括を以下にまとめます。
| 端末名 | OSバージョン | 動作結果 |
|---|---|---|
| Galaxy S24 Ultra | Android 16 | OK |
| OPPO Find X3 Pro | Android 13 | OK |
| isai LGV35 | Android 9 | OK |
| URBANO KYV34 | Android 5.1 | ブラウザは開いたがabout blankのまま動かず |
動かしてみた感想
1. 「実機の壁」は意外と低かった
情報が少なかったということもあり、Playwrightによる実機の自動テストは難しそうだと後回しにしていましたが、デバッグ設定済みのスマホさえあれば、数行のコードでブラウザ制御が始められる点に感動しました。
2. OSバージョンの境界線
検証結果のまとめ
| OSバージョン | 動作状況 | 判定 |
|---|---|---|
| Android 9〜16 | ブラウザ起動・操作・スクショ共に問題なし | 実用圏内 |
| Android 5.1 | ブラウザは開くが、操作を受け付けない | 非対応 |
今回の検証結果から、「Android 9 以降であれば、最新のPlaywrightでも十分に実機テストを自動化できる」と言えそうです。
もちろん、さらに古い端末(Android 6〜8など)でも動く可能性はありますが、検証の手間や動作の安定性を考えると、Android 9〜10あたりをサポートの基準点にするのが、現実的な判断になりそうです。
おわりに
今回は、Playwrightを使ったAndroid実機の自動テストに挑戦しました。
まだ実験的な機能ではありますが,実際に動かしてみると簡単に複数端末を同時にテストできる環境を整えることができました。
また,「多端末検証」という重い課題に対して、強力な解決策になり得るなと感じました.
全ての業務を自動化するのは難しいですが、少しずつ自動化できる部分を増やしていくことで、自分たちの環境をより良くできたらいいなと思います。
そして何より、引き出しの奥で眠っていた「かつての相棒たち」に、新たな役割を与えられたことが嬉しかったです。おそらく救い出せたことでしょう。
社会人2年目も新しいことに挑戦しながら着実に成長できる一年にしていきます。
最後まで読んでいただきありがとうございました!

