PlaywrightをRSpec, Capybara, Seleniumと組み合わせて使い、traceを出力する
環境
確認したのは以下のバージョン
- YusukeIwaki/playwright-ruby-client: Playwright client for Ruby 1.45.0
- YusukeIwaki/capybara-playwright-driver: Playwright driver for Capybara 0.5.2
- SeleniumHQ/docker-selenium: Provides a simple way to run Selenium Grid with Chrome, Firefox, and Edge using Docker, making it easier to perform browser automation 4.23.1
Playwrightを使いたい
なんで?
- Selenium と Capybara を使うテストで謎のエラーが起きるのがつらい
- Ruby と組み合わせたいので Cypress など JS 専用のものは避けなければいけない
- Puppeteer も同じ理由で候補から外れていたんだがいつの間にか YusukeIwaki/puppeteer-ruby: A Ruby port of Puppeteer なんてものができていた
- ただ Puppeteer チームが Playwright 作ってたんじゃなかったっけ?という理解
個人的にいちばん大きいのは
Fast and reliable end-to-end testing for modern web apps | Playwright より
Resilient • No flaky tests
Auto-wait. Playwright waits for elements to be actionable prior to performing actions. It also has a rich set of introspection events. The combination of the two eliminates the need for artificial timeouts - the primary cause of flaky tests.
Web-first assertions. Playwright assertions are created specifically for the dynamic web. Checks are automatically retried until the necessary conditions are met.
Tracing. Configure test retry strategy, capture execution trace, videos, screenshots to eliminate flakes.
この辺り。特に tracing は嬉しい。今までせいぜい画像や録画しかなかったが、ブラウザ上で起きていることをそのまま後で確認できるのは大きい。
基本的な仕組み
実現しているのは playwright - npm で、ブラウザも playwright 管理のものを使う。
Playwright 公式で対応していない言語は Playwright Client に使いたい言語でラッパーを用意する形になるようだ。
混乱しやすいdriverという用語
- Playwright driver
- Playwright server が実際にブラウザを操作するもの
- Capybara driver
- Capybara から見たブラウザを操作するライブラリ。実際には RackTest だったり Selenium (という名の WebDriver)だったり Playwright だったりする
- WebDriver
- ブラウザを操作する規格 cf. WebDriver
Rubyで使いたい
必要なもの
playwright client/server を実現しているのはあくまで npm のパッケージなので、gem だけでなく npm も必要。
基本的な使い方はこんな感じ。
browser = Playwright.create(
playwright_cli_executable_path: "./node_modules/.bin/playwright"
).chromium.launch # ここにchromiumが挟まるのイヤだなぁ
page = browser.new_page
page.goto "<URL>"
公式のサンプルは全部ブロックの中に入れてしまっていて扱いにくいが、別に全部ブロックの中に入れなければいけないわけではない。(ブロックを与えなければいけないものもある)
※ 2024-08 時点で確認したところ、npm で playwright をインストールしていない場合は npx
コマンド経由で自動的に playwright を呼び出す仕様になっているので、万全の Node.js 環境が動いているなら別途 npm をインストールしなくても問題なく動く。もしコンテナ環境など一部のバイナリしか存在しない場合はうまく動かないので注意が必要。
traceを使いたい
tracing をコントロールするメソッド群は BrowserContext が持っている
ので、上の基本のコードにちょっと手を加えて
browser = Playwright.create(
playwright_cli_executable_path: "./node_modules/.bin/playwright"
).chromium.launch
context = browser.new_context # <-
context.tracing.start(*opts) # <-
page = context.new_page
page.goto "<URL>"
browser と page の間に context が必要になる。オプションは確認しておくこと。どうもデフォルトでは screenshot は生成されないっぽい。
stop するまで記録されるので、テストケースごとに記録する場合はテストスイートの before / after, setup / teardown などにこれらのコードを記述する。
このエントリではのちほど RSpec と組み合わせる例を挙げる。
Capybaraと組み合わせたい
YusukeIwaki/capybara-playwright-driver: Playwright driver for Capybara
capybara driver を登録すると使えるようになる。最小限はこんな感じ。1
Capybara.register_driver(:playwright) do |app|
Capybara::Playwright::Driver.new(app)
end
あとは
Capybara.default_driver = :playwright
なり
Capybara.current_driver = :playwright
なりセットしたのちの動作が Playwright 経由になる。この辺りの切り替えの話は他の driver を使っている場合と同じ。
参考
Capybara があると既存のテスト資産の移行の際にはだいぶ助かるのだが、実は Capybara DSL が flaky テストの原因という話がある。
- Use Capybara without DSL | playwright-ruby-client
- PlaywrightをRailsのsystem specから使いたくてCapybaraドライバを作った - YusukeIwakiのブログ
- 「Capybara、お前はただサーバーを起動してくれたらいいんだ!」って思ったときの対処法
- CapybaraなしでRailsアプリのE2Eテスト(feature spec)を実行する
※ リンクはいくつもあるが、全部 capybara driver 作者が書いている
RSpecと組み合わせたい
これは Capybara との組み合わせの話もコミになってしまうんだけど、RSpec + Capybara は driver の情報について
RSpec の before / after が Capybara の session と紐づく形で設定されている
capybara の capybara/rspec.rb に以下のような記述がある。
config.after do
if self.class.include?(Capybara::DSL)
Capybara.reset_sessions!
Capybara.use_default_driver
end
end
config.before do |example|
if self.class.include?(Capybara::DSL)
Capybara.current_driver = Capybara.javascript_driver if example.metadata[:js]
Capybara.current_driver = example.metadata[:driver] if example.metadata[:driver]
end
end
何の話かというと、ここでさっきの tracing の話に戻ってくる。
- Capybara の driver の機能を使いたければ current_session の driver オブジェクトから呼び出す必要があり、特に trace の stop のリミットは after になる
- around は before の前、after の後に影響するので tracing 関係のコードは around の中には書けない
結論としては以下のようなコード例になる。
Rails のブラウザテストを Playwright で動かすようにしたらデバッグが簡単になって捗った #Ruby - Qiita
before で start_tracing を、after で stop_tracing を呼び出すべし。
Capybaraとの組み合わせを意図的に外す場合
上の Capybara の参考先に散々書かれているが、
実は Capybara DSL を利用するとせっかく Playwright を使っていても flaky になり得る。
そこで、意図的に Capybara を外すコードも利用できるようにしておくとよいのではないかと考えた。例えば以下のような感じ。
it "なにかのテスト", js: true, capybara: false do
end
it "なんらかのテスト", js: true, capybara: true do
end
設定はこんな感じ。
config.before do |example|
# この中だけ playwright 環境とする
if example.metadata[:js]
if example.metadata[:capybara]
Capybara.current_session.driver.start_tracing(*opts)
else
@context.tracing.start(*opts)
end
end
end
config.after do |example|
if example.metadata[:js]
if example.metadata[:capybara]
Capybara.current_session.driver.stop_tracing
else
@context.tracing.stop
end
end
end
デフォルトをどっちに倒すかは分量次第だと思うので、既存のテスト資産がある場合には capybara: true
がデフォルトになるようにしておくとよいかもしれない。
Seleniumと組み合わせたい
実は自分は Playwright は Selenium を置き換えてしまうんじゃないかと思っていたんだけど、Playwright はスコープをそこまで広げようと思っていないこと、Selenium も進化していることから、そういうことではないらしい。むしろ組み合わせて使うことができる。
Playwright はそもそもクライアントサーバモデルなのだが、Playwright client を Playwright server ではなく Selenium Grid に接続することでこれを実現する。
- 実は Selenium は 4 から CDP ( Chrome DevTools Protocol ) をサポートしている
- selenium/java/CHANGELOG at trunk · SeleniumHQ/selenium
- 4.0.0 Beta 3 2021-04 くらい?
- Playwright も feat(launch): connect to process.env.SELENIUM_REMOTE_URL instead of local launch by dgozman · Pull Request #9056 · microsoft/playwright 2021-09 辺りから対応済み
使い方は簡単。Playwright に対して環境変数
SELENIUM_REMOTE_URL
に接続先の URL をセットするだけ。実際の接続を行うのは npm の方の playwright なので、Ruby のコード内で
ENV["SELENIUM_REMOTE_URL"] = "<Selenium GridのURL>"
をセットすればオーケー。
この場合、ブラウザへの接続は playwright の責任範囲外なので、 playwright install
を実行しておく必要はない。(playwright-ruby-client が npm の playwright を呼び出すのは変わらないので、この部分の準備は必要。)
もちろん Selenium Grid 側も相応の準備が必要で、例えば
を使う場合、環境変数
SE_NODE_ENABLE_CDP
SE_ENABLE_TRACING
辺りが関係してくるのだが、幸い
selenium/standalone-chrome - Docker Image | Docker Hub
などの standalone image ではデフォルトで有効になっているようで、何の追加設定もなしにただ Selenium Grid に繋ぐだけで trace を含めて使うことができた。
※ Selenium の CDP サポートは WebDriver BiDi 実装が進むまでの仮扱いっぽいが、これはブラウザ対応の進み具合にもよると予想できる。CDP を利用するか WebDriver BiDi を利用するかを我々ユーザー側は気にすることなく、今後もそれなりの期間この組み合わせは動作しそう。
Chrome も出てきた当初はこういう設定をしていたなぁ ↩