これは ドリコム Advent Calendar 2021 の19日目です。
18日目は 小林航大 さんの Client Hints の最新情報を追ってみた です。

はじめに

初めましての方は、初めまして。
そうでない方はどうも、私です。
情報システムグループの「なかはらつ」です。

昨年のアドベントカレンダーでは「情シスのぽちぽち作業を駆逐している話」というタイトルで、RubyとSeleniumを使って手作業を自動化している話を書きました。

今年は、上記の中で使っていたSeleniumをアップデートしたらテストが盛大に動かなくなったので色々調べつつ対応したよ、という話を書いていきます。
タイトルは盛っています。

Seleniumとは

ざっくりゆるふわに書くと、ブラウザ操作をスクリプトとして記述できるツールで、Webサービス等のテストで使われるものです。
JavaやRubyなど様々な言語から利用可能であり、操作可能なブラウザもChromeやFirefoxの他にSafariなども対応可能となっていて便利なやつです。
参考:https://www.selenium.dev/documentation/getting_started/installing_browser_drivers/#quick-reference

なんで情シスの人がSeleniumなんて使ってるんじゃ

昨年のアドベントカレンダーで書いた「情シスのぽちぽち作業を駆逐している話」の通り、人がわざわざ行わなくても良いような単純作業をRubyとSeleniumを使ってよしなに自動化するために使っています。
API使えよ、と強いエンジニアの方から怒られてしまいそうですが、利用しているサービスの中には管理者権限でAPIが実行できないものがあったり、そもそもAPIが公開されていないものがあったりと辛い日々を過ごしています。

Selenium4

さて、本題のSelenium4についてみていきます。
以下3系・4系のようにメジャーバージョンだけ表記します。
なお、3系v3.142.74系v4.0.3を想定しています。

また、前述の通りRuby+Selenium環境なので、視点はRuby基準です。 今回メジャーアップデートだけあって、変更点は多いようです。
ざっくり公式の「Announcing Selenium 4」を見ながら要所をリストにしてみると、以下のようなものが追加されているようです。
  • Relative locators
    • 複雑なセレクタ使わずに、ある要素の隣にある要素、というような相対的な位置で指定できる機能
    • 便利そうではあるが、結局構造が変わると書き直しになるので、どこまで使えるのか気になるところ
  • BiDi APIs
    • WebDriver BiDirectional Protocol」というブラウザとクライアントの双方向通信のためのプロトコル整備が進んでいるようで、その辺の対応が入ったようです
    • この中で、Basic認証・DOMの変化を検知する機能・JSのエラー検知など、多くのことができるようになったようで便利そうな印象だが、きちんと中身を追いきれていない
  • Selenium Gridの作り直し
    • ZaleniumやSelenoidなどを参考に作り直したようです
    • 使っていないのと、変更前のものもよくわかっていないので「そーなのかー」と読み飛ばしています
  • その他の細かいところ
    • Element#screenshotのサポート
    • Chromium版Edgeのサポート
    • Firefoxでのフルページのスクリーンショットをサポート
    • 初期化時にオプション周りのオブジェクトの渡し方が変更
    • 最低要求バージョンがRuby2.6に変更
ここから、実際のコードの話に移っていきますが、
今回影響があったのは「細かいところ」にある「初期化時にオプション周りのオブジェクトの渡し方が変更」の部分でした。

手元の修正前と修正後のコード

公式の「Announcing Selenium 4」に、おかしなコードを書いていなければアップデートは簡単だよ〜、と書かれていたので無邪気にアップデートしてみたら、テストの大半が失敗しました。悲しい。 どこが悪いんじゃ、と思いながら「How to upgrade to Selenium 4」やCHANGELOGと自分のコードを見ていきました。
結果として、修正箇所は以下の通り。

# 変更前 (v3.142.7)
@driver = Selenium::WebDriver.for(:chrome, options: options)
# 変更後 (v4.0.3)
@driver = Selenium::WebDriver.for(:chrome, capabilities: [options])

たったこれだけでした。
この1行変更するだけで、テストは通るようになりました。
めでたしめでたし。 ・・・だけではなんの学びもありません。
何が起こっていたのか、もう少し調べてみます。

Seleniumの変更点を追ってみる

まず、変更前の実装のまま4系を使って実行した場合にどうなるかというと、以下のような警告文が出てきます。

2021-11-16 19:44:50 WARN Selenium [DEPRECATION] [:browser_options] :options as a parameter for driver initialization is deprecated. Use :capabilities with an Array of value capabilities/options if necessary instead.

:optionsパラメータをdriverの初期化に渡すのは非推奨になった、とのこと。

この文言を出しているのは、以下のあたり。
https://github.com/SeleniumHQ/selenium/blob/3a2181467904af9043828cede13e5dc866c1af12/rb/lib/selenium/webdriver/common/driver.rb#L327-L329
(deprecateの文言もメソッドとして用意しているんですね、知らなかった。これも学び。)

前後を見ると、create_bridgeというメソッドの中で初期化時に渡すオプション等を処理しているようです。

:capabilities、 :desired_capabilities:optionsというキーワード引数たちを配列にまとめて、最終的にgenerate_capabilitiesメソッドへ渡して1つの塊にしているイメージ。

では、3系ではどういう処理になっていたかというと、該当しそうなのは以下のあたり。
https://github.com/SeleniumHQ/selenium/blob/e82be7d3584062a0d16af8d562d387e3d4855aa1/rb/lib/selenium/webdriver/chrome/driver.rb#L67-L113
(上記の中にもWebDriver.logger.deprecateがいっぱいあるので、この辺が4系で駆逐されたんでしょうね)

3系ではforメソッドの引数のうち、ブラウザ指定以外の引数は全てoptsとして各ブラウザごとのドライバーへ渡されていたようです。

ざっくり処理を追っていくと、上記の通り様々な引数を受け取り、主にcapsoptionsにそれぞれの値をくっつけていき、最終的にはcapsにマージされているようです。


ということで、簡単にまとめると

3系ではdriverの初期化時に様々なオプションをキーワード引数として取得し、内部でよしなに変換・マージしてオプションを渡していたようですが、
4系ではそれを非推奨として、それぞれのオブジェクトとして作るよう変更されたわけです。

そういえば、実装当時はSeleniumのオプション周りはよく理解せずに実装してしまっていたなぁ・・・と思い出しつつ、そっと1行を変更して終わりました。

なお、この辺の話は実際に中身を追わなくても、リリースノートやCHANGELOGなどにもバッチリ記載があります。
https://github.com/SeleniumHQ/selenium/blob/af668385eeb4c31f48d182a4ff2187544f2115df/rb/CHANGES#L254-L263

まとめ

今回は、情シスのぽちぽち作業を駆逐する中で使っているSeleniumを無邪気にバージョンアップしたらテストが盛大に転けたので、諸々調べつつ対応した話でした。

実際に対応した時には、少し調べて修正が必要な箇所だけ追って直しました。
しかし、今回の記事にまとめるにあたり、なぜ動かなくなったのかをSeleniumの中身を前後のバージョンや更新履歴を追っていくなかで、よりSeleniumの中でやっていることの理解度が増した気がします。
(個人の感想です。効果を保証するものではありません)

また、ある程度テストを書いていたので問題にすぐに気が付くことができたのは良かったかなと思います。
アップデート後、テストがこけてワタワタしましたが、公式アナウンス等が親切に修正方法などを記載してくれていたので、どう直せば良いかすぐにわかったので公式情報を追うのは大事だなぁと思いました。
と、同時に昨年実装した時はあまり公式情報を見ずに、その辺のブログ等を参考にしてしまっていた自分をぶん殴りたい気持ちでいっぱいです。
あとは、Seleniumさんと少し仲良くなれた気がしたのでOKです。 今回はここまで。
おわり

ドリコムでは一緒に働くメンバーを募集しています!
募集一覧はコチラを御覧ください!

About the Author

中原翼

なかはらつ

2019年、サーバサイドエンジニアとして新卒入社。
2020年から情報システムグループ。

ラーメンが好き。
休みになるとランダムに駅を選び、その駅近くのラーメン屋を探し食べるという遊びをしている。
冬でも半袖着がち。
プロフィール画像のお店がわかる方は僕と握手。