safaridriverでmobilesafariを自動操作してみた

はじめに

本稿は、Selenium/Appium Advent Calendar 2019 の12/15の投稿になりました1本当は12/17だったけど、早めにできた & 空いてたので変えました。safaridriverがiOS 13のSafariをサポートするようになったので、ちょっとやってみようと思います。

目次

  1. 前提
  2. 出来上がったコード
  3. 厳★選 ハマったところ
  4. 試してて気になったところ
  5. その他、公式ブログから
  6. まとめ
  7. お持ち帰り
  8. 参考

1. 前提

  1. MacOS: 10.14.6
  2. iOS: 13.2.3(実機)
  3. safaridriver: Included with Safari 13.0.4 (14608.4.9.1.4)
  4. WebdriverIOを使う2JavaScript向けSeleniumのクライアントライブラリ。(主に筆者 OR safaridriverの)技術的制約により、たぶんこれがいい
  5. mochaを使う(テストフレームワーク)
  6. babelを使う(コンパイラ?よく知らない)
  7. 筆者のJavaScript力: 低い

WebdriverIOのセットアップは長くなるので、こちらがすごく参考になります、というか、ライブラリ周りはかなりそのまま持ってきた。

2. 出来上がったコード

前回と同じく、日本Seleniumユーザーコミュニティで用意されているテスト用サイトをAUT(Application Under Test, テスト対象)として使うことにします。ざっくりこんな感じです。

desired capabilities

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

スクリプト本体(イメージ)

import assert from "assert"
import helper from "../lib/helper"


describe("example.selenium.jp/reserveApp", function () {
  before(function() {
    browser.addCommand("setNativeValue", helper.customCommand, true);
  });

  it("Make a reservation at example.selenium.jp", function () {
    browser.url("http://example.selenium.jp/reserveApp/")
    
    $("#reserve_year").setNativeValue("2020");
    $("#reserve_month").setNativeValue("01");
    $("#reserve_day").setNativeValue("08");
    $("#guestname").setNativeValue("mwakizaka");
    $("#goto_next").click();

    assert($("#price").getText() == 8000);
    $("#commit").click();

    assert($("body.final_form > div.container > h1").getText() == "予約を完了しました。");
  })
})

とても普通ですね。最初 clientサイドはまだ対応してないかなと思って、Postmanを淡々と叩いてたんですけど、そうでもないみたいですね。

3. 厳★選 ハマったところ

3.1 iosシミュレータが闇に堕ちる

desired capabilitiesに'safari:useSimulator': true と書いてあげるとiOS simulatorを使うことができます。iOS simulatorを予め立ち上げておくと成功します。が、iOS simulatorを立ち上げていないと、よくわからぬエラーにより失敗します。3しかもその後、iOS simulatorを予め立ち上げていても失敗するようになります。そしてごちゃごちゃやってると、回復するケースもある具体的にはこんな感じ

[0-0] 2019-12-15T11:44:13.763Z ERROR webdriver: Request failed due to session not created: Could not create a session: Unable to find the RWISimulator associated with the booted simulator: ‘iOS 13.3 (17C45) – iPhone 8’ (899F3A33-622F-4952-B6E0-1187A557C721)

RWISimulator って何やねん思って、Google先生に聞いてもほとんど何も出てきませんでした。この問題を世界で最初に解くチャンスがあるらしいことはわかったのですが、時には退却することも大事であると思うことにしました。うん、今はまだその時ではない。4解決策を期待してやってきた人、ゴメンな!

【追記】クリックもどうもできないように見える。後述のSafaridriverの問題と同じかもしれない

3.2 sendKeysできない

ログ見てる感じ、明らかにsendKeys してるのですが、端末を見ていると実際のところ、ひたすらに入力欄を空にしてるだけでした。一体何が起こっているというのか。。。

[0-0] 2019-12-15T11:53:39.079Z INFO webdriver: COMMAND findElement(“css selector”, “#reserve_year”)
[0-0] 2019-12-15T11:53:39.079Z INFO webdriver: [POST] http://127.0.0.1:4444/session/B449D936-B453-4CB6-8A3D-04F54DD7F227/element
[0-0] 2019-12-15T11:53:39.079Z INFO webdriver: DATA { using: ‘css selector’, value: ‘#reserve_year’ }
[0-0] 2019-12-15T11:53:39.096Z INFO webdriver: RESULT {
  ‘element-6066-11e4-a52e-4f735466cecf’: ‘node-61A4E618-782F-4CEC-AEDB-402BC3FCA15C’
}
[0-0] 2019-12-15T11:53:39.100Z INFO webdriver: COMMAND elementClear(“node-61A4E618-782F-4CEC-AEDB-402BC3FCA15C”)
[0-0] 2019-12-15T11:53:39.100Z INFO webdriver: [POST] http://127.0.0.1:4444/session/B449D936-B453-4CB6-8A3D-04F54DD7F227/element/node-61A4E618-782F-4CEC-AEDB-402BC3FCA15C/clear
[0-0] 2019-12-15T11:53:39.132Z INFO webdriver: COMMAND elementSendKeys(“node-61A4E618-782F-4CEC-AEDB-402BC3FCA15C”, “2020”)
[0-0] 2019-12-15T11:53:39.132Z INFO webdriver: [POST] http://127.0.0.1:4444/session/B449D936-B453-4CB6-8A3D-04F54DD7F227/element/node-61A4E618-782F-4CEC-AEDB-402BC3FCA15C/value
[0-0] 2019-12-15T11:53:39.133Z INFO webdriver: DATA { text: ‘2020’ }

これもGoogle先生に聞いてもめぼしいのは出てこなかったです。さっきの件といい、聞き方が悪いのであろうか。Appiumでwebview自動化するときも似たような問題あったなーと思い出して、こちらのコードで回避することにしました。WebDriverIOを使ってるのは主にこれが理由。JavaScriptのイベント発火しないかもしれないけど、その辺含めた諸々の話はまた別の機会にじっくりと。

4. 試してて気になったところ

4.1 セッション溜まってる?

Desktop SafariにもChromeのDevTools的なものがあり、その開発メニューで端末のSafariのセッションを見ることができます。テストに使ってる端末を見てみると、テストを実行するたびに「about:blank」という項目が増えてるんですよね。端末のSafariを完全に終了すると消えてくれるのですが、それを落とす手段がsafaridriverに提供されてるように見えないので、ちょっと気になりました。

「about:blank」がわらわら増えはじめる前の様子

4.2 safaridriver起動したら、わんさかメッセージ出てきた

こんな内容でした。Catalinaでは出なかったので、Mojaveの場合に出るとかでしょうか。多分実害はなかったので、今回はスルーしました。

objc[46192]: Class AMSupportURLConnectionDelegate is implemented in both /System/Library/PrivateFrameworks/EmbeddedOSInstall.framework/Versions/A/EmbeddedOSInstall (0x7fffa2fefc58) and /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice (0x104d790e8). One of the two will be used. Which one is undefined. objc[46192]: Class AMSupportURLSession is implemented in both /System/Library/PrivateFrameworks/OSPersonalization.framework/Versions/A/OSPersonalization (0x7fffa48263a8) and /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice (0x104d79138). One of the two will be used. Which one is undefined. objc[46192]: Class RPStream is implemented in both /System/Library/PrivateFrameworks/EmbeddedOSInstall.framework/Versions/A/EmbeddedOSInstall (0x7fffa2ff0d38) and /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice (0x104d791d8). One of the two will be used. Which one is undefined.

4.3 ssh越しだと safaridriver --enable できないらしい

ツラたん

4.4 [余談]Desktop Safariだとclickできない不具合があるらしい

13から。私も試したけどできなかった

5. その他、公式ブログから

SafeguardsPorting Tests のところから気になったところを抜き出すとこんな感じでしょうか。

  1. 分離されたセッションで起動するので、いつも綺麗な状態でテストを始められる
  2. W3C WebDriver はWebコンテンツを自動操作することにフォーカスしてるので、非Safariなコンテンツは無効化される。5プッシュ通知は飛んできても無視されるし、電話のリンクは押下しても電話アプリは起動しないし、app storeのリンクはApp Storeにリダイレクトしてくれない。
  3. 自動操作中は、オレンジ色になるので、触っちゃダメなの一目でわかる。自動テストに干渉できなくなっている6Desktop Safariもそうなってるっぽい
  4. DesktopのSafariでもiOSのSafariでも同じように操作できるようにAPIは統一されてる(e.g. iOS Safariでも同じようにclick を使う。)
  5. マルチタッチの入力はまだサポートされてない

2番については捉え方次第かなと。プッシュ通知とかに邪魔されないのはいいかもしれないけど、Mobile Safariの外との連携を確認するような項目のテストには向いてなさそうです。少なくとも、単体だとWebViewのテストはできなさそうです。Appiumと組み合わせればできるかもしれません。7ろくすっぽ確認してなかったけど、もうできるのだろうか 5番については、純粋にWebサイトをテストするにあたり、そんなに気にならないかも

6. まとめ

とりあえずできることやってみました。使い倒してないので、これがどの程度実用に耐えるかまだわからないのですが、パッとみた感じ割と高速に動いてる印象を受けました。Appium mobilesafariを自動操作するより速いかも。あと、Simulatorより実機の方が安定してますね。時間の都合でissueあげたりできなかったのですが、何処かのタイミングで何かしらの貢献をしてみたいなと思います。8追記。3.1について、不具合チケットあげました

7. お持ち帰り

今回のコードはこちらにあげてあるので、気になる方は試してみてくだされ

8. 参考

Safaridriverの話を書いてくれてる方〜
https://qiita.com/hiroshitoda/items/6ee3ad892357cda3f0e0
https://moneyforward.com/engineers_blog/2019/11/06/e2e-test-automation/
https://medium.com/swlh/a-guide-to-using-webdriverio-with-ios-13-ba0a24420ff8