$30 off During Our Annual Pro Sale. View Details »

ブラウザ自動操作技術の深層へ、直接触れて学ぶ WebDriver と Chrome DevTools Protocol

ブラウザ自動操作技術の深層へ、直接触れて学ぶ WebDriver と Chrome DevTools Protocol

ウェブアプリケーションの開発においてE2Eテストの自動化は身近なトピックです。SeleniumやPuppetter、PlaywrightやAppiumなどがブラウザ・ネイティブアプリの自動操作のOSSとしてよく挙げられます。しかし、それらの裏側はご存知でしょうか?

本トークではこれらのツールの背後にいるWebDriver、Chrome DevTools Protocolsに焦点を当てます。

WebDriver、CDPとはなにか、その違い、仕様について、PHPエンジニアに身近な言語を用いて"直接"実装することを通じて解説します。

本トークを通じて直接触れることでライブラリでwrapされている裏側まで知ることできます。E2Eテスト自動化の課題に出会ったときに「裏側がこうだからたぶんこういうことだよね」と想像できるようになる、少し世界の見え方が変わる時間を提供します。

Kazuki Higashiguchi

March 28, 2022
Tweet

More Decks by Kazuki Higashiguchi

Other Decks in Technology

Transcript

  1. ブラウザ自動操作技術の深層へ
    直接触れて学ぶ
    WebDriverと
    Chrome DevTools Protocol
    Kazuki Higashiguchi
    April 10, 2022 @ PHPerKaigi 2022

    View Slide

  2. Agenda
    1. WebDriver とは
    2. PHP で WebDriver binding をスクラッチ実装する
    3. Chrome DevTools Protocol (CDP) とは
    4. PHP で CDP binding をスクラッチ実装する

    View Slide

  3. About Me
    Kazuki Higashiguchi
    Backend Engineer of Autify
    AIを用いたソフトウェアテスト自動化プラットフォーム
    ID: @hgsgtk

    View Slide

  4. Autify Solution
    AIを用いたWeb/MobileアプリのE2Eテスト自動化サービス
    No codeで誰でも簡単 AIがメンテナンス
    デモリクエスト受付中 https://autify.com/ja/demo

    View Slide

  5. 01.
    WebDriverとは

    View Slide

  6. WebDriver
    ブラウザ*1
    を操作したり観察できる遠隔制御インターフェース
    *1 厳密にいうと、”User agent” という表現が正確です。操作対象はウェブブラウザに限定されません。たとえば Appium は
    WebDriver protocol を使用してモバイルアプリを操作します。
    例:
    - ウェブ文書内のDOM要素の検出・操作
    - ブラウザ動作の制御

    View Slide

  7. 中立なインターフェース
    プログラミング言語とプラットフォームに中立なインターフェース
    WebDriver interface
    …etc
    …etc

    View Slide

  8. プログラムから見たWebDriver
    WebDriver
    HTTP request
    HTTP response
    JSON ベースの HTTP API*1、各プログラミング言語でHTTP Clientを実装
    *1 WebDriver protocol では PHP 側を Local end 、WebDriver 側を Remote end と定義しています。

    View Slide

  9. ブラウザから見たWebDriver
    WebDriver interface *1
    ChromeDriver SafariDriver geckodriver IEDriver OperaDriver
    ※2
    *1 W3C勧告 によって、それぞれのドライバーが実装しなければならない API が定義されています。
    *2 モバイルアプリのテスト自動化フレームワークである Appium では iOS 用の XCUITest Driver など Appium 自身がメンテナ
    ンスする独自ドライバーを実装・提供しています。

    View Slide

  10. Selenium
    WebDriver*1
    仕様を使って、ブラウザを自動操作する
    ための仕組み
    - Selenium Grid: 並列実行を実現するインフラ
    - Selenium IDE:ブラウザ操作を自動記録し再生できるツール
    - Language bindings:各言語でのAPI実装
    - WebDriver
    *1 Selenium が使用するプロトコルは過去に使用されていた JSON Wire Protocol Specification と、現行の W3C
    specification の 2 種類があります。各 binding 実装の中身では、この2つの仕様それぞれに対応したコードがちらほら実装さ
    れていることが見れます。

    View Slide

  11. 02.
    PHP で WebDriver binding をスク
    ラッチ実装する

    View Slide

  12. PHPでWebDriver bindingを実装する
    JSON APIの仕様を読み解き
    ブラウザのライフサイクルを意識した
    APIクライアントを実装する

    View Slide

  13. 実装する自動化フロー
    ブラウザを開く ページ遷移 ボタンをクリック フォーム入力

    View Slide

  14. 実装した自動化コード
    * 今回の実装は https://github.com/hgsgtk/phpwd にて公開しています。

    View Slide

  15. デモンストレーション

    View Slide

  16. WebDriverを起動する
    ChromeDriverを使用する場合...
    ローカルで起動すると、
    ポート 9515 に、
    APIサーバーが立ち上がる*1
    *1 本例では、同一ホストシステムで立ち上げた ChromeDriver を直接使用する構成をとっていますが、 Remote WebDriver や
    Selenium Server(Grid) を用いる別のホスト内で立ち上げた WebDriver を使用する構成もあります(参考: Selenium
    components)。

    View Slide

  17. ブラウザを開く
    ブラウザを開く ページ遷移 ボタンをクリック フォーム入力

    View Slide

  18. PHPで実装する
    1. http://localhost:9515/session
    へ POST リクエスト*1を送信する
    2. ChromeDriverがブラウザを開く
    3. HTTPレスポンスが返却され
    Session Id が手に入る
    *1 W3C WebDriver プロトコルはこの一つの HTTP リクエストを Command と定義し、多くの Command 定義によって構成され
    ています。

    View Slide

  19. 開いたブラウザに対応するSession Id
    Session Element
    SessionID ElementID
    Session Id を指定してページ操作
    - DOM要素を取得
    - スクリーンショットを撮る
    - 前のページに戻る
    - 現在のURLを取得する
    - etc

    View Slide

  20. PHP 8.0 Constructor property promotion を使用した値クラス

    View Slide

  21. ページ遷移する
    ブラウザを開く ページ遷移 ボタンをクリック フォーム入力

    View Slide

  22. PHPで実装する
    /session/{sessionId}/url へPOSTリクエスト

    View Slide

  23. ボタンをクリック・フォーム入力
    ブラウザを開く ページ遷移 ボタンをクリック フォーム入力

    View Slide

  24. 要素を取得する
    1. 要素検索方法(LocatorStrategy)
    と検索値を用意
    2. /session/{sessionId}/element
    へ POST リクエスト
    3. HTTPレスポンスが返却され、
    Element Id が手に入る

    View Slide

  25. PHP 8.1 Enum を使用した列挙型

    View Slide

  26. 取得した要素に対応するElement Id
    Session Element
    SessionID ElementID
    Element Id を指定して要素操作
    - テキストの取得
    - クリック
    - 入力
    - etc

    View Slide

  27. ページ要素をクリック
    /session/{sessionId}/element/{elementId}/click へPOSTリクエスト

    View Slide

  28. フォームに入力する
    /session/{sessionId}/element/{elementId}/value へPOSTリクエスト

    View Slide

  29. 実装した自動化コード(再掲)
    * 今回の実装は https://github.com/hgsgtk/phpwd にて公開しています。

    View Slide

  30. 実装してみたくなったあなたへ、おすすめ資料集
    - Seleniumの公式ドキュメントで概要
    を理解する
    - テスト自動化プラットフォームのブロ
    グ(e.g. BrowserStack、SourceLab、Autify)
    WebDriverをもっと理解したい! 自分で実装してみたい!
    - WebDriver仕様のエンドポイント一
    覧で出来ることを知る
    - Curlでリクエストを送ってみる
    - php-webdriverなどbinding実装を
    読んでみる*1

    View Slide

  31. 03.
    Chrome DevTools Protocol とは

    View Slide

  32. Chrome DevTools Protocol (CDP)
    Chromium*1
    ・Chrome・その他Blink*2
    ベースのブラウザのデバッ
    グ用プロトコル
    *1 Chromium はオープンソースのブラウザプロジェクトです。 Microsoft Edge や Opera など多数のブラウザで利用されていま
    す。
    *2 Blink は Chromium によって利用されているレンダリングエンジンです。
    例:
    - ページ遷移やスクリーンショット取得等のブラウザ操作
    - JavaScriptカバレッジ等のプロファイル
    - パフォーマンスメトリクスの収集

    View Slide

  33. Chrome DevTools Protocolの使用例
    Chrome DevTools
    - Lighthouse ページのパフォーマンス・品質改善のため
    のツール
    - etc
    ブラウザオートメーションツール
    - Puppeteer
    - Playwright
    - Selenium 4 *1
    - etc
    *1 Selenium 4 にて、 Chrome DevTools Protocol に直接アクセスできる API getDevTools() と executeCdpCommand() が導
    入されました。

    View Slide

  34. プログラムから見たChrome DevTools Protocol
    HTTP request
    HTTP response
    WebSocketサーバー、各プログラミング言語でWebSocket clientを実装する
    API
    WebSocket connection

    View Slide

  35. ブラウザから見たChrome DevTools Protocol
    Chrome DevTools Protocol
    Remote
    protocol *1
    *1 FireFoxでは Remote Protocol という低レベルのデバッグインターフェースを提供しています。デバッガである Remote
    Debugging Protocol を補完する立ち位置で Chrome DevTools Protocol のサブセットを実装しています。
    Chromium-base

    View Slide

  36. 04.
    PHP で CDP binding をスクラッチ実
    装する

    View Slide

  37. PHPでCDP bindingを実装する
    WebSocketコネクション上で
    定義されたプロトコルに沿って
    メッセージを送受信する
    WebSocketクライアントを実装する

    View Slide

  38. 実装する自動化フロー
    タブを開く ページを開く
    ネットワーク
    トラッキングを有効化
    集計

    View Slide

  39. 実装した自動化コード
    * 今回の実装は https://github.com/hgsgtk/php-cdp にて公開しています。

    View Slide

  40. デモンストレーション

    View Slide

  41. リモートデバッグを有効にしてChromeを起動
    –remote-debugging-port=9222
    ポート 9222 に、APIサーバーが立ち上がる

    View Slide

  42. 実装する自動化フロー
    タブを開く ページを開く
    ネットワーク
    トラッキングを有効化
    集計

    View Slide

  43. タブを開く
    1. http://127.0.0.1:9222/json/new
    へGETリクエスト
    2. 新しいタブが開かれる
    3. HTTPレスポンスが返却される
    4. targetIdとwebSocketDebuggerUrl
    が得られる

    View Slide

  44. targetIdとwebSocketDebuggerUrl
    専用のWebSocket endpoint: /devtools/page/{targetId}
    例:ws://127.0.0.1:9222/devtools/page/7938D87B3D0A3C4D1F0F1F0D5706D297

    View Slide

  45. 実装する自動化フロー
    タブを開く ページを開く
    ネットワーク
    トラッキングを有効化
    集計

    View Slide

  46. WebSocket上でのコマンド送受信プロトコル
    JSON形式でリクエストとレスポンスを表現する JSON-RPC *1
    リクエスト
    Members: id, method, params
    *1 JSON-RPC は 1.0 と 2.0 の 2 つのバージョンがあり、2.0 ではリクエストの形式に id, method, param に加えて jsonrpc と
    いうメンバーが追加されています。 CDP のプロトコルは JSON-RPC 1.0 がベースとなっています。
    レスポンス
    Members: id, result, (error)

    View Slide

  47. ネットワークトラッキングを有効化
    WebSocketコネクションへ Network.enable コマンドを送信する

    View Slide

  48. WebSocket library in PHP
    リポジトリ Description
    ratchetphp/Ratchet 非同期のWebSocketサーバー
    Starred: 5.7K
    beyondcode/laravel-websoc
    kets
    Laravel用のWebSocketライブラリ
    Starred: 4.3K
    Textalk/websocket-php WebSocketクライアントとサーバー両方を提供
    Starred: 691
    現在も定期的なメンテナンスあり

    View Slide

  49. Textalk/websocket-phpを使用したWebSocketクライアント
    send() でメッセージを書き、
    receive() でメッセージを読む

    View Slide

  50. 実装する自動化フロー
    タブを開く ページを開く
    ネットワーク
    トラッキングを有効化
    集計

    View Slide

  51. ネットワークトラッキング有効化で得られる通知
    Experimentalな機能を含めて、
    30種類のEventが送られてくる

    View Slide

  52. 特定のイベントだけを購読したい
    例:ブラウザから送信されたリクエストを確認したい
    Network.requestWillBeSent のみ購読するリスナーを登録する

    View Slide

  53. リスナーを登録しメッセージ受信時に処理する
    No port specified
    リスナーを登録する
    - 購読したい Method
    - コールバック(Callable)関数

    View Slide

  54. リスナーを登録しメッセージ受信時に処理する
    No port specified
    特定の Method を受信すると、
    コールバック関数を呼び出す
    例:Network.responseReceivedExtraInfo

    View Slide

  55. 「HTTPレスポンスを受け取った」イベントだけを購読する
    Network.responseReceived のみ購読するリスナーを登録する

    View Slide

  56. PHP 8.1 : First class callable syntaxを用いたコールバック関数
    CallableExpr(...) という記法
    PHPの文法上直接コールできるあらゆる式で使える
    Callable から Closure*1 を生成する
    *1 Closure は無名関数を表すクラスです。

    View Slide

  57. 実装する自動化フロー
    タブを開く ページを開く
    ネットワーク
    トラッキングを有効化
    集計

    View Slide

  58. ページを開く
    Page.navigate コマンドを送信

    View Slide

  59. 実装した自動化コード(再掲)
    * 今回の実装は https://github.com/hgsgtk/php-cdp にて公開しています。

    View Slide

  60. コラム: プロトコル定義に基づくPHPコードの自動生成
    プロトコルAPIの定義ファイル*1
    - Domain: Page・DOM・Networkなど
    - Types: 型定義
    - Commands: Domain内で行える操作
    - Events: 送られるイベント
    例:browser_protocol.json
    *1 browser_protocol.pdl と js_protocol.pdl という2つの定義ファイルがあり、
    ChromeDevTools/devtools-protocol では JSON バージョンも公開されていま
    す。

    View Slide

  61. コラム: プロトコル定義に基づくPHPコードの自動生成
    jakubkulhan/chrome-devtools-protocol のアプローチ*1
    js_protocol.json
    JSON
    JSON
    protocol.json
    JSON
    browser_protocol.json
    定義ファイルを一つにまとめ PHPコードを生成
    クラスファイル群
    nette/php-generator
    コード生成スク
    リプト
    *1 dotNet や Go 等他言語でも同様のコード生成アプローチが取られています。

    View Slide

  62. 実装してみたくなったあなたへ、おすすめ資料集
    - CDPの公式ドキュメントで概要を理
    解する
    - Chrome-remote-interfaceや
    Puppeteerを使ってCDPに触れる
    - Chrome DevTools の Protocol
    monitor で流れるCDP req/resを眺
    める
    CDPをもっと理解したい! 自分で実装してみたい!
    - Getting startedを読んでプロトコ
    ルを理解する
    - Vanilla-protocol-viewerを活用し
    てコマンドを探す
    - jakubkulhan/chrome-devtools-pr
    otocolなど既存のPHP bindingを
    読んでみる

    View Slide

  63. ご視聴ありがとうございました
    デモリクエスト受付中 https://autify.com/ja/demo

    View Slide