php-webdriverのラッパーライブラリ”screru”のバージョンをあげた

投稿日:

というわけでバージョンを上げました(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が入っていなければインストールが必要です。

パスを通す

  • ChromeDrivergeckodriver のパスを通します
    • 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
      

任意のパスにあるドライバーを使う場合

任意のパスにあるドライバーを使いたい場合、.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.

テストを実行して上記エラーが表示されたら以下リンクを参照してみてください。

要は、IEのインターネットオプション-セキュリティにおいて、すべてのゾーンの設定を同じにすればいい(保護モードを有効にする)だけです。地味にめんどくさいけど。

Linux (CentOS 6.9)

javaFirefoxXvfb のインストールが必要です(入っていなければ)。

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 を起動させないといけないので)

  1. Run Xvfb & selenium-server-standalone
    $ sudo sh start_selenium.sh
    
  2. 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&amp;hl=en&amp;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\Testableuse したのち、プロパティ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タグとかの確認とか) を簡単に確認出来るような機能を追加していきたいなぁと思っています。

ではでは。

作成者: shimabox

Web系のプログラマをやっています。 なるべく楽しく生きていきたい。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください