経緯
- WebUIのテストをやるぞ
- 画面ポチポチ検査するの面倒だな
- WebUIの自動テストをやろう
- Seleniumがあるじゃない
- まずはローカルで試そう
- Seleniumはdockerイメージがあるからそれを使おう
- docker for Desktopは好きじゃないからVM上のdockerでやろう
- VirtualBox使おう
- VirtualBoxはM1 macは非対応・・・だと・・・
- UTMというのがあるらしい。そっちを使おう
- UTM上にubuntu arm64版があったのでそれを使おう
- SeleniumのDocker imageを使おう
- arm64のUbuntu上では動かない・・・だと・・・
- arm64向けに作られたコンテナがあるから使おう
- pythonあまり使わないからNodejsでテスト書こう
- nodejsのテストはmochaテストフレームワークが使われているらしいから使おう
- assertionにはchaiを使うらしいから使おう
環境/ライブラリ
- M1 macbook BigSur(11.4)
- UTM 2.3.1 (38)
- Ubuntu20.04.3 server arm64 image
- docker 20.10.10
- docker-compose v2.0.1
- selenium docker image(arm64版)
- nvm 0.39.0
- npm 8.1.1
- nodejs v16.13.0
- mocha 9.1.3
- chai 4.3.4
- selenium-webdriver 4.0.0
M1 mac上での仮想マシン構築
VirtualBoxを使用するつもりが、M1 macではそもそも動かないことがわかったので違う方法を模索した。
- VMWareを使う
- まだ正式サポートでない
- Parallelsを使う
- 一応正式サポートになっているが、持っていない
- UTMを使う
- 動きそう
ということでUTMを使用することにする。
UTMとUbuntu環境の準備
Install Ubuntu ARM64 on Apple M1
に書いてある通りに行った。Ubuntu Desktopはインストールしない。
dockerとdocker-compose
それぞれインストールする。apt-get
で特に問題なくインストールできる。細かいところは割愛する。
Selenium Gridのdockerコンテナ起動
公式のdocker imageを使用し、Composeの設定ファイルを参考にする。
# To execute this docker-compose yml file use `docker-compose -f docker-compose-v2.yml up`
# Add the `-d` flag at the end for detached execution
# To stop the execution, hit Ctrl+C, and then `docker-compose -f docker-compose-v2.yml down`
version: '2'
services:
chrome1:
image: selenium/node-chrome:4.0.0-20211025
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
ports:
- "6900:5900"
chrome2:
image: selenium/node-edge:4.0.0-20211025
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
ports:
- "6901:5900"
selenium-hub:
image: selenium/hub:4.0.0-20211025
ports:
- "4442:4442"
- "4443:4443"
- "4444:4444"
とりあえず、2台のコンテナと1台のhubを用意し、nodeはどちらもchromeとする。適当なディレクトリを掘って、作成したファイルをdocker-compose.ymlにリネームする。
$ docker-compose up -d
[+] Running 3/0
⠿ Container selenium-selenium-hub-1 Created 0.0s
⠿ Container selenium-chrome1-1 Created 0.0s
⠿ Container selenium-chrome2-1 Created 0.0s
Attaching to selenium-chrome1-1, selenium-chrome2-1, selenium-selenium-hub-1
selenium-selenium-hub-1 | standard_init_linux.go:228: exec user process caused: exec format error
selenium-selenium-hub-1 exited with code 1
selenium-chrome1-1 | standard_init_linux.go:228: exec user process caused: exec format error
selenium-chrome2-1 | standard_init_linux.go:228: exec user process caused: exec format error
selenium-chrome1-1 exited with code 1
selenium-chrome2-1 exited with code 1
エラーとなりコンテナが停止されてしまう。一旦すべてのコンテナをクリアし、単体で実行してみる。
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker run -d -p 4442-4444:4442-4444 --net grid --name selenium-hub selenium/hub:4.0.0-20211025
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
75d8094554124ebffdab995ee0ba3167affea3fc5d4ddee91730cf9c00177f78
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
75d809455412 selenium/hub:4.0.0-20211025 "/opt/bin/entry_poin…" 30 seconds ago Exited (1) 29 seconds ago selenium-hub
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
どうやらarm64で動いているこのホストマシンとimageが合わないようだ。
arm64向きdocker image
https://github.com/SeleniumHQ/docker-selenium/issues/1076
ここで議論されている中で、arm64向きのimageが公開されている。このcontainerは継続サポートはされないようだが、ここでarm64向きビルドを行っている人がいる。自前でもビルドできるので参考程度に。
docker-composeymlを修正して、以下とする。
# To execute this docker-compose yml file use `docker-compose -f docker-compose-v2.yml up`
# Add the `-d` flag at the end for detached execution
# To stop the execution, hit Ctrl+C, and then `docker-compose -f docker-compose-v2.yml down`
version: '2'
services:
chrome1:
image: seleniarm/node-chromium:4.0.0-beta-1-20210215
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
ports:
- "6900:5900"
chrome2:
image: seleniarm/node-chromium:4.0.0-beta-1-20210215
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
ports:
- "6901:5900"
selenium-hub:
image: seleniarm/hub:4.0.0-beta-1-20210215
ports:
- "4442:4442"
- "4443:4443"
- "4444:4444"
imageの箇所を先程のものに差し替えただけ。前に失敗している場合は、docker-compose down
で停止しておくこと。
$ docker-compose up -d
[+] Running 4/4
⠿ Network selenium_default Created 0.0s
⠿ Container selenium-selenium-hub-1 Started 0.5s
⠿ Container selenium-chrome1-1 Started 1.4s
⠿ Container selenium-chrome2-1 Started
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f2d71f110a11 seleniarm/node-chromium:4.0.0-beta-1-20210215 "/opt/bin/entry_poin…" 19 minutes ago Up 19 minutes 0.0.0.0:6901->5900/tcp, :::6901->5900/tcp selenium-chrome2-1
48708d0256d9 seleniarm/node-chromium:4.0.0-beta-1-20210215 "/opt/bin/entry_poin…" 19 minutes ago Up 19 minutes 0.0.0.0:6900->5900/tcp, :::6900->5900/tcp selenium-chrome1-1
bb0dfa0bcd4d seleniarm/hub:4.0.0-beta-1-20210215 "/opt/bin/entry_poin…" 19 minutes ago Up 19 minutes 0.0.0.0:4442-4444->4442-4444/tcp, :::4442-4444->4442-4444/tcp selenium-selenium-hub-1
ここまで動いたら、hubが動作しているのか確認する。
UTM上で動いている仮想マシンのIPアドレスを確認し、実行PCからアクセスしてみる。今回の場合は192.168.64.2:4444
にアクセスする。
2台のchromeが起動していることが確認できた。
seleniumテスト
テストは、仮想マシンを動かしているPC上で実行する。nvm, npmで環境を準備し、以下のバージョンで行う。
- nvm 0.39.0
- Node.js : v16.13.0
- npm 8.1.1
適当にディレクトリを作成し、必要なライブラリをインストールする。
- elenium-webdriver
- mocha
- chai
$ mkdir node-selenium
$ cd node-selenium
% npm install --save-dev selenium-webdriver mocha chai
テストの作成
$mkdir tests
testsディレクトリを作成し、2つのテストを作成する。内容は一緒だが並列にテストを行うために用意する。
const { Builder, By, Key, Capabilities } = require("selenium-webdriver");
var chai = require('chai');
var assert = chai.assert;
let driver;
describe("Qiita表示テスト1", () => {
before(() => {
driver = new Builder()
.usingServer("http://192.168.64.2:4444/wd/hub")
.withCapabilities(Capabilities.chrome())
.build();
});
after(() => {
return driver.quit();
});
it("Qiita表示1", async () => {
await driver.get("https://qiita.com");
const title = await driver.getTitle();
assert.strictEqual(title, "Qiita");
});
it("Qiita検索遷移テスト1", async () => {
await driver.get("https://qiita.com");
await driver.findElement(By.xpath('/html/body/div[1]/div[1]/div/div/div/div[1]/form[1]/input')).sendKeys("selenium", Key.RETURN);
const currentUrl = await driver.getCurrentUrl();
assert.strictEqual(currentUrl, "https://qiita.com/search?q=selenium");
});
});
.usingServer("http://192.168.64.2:4444/wd/hub")
この箇所については適宜自身の環境のhubに置き換えること。
test2.jsを作成し、describeとitの文字列を2に変更して、tests以下に保存。
ls tests
test1.js test2.js
テスト実行
package.jsonを編集して、scripts以下を追加する
{
"devDependencies": {
"chai": "^4.3.4",
"mocha": "^9.1.3",
"selenium-webdriver": "^4.0.0"
},
"scripts": {
"test": "mocha tests/ --timeout 20000"
}
}
テストを実行する。
% ls
node_modules package.json
package-lock.json tests
$ npm test
> test
> mocha tests/ --timeout 20000
Qiita表示テスト1
✔ Qiita表示1 (3652ms)
✔ Qiita検索遷移テスト1 (1965ms)
Qiita表示テスト2
✔ Qiita表示2 (2564ms)
✔ Qiita検索遷移テスト2 (2632ms)
4 passing (11s)
これだけだと、並列実行されず一つずつテストされるためSelenium Gridの恩恵を受けることができない。
package.jsonを編集し--parallel
をmocaのオプションに追加、再度実行する。
"scripts": {
"test": "mocha --parallel tests/ --timeout 20000"
}
$ npm test
> test
> mocha --parallel tests/ --timeout 20000
Qiita表示テスト1
✔ Qiita表示1 (3327ms)
✔ Qiita検索遷移テスト1 (3247ms)
Qiita表示テスト2
✔ Qiita表示2 (4253ms)
✔ Qiita検索遷移テスト2 (3618ms)
4 passing (8s)
二つのノードで同時に実行され、Concurrencyは100%になり、誤差レベルでテスト時間が早くなった。
まとめ
今回はテストが2つしかないため並列に実行する恩恵はほとんどないが、テスト数が増えれば増えるほど恩恵は大きくなる。
テストが増えた場合にはノードを増やすことでより一層テスト時間の短縮ができるだろう。
ちなみにM1 macじゃなければ普通に簡単なのでここまで面倒なことをはしなくて良い。さっさとIntel macでやればよかった。