フューチャー技術ブログ

クライアント/サーバ構成でみるPlaywright

Playwright連載6日目です。

はじめに

Playwrightはさまざまな言語でテストを記述することが可能です。

公式ドキュメントを見ると JavaScript/TypeScript をはじめとし、Python / Java / .Net がサポートされていることがわかります。
そのほかにもGoRubyといった言語もサードパーティ製の実装によって利用することが可能です。

このように幅広い言語をサポートしているのは利用者としてとても嬉しいことです。

今回はこのような他言語展開を可能にしているPlaywrightのアーキテクチャについて調べました。

環境情報

本記事執筆時点のPlaywrightの最新バージョンはv1.37.1であり、本記事の内容及び参照しているドキュメントやソースコードは当該バージョンのものを前提としています。

Playwright Architecture

通常のテストランナーを利用する場合、あまり意識することはないのですが、Playwrightはクライアント/サーバの構成で動作させることが可能です。

なぜ意識することがないかというと、通常のテストランナーにおいては明示的に指定をしない限りクライアントとサーバはプロセスとして分離せず、同一のプロセスで動作するためです。

クライアント/サーバ構成のイメージは下記の通りです。

Playwright_Architecture

サーバ側はWebSocketまたは標準入出力の口をもち、クライアントからのリクエストに応じて各ブラウザに対しての操作を実行します。クライアント側はテストスクリプトに応じてサーバに対してリクエストを送信します。

図を見ればわかるとおり、クライアント側はPlaywrightが定めるリクエスト/レスポンスの形式に従ってWebSocket通信を行うことができればE2Eテストが実行なため、複数言語のサポートが容易となっています。

クライアント/サーバ構成のE2Eテストツールと聞くとSeleniumが有名ですが、こちらも同じく複数の言語をサポートするよう設計されています。

ただし、PlaywrightはSeleniumよりも遥かに効率的かつ高速に動作するよう設計されており、通常のテストランナーにおいてクライアントとサーバを分離せずに実行できるような作りになっているのは良い点だと言えそうです。

Playwright CLI

Playwright CLIのソースコードを読むと、公開されていないCLIのコマンドがいくつかあります。その中でもサーバを起動するコマンドは下記の3つとなります。

簡単に違いを説明します。

run-driver

標準入出力を通信経路とするPlaywright Serverを起動します。

内部実装はこのあたりを見るとJSON形式のメッセージを標準入出力でやりとりしていることがわかります。

$ npx playwright run-driver -h
Usage: npx playwright run-driver [options]

Options:
-h, --help display help for command

run-server

このコマンドはWebSocketを通信経路とするPlaywright Serverを起動します。

$ npx playwright run-server -h
Usage: npx playwright run-server [options]

Options:
--port <port> Server port
--path <path> Endpoint Path (default: "/")
--max-clients <maxClients> Maximum clients
--mode <mode> Server mode, either "default" or "extension"
-h, --help display help for command

内部実装はこのあたりを見ると、JSON形式のメッセージをWebSocketでやりとりしていることがわかります。

launch-server

このコマンドはWebSocketを通信経路するPlaywright Serverを起動します。
run-server との違いとして run-server コマンドは複数のブラウザに対応したサーバを起動するのに対し、本コマンドは単一のブラウザに対応したサーバを起動します。

コマンドのオプションを見てもわかる通りブラウザの指定が必須となっています。

$ npx playwright launch-server -h
Usage: npx playwright launch-server [options]

Options:
--browser <browserName> Browser name, one of "chromium", "firefox" or "webkit"
--config <path-to-config-file> JSON file with launchServer options
-h, --help display help for command

クライアント/サーバ構成でのテスト実行

npm init playwright@latestで作成した初期プロジェクトでテストを実行します。

サーバサイド

run-serverコマンドを利用してPlaywright Serverを8008ポートで起動します。
なお、サーバ側のログを出力するため環境変数DEBUG=pw:serverを指定します。

$ DEBUG=pw:server npx playwright run-server --port 8008
Listening on ws://127.0.0.1:8008/

クライアントサイド

playwright.config.ts を編集し、connectOptionsに接続先となるws://localhost:8008/を指定します。

export default defineConfig({
// (省略)
use: {
connectOptions: {
wsEndpoint: "ws://localhost:8008/",
},
},
});

テストを実行すると6ケースのテストがパスします。

$ npx playwright test
Running 6 tests using 4 workers
6 passed (8.2s)

サーバ側のログを見ると6ケース(3ブラウザ * 2ケース)のテストのログが出力されていることがわかります。

ログを見る
pw:server [1] serving connection: / +34s
pw:server [2] serving connection: / +3ms
pw:server [3] serving connection: / +2ms
pw:server [1] engaged launch mode for "webkit" +12ms
pw:server [4] serving connection: / +7ms
pw:server [3] engaged launch mode for "chromium" +2ms
pw:server [2] engaged launch mode for "webkit" +2ms
pw:server [4] engaged launch mode for "chromium" +89ms
pw:server [2] disconnected. error: undefined +3s
pw:server [2] starting cleanup +1ms
pw:server [2] finished cleanup +74ms
pw:server [1] disconnected. error: undefined +147ms
pw:server [1] starting cleanup +0ms
pw:server [1] finished cleanup +56ms
pw:server [5] serving connection: / +325ms
pw:server [5] engaged launch mode for "firefox" +8ms
pw:server [6] serving connection: / +259ms
pw:server [6] engaged launch mode for "firefox" +14ms
pw:server [6] disconnected. error: undefined +3s
pw:server [6] starting cleanup +1ms
pw:server [5] disconnected. error: undefined +622ms
pw:server [5] starting cleanup +0ms
pw:server [6] finished cleanup +234ms
pw:server [5] finished cleanup +247ms
pw:server [3] disconnected. error: undefined +37s
pw:server [3] starting cleanup +1ms
pw:server [3] finished cleanup +35ms
pw:server [4] disconnected. error: undefined +22s
pw:server [4] starting cleanup +0ms
pw:server [4] finished cleanup +37ms

別言語のクライアントはどうなっているのか

各クライアントは実行時にPlaywrightのドライバをダウンロードし、run driverすることでPlaywright Serverを立ち上げてテストを実行しているようです。

Playwrightのドライバはhttps://playwright.azureedge.net/builds/driver/playwright-${version}-${platform}.zipの形式でバージョンとプラットフォームを指定することでダウンロード可能です。
例. https://playwright.azureedge.net/builds/driver/playwright-1.37.1-mac.zip

例えば playwright-python を見てみるとこのあたりでドライバをダウンロードし、このあたりrun-driverをサブプロセスで実行しています。

なおこのドライバは実行環境にNode.jsランタイムがなくとも実行可能なバイナリとして配布されているため、例えば playwright-python を利用してテストを実行する場合はPythonの実行環境さえあれば良ということになります。

おわりに

普段使う分にはあまり意識することのないPlaywrightのアーキテクチャのお話でした。

本記事で説明している内容の多くが公式のドキュメントでは明文化されていないため、筆者もソースコードを追いながら理解した結果をまとめています。そのため将来的なバージョンアップにより本記事記載の内容が変更されることも十分にあり得ることをご了承いただけますと幸いです。

もし内容に不備や補足等ありましたらSNSやこちらでご意見いただけますと幸いです。