3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【デバッグ追体験】Selenium 4のSafari DriverでiOS Safariを動かそうとしたときのデバッグログ

Last updated at Posted at 2021-12-15

こんにちは。今回は自動テスト開発においてデバッグをした(そして諦めた)際のログを残してみようと思います。
SETエンジニアがどんなことを考えて試行錯誤しているのかトレースできるようにしてみたので、一種の読み物としてお楽しみいただければと思います。

サマリ

  • Selenium 4からdesired_capabilitiesがDeprecatedになり、Optionsを使うべきとWarningが出るようになった
  • Safari DriverでiOS Safariを動かそうとOptionsを変えて試行錯誤したものの、iOSでなくPCのSafariが起動してしまう
  • 調べた結果バグっぽいので、解消されるまで諦めてdesired capabilitiesを使うことにした

Environment

  • Python 3.10.0
  • selenium 4.1.0

Before Selenium 4

SeleniumではSafari Driverをサポートしており、
これを利用するとMac SafariだけでなくiOS Safariも動かすことができます。

SeleniumのPythonライブラリを使って、
pytest向けのテストスクリプトとして記述をすると以下のようになります。

from selenium import webdriver


class TestCase:
    def test_safari(self):
        desired_caps = {
            'browserName': 'safari',
            'platform': 'ios',
        }

        driver = webdriver.Safari(desired_capabilities=desired_caps)
        driver.get("https://google.co.jp")
        driver.quit()

※下記記事を参考にしました。

After Selenium 4

Selenium 4から、desired_capabilitiesがdeprecatedとなり、
上記コードを実行すると以下のようなWarningが出るようになりました。

DeprecationWarning: desired_capabilities has been deprecated, please use the Options class to set it
    driver = webdriver.Safari(desired_capabilities=desired_caps)

バージョンアップ対応もQAの仕事なので、これをどう改善したらいいか検討してみます。

Selenium 4 with Options

Warningには「Optionsクラスを使え」とあるので、SafariのOptionsクラスを引っ張ってきます。
SafariのOptionsクラスは以下の場所にあります。

from selenium.webdriver.safari.options import Options as SafariOptions

これをインスタンス化し、vars()関数を使ってデフォルト値を見ると下記のようになっていました。

{
    '_caps': { 'browserName': 'safari', 'platformName': 'mac', 'pageLoadStrategy': 'normal' },
    'mobile_options': None,
    '_arguments': [],
    '_ignore_local_proxy': False,
    '_binary_location': None,
    '_preferences': {},
    'log': < selenium.webdriver.safari.options.Log object at 0x1072e4910 >
}

なるほど、どうも'_caps'desired_capabilitiesに相当するようですね。
またOptionsには'_caps'をsetするメソッドであるset_capability()も用意されていました。

つまり、これを用いて先ほどのコードを書き換えると下記のようになるはずです。

from selenium import webdriver
from selenium.webdriver.safari.options import Options as SafariOptions


class TestCase:
    def test_safari_new(self):
        options = SafariOptions()
        options.set_capability("platform", "ios")
        options.set_capability("platformName", "ios") # to overwrite mac

        driver = webdriver.Safari(options=options)
        driver.get("https://google.co.jp")

しかしこれを実行すると、何故かiOSではなくMacのSafariが起動しました。

Debugging

なんでじゃい、と思ってGitHubのソースコードを読んでみると…

class WebDriver(RemoteWebDriver):
    """
    Controls the SafariDriver and allows you to drive the browser.
    """

    def __init__(self, port=0, executable_path=DEFAULT_EXECUTABLE_PATH, reuse_service=False,
                 desired_capabilities=DEFAULT_SAFARI_CAPS, quiet=False,
                 keep_alive=True, service_args=None, options: Options = None, service: Service = None):

desired_capabilitiesにはデフォルト値DEFAULT_SAFARI_CAPSが渡されていて、optionsにはNoneが渡されていることが分かりました。

となると、desired_capabilitiesoptionsより内部での処理の優先順位が高い場合、
自分で設定したoptions内の_capsよりもDEFAULT_SAFARI_CAPSが優先されてしまうことになります。
もしもDEFAULT_SAFARI_CAPSがMac Safariを起動するような設定になっていた場合、先ほどの挙動が引き起こされます。

これを検証するためには、Warningは出るものの起動はするtest_safariを以下のように書き換えて、MacとiOSのどちらのSafariが起動するか確認すればよさそうです。

from selenium import webdriver
from selenium.webdriver.safari.options import Options as SafariOptions


class TestCase:
    def test_safari_debugging(self):
        options = SafariOptions() # optionsはMac Safari を起動するように指定

        desired_caps = {
            'browserName': 'safari',
            'platform': 'ios',
        } # desired_capsはiOS Safariを起動するように指定

        driver = webdriver.Safari(options=options, desired_capabilities=desired_caps)
        driver.get("https://google.co.jp")
        driver.quit()

これを実行すると予想通りiOS Safariが起動しました。

さて、DEFAULT_SAFARI_CAPSの実体は…

from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

DEFAULT_SAFARI_CAPS = DesiredCapabilities.SAFARI.copy()

であって、この中身を見ると以下であることが分かります。

{
    'browserName': 'safari',
    'platformName': 'mac'
}

ビンゴっぽい。

これらのことから、先ほどの推論通り、
optionsに適切なパラメータを設定して渡しても無視されてMac Safariが起動してしまうのは、
内部でoptionsよりdesired_capabilitiesが優先して処理されるのにも関わらず、
desired_capabilitiesDEFAULT_SAFARI_CAPSが設定されているからのようであることが分かりました。

Reporting

とはいえ、これは観測した一部分の結果からの推論にすぎません。詳細は開発者の方に確認していただく必要があります。
例えば、お気づきの方もいたかと思いますが、SafariOptionsの中に存在している'mobile_options': Noneの記述はやはり気になりますよね。どうも中身を見る限りAndroidに関する設定項目のようだったので今回はスルーしましたが、これを適切に設定したら上手くいくという可能性もあります。

本来はここで発生した事象と再現手順と原因の推論を書いたIssueを上げてやっとQAの仕事が終わりになります。
…が、今回はWarningを無視すれば実用上の問題はないことと、他の業務があるという世知辛い理由でそこまではやれていません。尻切れトンボですみません。

おわりに

ということで、今回はOSSにたまたまバグっぽいものが見つかったので、デバッグ作業を追体験できるような記事を書いてみました。
僕たちSETエンジニアは、普段はこんなことをしながら、動かねー動かねー動かねー・・・と99回くらい繰り返したあとでやっと動いた、みたいなことを繰り返していると知っていただけると嬉しいです。自動化 is 大変。ではまた。

3
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?