Seleniumのアドベントカレンダーからこの記事を見て「OctoberCMSって何」と言う人のために少し説明すると、OctoberCMSとはLaravelベースのCMSです。まだまだ流行ってませんが、いくつかあるLaravelベースのCMSの中ではダントツの完成度です。WordPressよりも技術的な知識を必要としますが、Laravelベースだったり、拡張性・柔軟性が高いので、とても開発がしやすいです。
2017/12現在、OctoberCMSのドキュメントにはE2Eテストを実施する方法がFunctional testの説明としてあるが、自分がトライしたところChromeに接続できないなど問題があったり、使っているパッケージのバージョンが古くてメンテされていないようだ。
逆に、Laravel5ではDuskというテストフレームワークが含まれているので、せっかくならばそれを利用したい。OctoberCMSのドキュメントでは触れられていないが、OctoberCMSでDuskを使うことができたので、手順をまとめてみた。
ちなみに、Duskがどんなものかというと、結局のところPHPUnitとfacebook/php-webdriverとSelenium(またはスタンドアロンchromedriver)をLaravelベースのプロジェクトで使うためのパッケージだ。
更新
DockerコンテナからホストマシンのSeleniumにアクセスするのにホストのIPを指定する方法を記載していたが、現在では docker.for.mac.localhost
でアクセスできるので、IP周りの込み入った話を削除した。
前提
- 完全に自分の都合だが、OctoberCMSプロジェクトはDockerコンテナ内で走らせている
- OctoberCMSはLaravel5.5ベースのバージョン(Dusk使うにはLaravel5.5ベースが必要)
- コンテナ内の実行環境はPHP7+nginx(Laravel5.5ベースのOctoberCMSはPHP7が必須)
Laravel5.5ベースのOctoberCMSを使う方法は「OctoberCMSの導入」で説明している。edgeUpdates
のあたりが参考になる。
インストール
Selenium と Chrome Driver のインストール
自分の場合、
- 他のブラウザも将来的に対応したいのでSelenium + chromedriverで運用する
- ブラウザが入っていないDockerコンテナでOctoberCMSを走らせているため、ブラウザの入っているローカルマシンにこれらをインストールする
ローカルマシンでOctoberCMSを走らせている場合、Chromeだけを使うならばこれらをインストールする必要はない。Duskはスタンドアロンchromedriverをデフォルトで使用するようになっている。
下記を**ローカルマシン(コンテナのホストマシン)**で実行してSeleniumをインストール。
brew update
brew install selenium-server-standalone
selenium-server --version
こちらもローカルマシンで実行してchromedriverをインストール。
brew install chromedriver
Dusk のインストール
composerに追加
DuskはLaravelのドキュメントに書いてある様にcomposerでインストールする。こちらはコンテナ内で実行。注意:Octoberが使用しているLaravelのバージョンは5.5(2019/07/09現在)で、これに合うduskバージョンは2.xになる。バージョン3以降だとサポートから外されてしまっている。
composer require --dev laravel/dusk:^2.0
自分のコンテナ内ではrootでログインするのでcomposerコマンドを実行した後はプロジェクトのファイルの権限を修正してやる必要がある。例えば自分の場合はdocker-syncでファイルをローカルとコンテナで同期させているので、docker-syncのsync_userid
のユーザにchown
してやる必要がある。例えば、自分の環境の場合 chown -R www-data:www-data *
。
Service Providerの追加
開発環境のみで DuskServiceProvider
が有効になるようにする。
- プロジェクトルートに
config/dev
ディレクトリを作成 -
config/app.php
を作成したconfig/dev/
にコピー - .envファイルに
APP_ENV=dev
を追記 -
config/dev/app.php
のproviders
にLaravel\Dusk\DuskServiceProvider
を追加
'providers' => array_merge(include(base_path('modules/system/providers.php')), [
...
'Laravel\Dusk\DuskServiceProvider',
]),
インストールコマンド実行
コンテナ内のプロジェクトルートで下記を実行。念のため上記同様の理由でchown
も実行。
php artisan dusk:install
chown -R www-data:www-data
設定
クラスが認識されるようにする
もし tests/CreatesApplication.php
がプロジェクトになければ下記の内容で作成。内容はここから拝借。
<?php namespace Tests;
use Illuminate\Contracts\Console\Kernel;
trait CreatesApplication
{
/**
* Creates the application.
*
* @return \Illuminate\Foundation\Application
*/
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
return $app;
}
}
作成したPHPファイルと tests/DuskTestCase.php
を composer.json に追記して認識されるようにする。
"autoload-dev": {
"classmap": [
"tests/CreatesApplication.php",
"tests/DuskTestCase.php",
...
]
},
代わりに下記でも良さそう。
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
...
}
}
そして、下記を実行。再度、念のためchown
も。
composer dump-autoload
chown -R www-data:www-data
DuskTestCaseを修正
もし、テストをローカルマシン、またはブラウザが入っているコンテナ内で実行するのであれば、このステップは不要。
デフォルトのDuskTestCase
の実装では、テスト実行場所のchromedriverを自動で起動してそこに接続するようになっているので、自分の様に、テストをブラウザが入っていないコンテナ内で実行する場合は、ブラウザがあるローカルマシンのselenium(またはchromedriver)に接続する必要がある。
tests/DuskTestCase.php を以下のように修正する。
-
static::startChromeDriver();
をコメントアウト -
RemoteWebDriver::create
呼び出し時のURLパラメータをhttp://docker.for.mac.localhost:4444/wd/hub
に変更。
public static function prepare()
{
//static::startChromeDriver();
}
/**
* Create the RemoteWebDriver instance.
*
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
*/
protected function driver()
{
$options = (new ChromeOptions)->addArguments([
'--disable-gpu',
'--headless'
]);
return RemoteWebDriver::create(
'http://docker.for.mac.localhost:4444/wd/hub', DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY, $options
)
);
}
タイムアウトを伸ばす
- もし、テスト実行してタイムアウトエラーになる場合、下記のように
RemoteWebDriver::create
に引数を渡してタイムアウト時間を変更できる。 - 自分の場合、1分ではタイムアウトになるので、3分(180*1000)に変更して解決した。
return RemoteWebDriver::create(
'http://docker.for.mac.localhost:4444/wd/hub', DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY, $options
), 180*1000, 180*1000
);
もしそれでも解決しない場合、こちらが参考になるかも。
https://laracasts.com/discuss/channels/testing/dusk-doesnt-work-app-updated-to-laravel-54/replies/311354
テストの実行
Duskにはサンプルテスト (tests/Browser/ExampleTest.php
) がついてくるので、これを実行してセットアップできているか確認できる。
サンプルテストの修正
サンプルテストはまっさらなLaravelプロジェクトでパスするテストなので、ここではOctoberCMSのdemoテーマでパスするように修正する。
ExampleTest.php
はロードしたページに"Laravel"の文字列があるかどうかをチェックしているが、これを"October CMS"に変更する。
public function testBasicExample()
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertSee('October CMS');
});
}
Seleniumの起動
ローカルマシンで下記を実行して、Seleniumを起動する。chromedriverは自動的にロードされる。
selenium-server
テスト実行
プロジェクトが走るコンテナ内のプロジェクトルートで下記を実行することでテストを走らせることができる。
php artisan dusk
テストの実行は2分近くかかる。
テストに失敗した場合など、自動的にスクリーンショットを撮って、デフォルトでは tests/Browser/screenshots
に格納してくれる。
おまけ
Seleniumをローカルマシンではなく別のコンテナで走らせるというのも1つの選択肢だ。ローカルマシンにSeleniumを入れなくて良かったり、ホストのIPの設定をしなくて良くなるので、少しだけきれいになるのではないか。