Vagrant で IE11 の Selenium Grid Node を作る

こんにちは。SaaS Product Team の old_horizon です。

Docker の登場により、Selenium によるクロスブラウザでの E2E テストが簡単になりました。
Linux で動作する主要ブラウザについては、Selenium 公式の Docker Hub 等から Docker イメージを取得するだけで環境構築が完了します。

一方 Internet Explorer 11 (以下 IE11) でのテストは、他のブラウザと比較すると非常に手間がかかります。
下記がその要因と言えるのではないでしょうか。

  • Windows 環境が必要
    普段 Mac や Linux で開発している場合、仮想マシンを別途用意する必要がある
  • Selenium を動作させるための設定が煩雑
    IE のインターネットオプションやレジストリの設定変更が必要
    参考: InternetExplorerDriver の wiki
  • Microsoft が配布する仮想マシンは 90 日で利用期限が切れる
    一度環境を構築しても、期限が切れたら作り直さなければならない

こういった辛さを可能な限り軽減するため、Vagrant を使った自動化を試みました。
なお、動作確認は以下の環境で行っています。

  • Ubuntu 18.04
  • Vagrant 2.2.14
  • VirtualBox 6.1.16
  • Docker 20.10.3
  • OpenJDK 11.0.10
  • Groovy 3.0.4

Vagrantfile

早速ですが、今回作成した Vagrantfile はこちらです。

処理の詳細は実際のコードを見ていただければご理解いただけると思いますので、ここからは作成する中で発見した Tips をいくつかご紹介していきます。

Vagrant の Linked Clones 機能

Linked Clones は Vagrant 1.8 で追加されました。Box をインポートした直後の状態を保存して、以降の変更は差分だけを別のイメージに保存していく機能です。

したがって VM の初回作成時には従来と同等の時間がかかりますが、二回目以降はプロビジョニングから始まるため圧倒的に短縮されます。

今回ベースにする Box は 90 日で利用期限が切れてしまうため、定期的に VM の作り直しが発生します。そのため vb.linked_clone = true により、本機能の恩恵を受けられるようにしました。

Chocolatey による自動インストール

Chocolatey は各種ソフトウェアのインストーラーをラップしたパッケージを提供しています。
煩雑なインストール作業を自動化することができる、パッケージマネージャに近いものです。

PowerShell から公式のインストール手順に記載されたコマンドを実行すると、chocolatey (choco) コマンドが利用できるようになります。

VirtualBox Guest Additions のインストール

VirtualBox Guest Additions は、ゲスト OS のパフォーマンスやユーザビリティを向上させます。画面解像度の変更もこの拡張機能が担います。

なおインストールしただけでは画面解像度は大きくなりません
そのため、プロビジョニング完了後に一度 VirtualBox を開いて画面をリサイズする必要があります。

Selenium の -remoteHost オプション

Selenium Grid の Node は、Hub に接続する際に自分自身の接続先情報 (IP アドレス・ポート番号) を報告します。

しかし今回構築する Node は VirtualBox の仮想ネットワーク上の IP が割り当てられているため、Node から 報告された接続先情報では Hub から Node に通信できません
したがって Hub に報告する接続先情報を、Hub から疎通できるものに変更しなければなりません。

この対策として、Vagrantfile で Node が公開する 5555 ポートをホスト側にポートフォワードしました。

config.vm.network :forwarded_port, guest: 5555, host: SELENIUM_NODE_PORT

かつ、Selenium 起動時に -remoteHost オプションで (ホストの IP):(Node の 5555 ポートを割り当てたホスト側ポート) を指定しています。

(Get-Content $scriptPath) -replace '(^.*nodeconfig\\.json\").*$', '$1 -remoteHost http://#{SELENIUM_NODE_IP}:#{SELENIUM_NODE_PORT}' | Set-Content $scriptPath -Encoding Ascii

これで Hub から Node への接続先情報が変更され、E2E テストが実行できる状態になりました。

動作確認

実際に Selenium Grid を構築して、IE11 で E2E テストを実行してみましょう。

Vagrant Box の追加

Microsoft Edge Developer の仮想マシン配布ページを開き、以下の条件で zip をダウンロードします。

  • 仮想マシン
    MSEdge on Win10 (x64) Stable 1809
  • VM プラットフォームを選択します。
    Vagrant

ダウンロードした zip を展開した中にある MSEdge_Win10.box があるディレクトリで、下記コマンドを実行して Vagrant に追加します。

$ vagrant box add (Box につける任意の名前) MSEdge_Win10.box

Selenium Grid Hub を起動

Docker で Selenium Grid Hub を 4444 ポートで起動します。

$ docker run --rm -p 4444:4444 selenium/hub

IE11 の Selenium Grid Node を作成

まずは Gist から Vagrantfile をダウンロードします。

Vagrantfile をダウンロードしたディレクトリに移動して、以下のコマンドを実行します。

VAGRANT_BOX=(Box につけた任意の名前) SELENIUM_HUB_IP=10.0.2.2 SELENIUM_NODE_IP=$(hostname -I | cut -d ' ' -f 1) SELENIUM_NODE_PORT=5555 vagrant up

それぞれの環境変数の役割については以下のとおりです。

  • VAGRANT_BOX
    Vagrant Box の名前
  • SELENIUM_HUB_IP
    Selenium Grid Hub の IP アドレス
    例で指定した 10.0.2.2 は VirtualBox の仮想ネットワークからホストを参照する際の IP アドレスです。
  • SELENIUM_NODE_IP
    Selenium Grid Node の IP アドレス
    Selenium Grid Hub から参照できる IPを指定します。
  • SELENIUM_NODE_PORT
    VirtualBox 上の Selenium Grid Node の 5555 ポートを割り当てたホスト側ポート

VM 起動後のプロビジョニングが完了すると、一度 VM が再起動します。
再起動が完了すると Selenium Grid Node のプロセスが自動的に立ち上がります。

正常に Selenium Grid Node が起動すると、http://localhost:4444/grid/console で次のような表示が確認できます。

f:id:old_horizon:20210215085311p:plain

E2E テストを実行

よく IPv6 の接続確認でお世話になる、KAME プロジェクトの Web サイトで動作確認します。

以下の Groovy Script を実行してみましょう。

@Grab(group='org.gebish', module='geb-core', version='3.4.1')
@Grab(group='org.seleniumhq.selenium', module='selenium-ie-driver', version='3.141.59')
@Grab(group='org.seleniumhq.selenium', module='selenium-remote-driver', version='3.141.59')
@GrabExclude("org.codehaus.groovy:groovy-all")

import geb.Browser
import org.openqa.selenium.Platform
import org.openqa.selenium.ie.InternetExplorerOptions
import org.openqa.selenium.remote.RemoteWebDriver

def capabilities = new InternetExplorerOptions().useCreateProcessApiToLaunchIe().addCommandSwitches("-private")

def remoteWebDriver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), capabilities)

try {
  Browser.drive(driver: remoteWebDriver) {
    go "http://www.kame.net/"
    assert $(".tit").text() == "The KAME project"
  }
} finally {
  remoteWebDriver.quit()
}

なお InternetExplorerDriver を使用する際は、このサンプルのように InPrivate ブラウズで実行することをおすすめします。
過去の Cookie 等が残る通常モードでは、ログインを必要とする E2E テストなどで期待しない動作をする恐れがあるからです。

おわりに

IE11 をサポートする Web サイトは減りつつありますが、Windows VM の自動プロビジョニング全般で今回の記事が参考になれば幸いです。

© Uzabase, Inc. All rights reserved.