safaridriverでmobilesafariを自動操作してみた ~ M1 Mac編 ~

はじめに

本稿は、自動テスト Advent Calendar 2020 の12/24の投稿です。昨年もsafaridriverでmobilesafariを自動操作してみたのですが1そして何故かそれはgoogle検索でそこそこ上位に来る、今回はM1 Macでやってみようと思います。

結論

去年の内容をふんわりやってみたのですが、M1 Mac(Big Sur) vs Intel Mac(Catalina) で比較しても特に違いは感じませんでした。ただ、去年の結果と比較したところ、気づいたのは次の3つ

  1. シミュレータは前よりも安定して動く (謎のUnable to find the RWISimulator associated with the booted simulatorというエラーは出なかった)
  2. sendKeysは依然としてできない (去年の記事の回避策は今も必要)
  3. iOS14ではクリックができなくなった (回避策はこの後紹介)

それから、M1 Macの環境セットアップですが、brewとnode (v15.3.0以降らしい2 https://qiita.com/shibukawa/items/797b7cbb7e530842e6f7#nodejs )が入れば問題ないと思います。Xcodeも多分必要ですが、簡単にインストールできるので省略します。

環境構築

(読み飛ばし可) まずはbrewを入れます3 https://qiita.com/yujiod/items/56002a7cef5b5a3be3fb#arm64 4 https://docs.brew.sh/Installation#untar-anywhere

$ cd /opt
$ sudo mkdir homebrew
$ sudo chown $USER\:admin homebrew
$ curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew

ついでにPATHを通しましょう

export PATH=/opt/homebrew/bin:$PATH

それからnodeを入れます

$ brew install node

全てがうまくいくなら、こんなログが出ることでしょう。成功です。

$ brew install node
Warning: You are running macOS on a arm64 CPU architecture.
We do not provide support for this (yet).
Reinstall Homebrew under Rosetta 2 until we support it.
You will encounter build failures with some formulae.
Please create pull requests instead of asking for help on Homebrew's GitHub,
Twitter or any other official channels. You are responsible for resolving
any issues you experience while you are running thisunsupported configuration.

==> Downloading https://homebrew.bintray.com/bottles/node-15.4.0.arm64_big_sur.bottle.tar.gz
Already downloaded: /Users/mwakizaka/Library/Caches/Homebrew/downloads/5991bb85ee172009e60f13caa3e00fd902daf435c9363317d5c2d5e3474dcde5--node-15.4.0.arm64_big_sur.bottle.tar.gz
==> Pouring node-15.4.0.arm64_big_sur.bottle.tar.gz   
🍺 /opt/homebrew/Cellar/node/15.4.0: 3,273 files, 54.2MB

ちなみに、nodebrewの使用は検討しましたが、残念ながら動く気配を感じなかったため、使用していません。それから、Rosetta 2の高い評価は聞き及んでいますが、個人的にはその使用は何か敗北に似ているため、今回は使用しておりません。

サンプルコード

全てはここにありますが、ふんわり紹介します。

capabilitiesは以下のように書きます。もしsimulatorでテスト実行したい場合は、'safari:useSimulator': trueを追記します。

{
    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.setNativeValueCommand, true);
    browser.addCommand("nativeClick", helper.clickForIOS14SafariCommand, true);
  });

  it("Fail to make a reservation", function () {
    browser.url("http://example.selenium.jp/reserveApp/")
    
    $("#reserve_year").setNativeValue("1987");
    $("#reserve_month").setNativeValue("01");
    $("#reserve_day").setNativeValue("08");
    $("#guestname").setNativeValue("mwakizaka");
    const gotoNext = $("#goto_next");
    gotoNext.nativeClick();

    assert($("body.confirm_form > div.container > h1").getText() === "予約エラー");
  });
})

webdriveriomochaしています。より具体的には、テスト自動化の話をする時にこぞって出てくる、広告おいたら稼げるかもしれないとあるホテル予約サイトにアクセスし、何か意味ありげな30年以上前の日付を入力してエラーを表示してもらう、という内容です。

ちなみに、このコードは以下の2環境で動作確認しています。

M1 MacIntel Mac
OSMac OS 11.0.1Mac OS 10.15.7
safaridriver14.1 (16610.2.11.51.8)14.0 (15610.1.28.1.9)
nodev15.4.0v12.13.1
npm7.0.156.12.1
Xcode12.312.2

iOS14でクリックできない問題

Apple Developerのフォーラムにも上がってるこちらと同じ問題だと思います。内容を要約するとclick操作ができなくて5リクエストは受け付けるが画面は反応していない、さらにTouchActions6 より原始的なAPI。例えば画面の特定座標を指定してクリックやダブルクリック等を実現できる も501(未実装)エラーが出て、使えないようです。そのため、回避策としてクリック操作を実現するJavaScriptを使う方式を取りました7 https://stackoverflow.com/a/58904446/14303272

function clickForIOS14SafariCommand(value) {
  if (driver.isIOS && compareVersions(driver.capabilities['safari:platformVersion'], '13.*') > 0) {
    browser.execute("arguments[0].click(); arguments[0].dispatchEvent(new Event('click', { bubbles: true }));", this);
  } else {
    this.click();
  }
}

// add a custom command so that arbitrary element can use `nativeClick()` method which calls `clickForIOS14SafariCommand`.
browser.addCommand("nativeClick", clickForIOS14SafariCommand, true);

// Usage
$("#goto_next").nativeClick();

上記の3行目で、JavaScriptを使い、以下の2つを実現しています。

  1. クリック
  2. クリックイベントを起こす(はず)8 確認取ってないので、違ってたら、正しい方法あったら教えてください

余談ですが、webdriverioはカスタムコマンドを足すことができます9 https://webdriver.io/docs/customcommands.html 。そのため、$("#goto_next").nativeClick();ということができます。

まとめ

M1 Macでも雰囲気問題なく動くことがわかりました。Unable to find the RWISimulator associated with the booted simulator という難攻不落の城も攻略されているみたいで嬉しいですね。その代わりクリックができなくなって、テキスト入力も不自由しますが、JavaScriptがある限りどうにでもなるので、総合的にみて進化しているのではないかなと思いました。