バージョンを上げました。 https://t.co/jBGOLeZ6iR
— しまぶ (@shimabox) November 15, 2018
というわけでバージョンを上げました(v0.6.0)。
バージョンアップの内容
バージョンアップの内容は大まかに挙げるとこんな感じです。
- shimabox/selenium-downloader の組み込み
SMB\Screru\Screenshot\Screenshot
- take(), takeFull(), takeElement()
- 引数のファイル名に拡張子が含まれていようと含まれていまいと拡張子は
.png
になるように統一 hoge.jpg
で指定されていてもhoge.png
で出力- シグネチャの修正
- UnitTest用のページを外部(Google)から、内部(localhost)に変更
- テストではビルトインサーバーを利用します
上記のアップデートで自分の中では大体形が見えてきたので、再度使い方についてまとめてみたいと思います。
そもそもこれは何なのか
facebook/php-webdriver のちょっとしたラッパーライブラリです。
主に以下の機能を持ちます。
- PHPUnit用に組み込める関数群をTraitとして用意しています
- 画面のフルスクリーンキャプチャが撮れます
- 指定要素のキャプチャが撮れます
- 各ブラウザのwebdriverがあれば容易にテスト可能です
対応ブラウザは、
- Firefox
- Chrome
- Internet Explorer (windows)
のみとなっています(いまのところ)。
https://github.com/shimabox/screru
名前は screru(スクレル) です。
インストール
Composer
で入れるか、git clone
します。
Composer
$ composer require shimabox/screru $ cd vendor/shimabox/screru $ cp .env.default .env
clone
$ git clone https://github.com/shimabox/screru.git $ cd screru $ composer install
自分のところで composer instal | update
した場合、.env.default
ファイルをコピーして .env
ファイルを作成します。
設定ファイルの修正 (.env | .env.default)
各設定を .env | .env.default
ファイルで管理しています。
デフォルト設定を変更する必要がある場合は、
.env.default
ファイルをコピーして.env
ファイルを作成- その
.env
ファイルを修正
します。
.env
ファイルが存在しなければ、.env.default
ファイルを参照します。
$ vim .env // selenium server url SELENIUM_SERVER_URL='http://localhost:4444/wd/hub' // you can override the default User-agent OVERRIDE_DEFAULT_USER_AGENT='' // local port LOCAL_PORT=8000 // true to enable ENABLED_CHROME_DRIVER=true ENABLED_FIREFOX_DRIVER=true ENABLED_IE_DRIVER= // true to start headless chrome ENABLED_CHROME_HEADLESS=true // true to start headless firefox ENABLED_FIREFOX_HEADLESS=true // true to platform is windows IS_PLATFORM_WINDOWS= // describe the webdriver path if necessary CHROME_DRIVER_PATH='' FIREFOX_DRIVER_PATH='' IE_DRIVER_PATH=''
Key | Description | Default | Example |
---|---|---|---|
SELENIUM_SERVER_URL | セレニウムサーバーのURLを定義しています. | http://localhost:4444/wd/hub | |
OVERRIDE_DEFAULT_USER_AGENT | (SPのテストなど) デフォルトで使われるUser-agentを変更できます. | Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1 | |
LOCAL_PORT | ユニットテストで使われるlocalhostのポート番号を定義しています. | 8000 | |
ENABLED_CHROME_DRIVER | trueにするとChromeDriverが有効になります. | true | |
ENABLED_FIREFOX_DRIVER | trueにするとgeckodriverが有効になります. | true | |
ENABLED_IE_DRIVER | trueにするとIEDriverServerが有効になります. | blank(false) | |
ENABLED_CHROME_HEADLESS | trueにするとChromeをヘッドレスモードで起動させます. | true | |
ENABLED_FIREFOX_HEADLESS | trueにするとFirefoxをヘッドレスモードで起動させます. | true | |
IS_PLATFORM_WINDOWS | Windowsでテストされているかどうか. Windowsでテストする場合必ずtrueにしてください. |
blank(false) | |
CHROME_DRIVER_PATH | 必要に応じてChromeDriverのファイルパスを記述します(ローカルのものとか). 記載が無ければPATHを見にいきます. Windowsの場合、.exeファイルのファイルパスを書いたほうがよいです. |
blank | /home/user/screru/chromedriver |
FIREFOX_DRIVER_PATH | 必要に応じてgeckodriverのファイルパスを記述します(ローカルのものとか). 記載が無ければPATHを見にいきます. Windowsの場合、.exeファイルのファイルパスを書いたほうがよいです. |
blank | /Applications/MAMP/htdocs/screru/geckodriver |
IE_DRIVER_PATH | 必要に応じてIEDriverServerのファイルパスを記述します(ローカルのものとか). 記載が無ければPATHを見にいきます. Windowsの場合、.exeファイルのファイルパスを書いたほうがよいです. |
blank | /c/xampp/htdocs/screru/IEDriverServer.exe |
どうしてもこのへん面倒くさいのですが、、何か他にいい案があったら教えてください。
準備
selenium-server-standalone
, ChromeDriver
, geckodriver
, IEDriverServer
などなど必要なものをダウンロードします(zip や tar は適宜解凍してください)。
※ 以下は、現時点(2018/11/16) でのおすすめバージョンです
Platform | selenium-server-standalone | ChromeDriver | geckodriver | IEDriverServer |
---|---|---|---|---|
Mac | 3.8.1 | 79.0.3945.36 | 0.26.0 | – |
Windows(64bit) | 3.8.1 | 2.43 | 0.23.0 | 3.14.0 |
Linux(CentOS 6.9) | 3.8.1 | – | 0.23.0 | – |
Linux(Ubuntu trusty) | 3.8.1 | 2.43 | 0.23.0 | – |
ダウンロードが面倒くさい場合
必要な諸々をダウンロードするスクリプトがあるのでそれを使います。
- Mac の場合
$ php selenium_downloader.php -p m -d . -s 3.8.1 -c 79.0.3945.36 -g 0.26.0
- Windows の場合
$ php selenium_downloader.php -p w -d . -s 3.8.1 -c 2.43 -g 0.23.0 -i 3.14.0
- Linux の場合
$ php selenium_downloader.php -p l -d . -s 3.8.1 -g 0.23.0
shimabox/selenium-downloader を組み込んでいますので、こちらも参考にしてみてください。
macOS
前提条件として、javaが入っていなければインストールが必要です。
パスを通す
ChromeDriver
とgeckodriver
のパスを通します- e.g) ChromeDriver
$ mv chromedriver /usr/local/bin/ $ chmod +x /usr/local/bin/chromedriver
- e.g) geckodriver
$ mv geckodriver /usr/local/bin/ $ chmod +x /usr/local/bin/geckodriver
- e.g) ChromeDriver
任意のパスにあるドライバーを使う場合
任意のパスにあるドライバーを使いたい場合、.env
ファイルの以下キーにドライバーのファイルパスを記述します。
※ 実行権限をつけてください(chmod +x
)
e.g)
CHROME_DRIVER_PATH=/Applications/MAMP/htdocs/screru/chromedriver FIREFOX_DRIVER_PATH=/Applications/MAMP/htdocs/screru/geckodriver
selenium-server-standaloneの実行
seleniumを以下コマンドで立ち上げます。
$ java -jar selenium-server-standalone-3.8.1.jar -enablePassThrough false
windows(64bit)
前提条件として、javaが入っていなければインストールが必要です。
.env
- Edit
.env
ENABLED_FIREFOX_DRIVER=true ENABLED_CHROME_DRIVER=true ENABLED_IE_DRIVER=true // true to platform is windows IS_PLATFORM_WINDOWS=true // describe the webdriver path if necessary FIREFOX_DRIVER_PATH='geckodriver.exe のファイルパスを記述します' CHROME_DRIVER_PATH='chromedriver.exe のファイルパスを記述します' IE_DRIVER_PATH='IEDriverServer.exe のファイルパスを記述します'
※ 各ドライバーには実行権限をつけてください(
chmod +x
)
IS_PLATFORM_WINDOWS
の値は必ず true
にしてください。
selenium-server-standaloneの実行
seleniumを以下コマンドで立ち上げます。
$ java -jar selenium-server-standalone-3.8.1.jar -enablePassThrough false
注意
Facebook\WebDriver\Exception\SessionNotCreatedException: Unexpected error launching Internet Explorer. Protected Mode settings are not the same for all zones. Enable Protected Mode must be set to the same value (enabled or disabled) for all zones.
テストを実行して上記エラーが表示されたら以下リンクを参照してみてください。
- Rantings of a Selenium Contributor: You’re Doing It Wrong: IE Protected Mode and WebDriver
- internet settings.png (2718×1068)
要は、IEのインターネットオプション-セキュリティにおいて、すべてのゾーンの設定を同じにすればいい(保護モードを有効にする)だけです。地味にめんどくさいけど。
Linux (CentOS 6.9)
java
と Firefox
と Xvfb
のインストールが必要です(入っていなければ)。
java
- install
$ sudo yum -y install java
- version 1.8>=
$ java -version openjdk version "1.8.0_131" OpenJDK Runtime Environment (build 1.8.0_131-b11) OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
Firefox
- install
$ sudo yum -y install firefox
or
$ sudo yum -y update firefox
- version 60.3.0
$ firefox -v Mozilla Firefox 60.3.0
Xvfb
- install
$ sudo yum -y install xorg-x11-server-Xvfb $ sudo yum -y groupinstall "Japanese Support"
パスを通す
geckodriver
のパスを通します$ mv geckodriver /usr/local/bin/ $ chmod +x /usr/local/bin/geckodriver
任意のパスにあるドライバーを使う場合
任意のパスにあるドライバーを使いたい場合、.env
ファイルの以下キーにドライバーのファイルパスを記述します。
※ 実行権限をつけてください(chmod +x
)
e.g)
FIREFOX_DRIVER_PATH=/home/user/screru/geckodriver
.env
- Edit
.env
ENABLED_FIREFOX_DRIVER=true ENABLED_CHROME_DRIVER= ENABLED_IE_DRIVER=
selenium-server-standaloneの実行
シェルを用意しているのでそれを叩いたほうが楽かもしれません。
(Xvfb と selenium-server-standalone を起動させないといけないので)
- Run Xvfb & selenium-server-standalone
$ sudo sh start_selenium.sh
- Stop Xvfb & selenium-server-standalone & geckodriver
$ sudo sh kill_selenium.sh
Linux (Ubuntu trusty)
Ubuntu は申し訳ないですが以下の設定を参考にしてみてください。
(いずれ自前でも動かしてみます)
試してみる
上記手順を踏めば、seleniumは立ち上がっていると思いますので
- フルスクリーンのキャプチャ
- 要素のキャプチャ
の撮り方を簡単に書いてみます。
フルスクリーンのキャプチャ
SMB\Screru\Screenshot\Screenshot
を使います。
<?php require_once '/vendor/autoload.php'; use SMB\Screru\Screenshot\Screenshot; // Screenshotをnewします $screenshot = new Screenshot(); // ファイル名 $fileName = 'full.png'; // キャプチャファイルを保存するディレクトリパス $captureDirectoryPath = '/xxx/capture_dir/'; // これでフルスクリーンのキャプチャが撮れます // $driverは Facebook\WebDriver\Remote\RemoteWebDriver です $screenshot->takeFull($driver, $captureDirectoryPath, $fileName);
要素のキャプチャ
SMB\Screru\Elements\Spec
, SMB\Screru\Elements\SpecPool
, SMB\Screru\Screenshot\Screenshot
を使います。
<?php require_once '/vendor/autoload.php'; use SMB\Screru\Elements\Spec; use SMB\Screru\Elements\SpecPool; use SMB\Screru\Screenshot\Screenshot; // Screenshotをnewします $screenshot = new Screenshot(); // ファイル名 $fileName = 'full.png'; // キャプチャファイルを保存するディレクトリパス $captureDirectoryPath = '/xxx/capture_dir/'; // 要素のセレクターを定義します $spec = new Spec('#id', Spec::GREATER_THAN_OR_EQUAL, 1); $spec2 = new Spec('.class', Spec::GREATER_THAN, 1); // SpecPoolに突っ込みます $specPool = (new SpecPool()) ->addSpec($spec) ->addSpec($spec2); // これで要素のキャプチャが撮れます // $driverは Facebook\WebDriver\Remote\RemoteWebDriver です $screenshot->takeElement($driver, $captureDirectoryPath, $fileName, $specPool);
なお、Screenshot::take()
は、Facebook\WebDriver\Remote\RemoteWebDriver::takeScreenshot()
のラッパーです。
上記を踏まえたデモ (Chrome)
<?php require_once '/vendor/autoload.php'; use SMB\Screru\Elements\Spec; use SMB\Screru\Elements\SpecPool; use SMB\Screru\Factory\DesiredCapabilities; use SMB\Screru\Screenshot\Screenshot; use SMB\UrlStatus; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\WebDriverBrowserType; use Facebook\WebDriver\WebDriverExpectedCondition; use Facebook\WebDriver\WebDriverBy; if (getenv('ENABLED_CHROME_DRIVER') !== 'true') { die('Please enable ChromeDriver.'); } $host = getenv('SELENIUM_SERVER_URL'); // Use chromedriver. $cap = new DesiredCapabilities(WebDriverBrowserType::CHROME); $driver = RemoteWebDriver::create($host, $cap->get()); // Window size. $w = 600; $h = 800; $dimension = new WebDriverDimension($w, $h); $driver->manage()->window()->setSize($dimension); $url = 'https://www.google.com/webhp?gl=us&hl=en&gws_rd=cr'; // 指定URLへ遷移 (Google) $driver->get($url); // 検索Box $findElement = $driver->findElement(WebDriverBy::name('q')); // 検索Boxにキーワードを入力して $findElement->sendKeys('Hello'); // 検索実行 $findElement->submit(); // コンテンツの中身が可視化されるまで10秒待つ(#botstuffをターゲットに) // もしも要素が現れないで10秒経った場合, // 'Facebook\WebDriver\Exception\TimeOutException' がThrowされます $driver->wait(10)->until( WebDriverExpectedCondition::visibilityOfElementLocated(WebDriverBy::id('botstuff')) ); // タイトルが `Hello - Google search` になっているかの確認 if ($driver->getTitle() !== 'Hello - Google Search') { throw new Exception('fail $driver->getTitle()'); } // HttpStatus of url $status = UrlStatus::get($driver->getCurrentURL()); if ($status->is200() === false) { throw new Exception('fail HttpStatus'); } /* |------------------------------------------------------------------------------ | Capture test. |------------------------------------------------------------------------------ */ $fileName = 'capture_demo'; $ds = DIRECTORY_SEPARATOR; $captureDirectoryPath = realpath(__DIR__ . $ds . 'capture') . $ds; // Create a Screenshot. $screenshot = new Screenshot(); // 全画面キャプチャ (拡張子は .png になります) $screenshot->takeFull($driver, $captureDirectoryPath, $fileName . '_full.png'); // 要素のセレクターを定義して $spec = new Spec('.RNNXgb', Spec::GREATER_THAN_OR_EQUAL, 1); $spec2 = new Spec('.brs_col', Spec::GREATER_THAN, 1); // SpecPoolに突っ込む $specPool = (new SpecPool()) ->addSpec($spec) ->addSpec($spec2); // 要素のキャプチャ (拡張子は .png になります) $screenshot->takeElement($driver, $captureDirectoryPath, $fileName, $specPool); // Close window. $driver->close();
動かしてみたときの gif はここで見れます。
キャプチャ
上記デモでとったキャプチャはこちら。
- capture_demo_full.png
- capture_demo_0_0.png (.RNNXgb)
- capture_demo_1_0.png (.brs_col)
- capture_demo_1_1.png (.brs_col)
IE (Windows)
上記の
$cap = new DesiredCapabilities(WebDriverBrowserType::CHROME);
を
$cap = new DesiredCapabilities(WebDriverBrowserType::IE);
こうするだけで、IEでもフルスクリーンキャプチャとれるぞ(もちろん要素も)。
※ IEDriverServer.exe
の用意と .env
の修正が必要
PHPUnitに組み込む
PHPUnit用の Trait\SMB\Screru\Traits\Testable
を用意しているので以下のように組み込みます。
// \PHPUnit_Framework_TestCase を継承したクラスでuseします class Sample extends \PHPUnit_Framework_TestCase { // use Trait use \SMB\Screru\Traits\Testable { setUp as protected traitSetUp; tearDown as protected traitTearDown; } /** * setUp */ protected function setUp() { $this->traitSetUp(); } /** * tearDown */ protected function tearDown() { $this->traitTearDown(); } // do someting ... }
フルスクリーン、要素のキャプチャを撮る
- フルスクリーンキャプチャ
Testable::takeFullScreenshot();
- 要素キャプチャ
Testable::takeElementScreenshot();
を使います。
※ Testable::takeScreenshot();
は、Facebook\WebDriver\Remote\RemoteWebDriver::takeScreenshot()
のラッパーです
テスト(assertion)失敗時にキャプチャを撮る
上記のTrait \SMB\Screru\Traits\Testable
を use
したのち、プロパティtakeCaptureWhenAssertionFails
の値を true
にします。
class Sample extends \PHPUnit_Framework_TestCase { // use Trait use \SMB\Screru\Traits\Testable { setUp as protected traitSetUp; tearDown as protected traitTearDown; } // Set this property to true protected $takeCaptureWhenAssertionFails = true; /** * setUp */ protected function setUp() { $this->traitSetUp(); } /** * tearDown */ protected function tearDown() { $this->traitTearDown(); } // do someting ... }
それか、以下関数を必要な箇所で呼びます。
(こっちのほうがいいですね)
// テスト失敗時のキャプチャ処理を有効化します $this->enableCaptureWhenAssertionFails(); // テスト失敗時のキャプチャ処理を無効化します $this->disableCaptureWhenAssertionFails();
その他設定
- デフォルトのseleniumサーバーのURLを変更する場合
$ vim .env // selenium server url SELENIUM_SERVER_URL='your selenium server url'
-
デフォルトのUserAgentを変更する場合(SPのテストで使われる)
$ vim .env // you can override the default User-agent (Android 7.1.1) OVERRIDE_DEFAULT_USER_AGENT='Mozilla/5.0 (Linux; Android 7.1.1; Nexus 5X Build/N4F26I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36'
Headless Chrome
最新のChromeであれば以下設定でヘッドレスモードになります。
※ trueにしなければ普通にブラウザが立ち上がります
- Edit
.env
// true to start headless chrome ENABLED_CHROME_HEADLESS=true
Headless Firefox
最新のFirefoxであれば以下設定でヘッドレスモードになります。
※ trueにしなければ普通にブラウザが立ち上がります
- Edit
.env
// true to start headless firefox ENABLED_FIREFOX_HEADLESS=true
テスト
ビルトインサーバを立ち上げます(立ち上げないとテストこけます)
$ php -S 127.0.0.1:8000 -t tests/web
ポート番号は .env
ファイルの LOCAL_PORT
の値と揃えます。
テスト実行
$ vendor/bin/phpunit
おわりに
準備がめんどくさい印象が強いですが、それさえ出来てしまえば簡単なe2eテストはサクッと書けるかと思います。
(エビデンスが求められるところが未だにあるかわからないですが)キャプチャもとれるし。
※ ただし、スクロールバーの操作を伴うものやjsなどで小難しいことをしているページだと今のところ対応はしてません。そこは独自にがんばってもらう方向で。。
あとは、よくありそうなパターン (目視が必要なやつとか、metaタグとかの確認とか) を簡単に確認出来るような機能を追加していきたいなぁと思っています。
ではでは。