12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Selenium/AppiumAdvent Calendar 2017

Day 8

OctoberCMSでLaravel Dusk + Seleniumを使ってE2Eテストをする

Last updated at Posted at 2017-12-03

Seleniumのアドベントカレンダーからこの記事を見て「OctoberCMSって何」と言う人のために少し説明すると、OctoberCMSとはLaravelベースのCMSです。まだまだ流行ってませんが、いくつかあるLaravelベースのCMSの中ではダントツの完成度です。WordPressよりも技術的な知識を必要としますが、Laravelベースだったり、拡張性・柔軟性が高いので、とても開発がしやすいです。

2017/12現在、OctoberCMSのドキュメントにはE2Eテストを実施する方法がFunctional testの説明としてあるが、自分がトライしたところChromeに接続できないなど問題があったり、使っているパッケージのバージョンが古くてメンテされていないようだ。

逆に、Laravel5ではDuskというテストフレームワークが含まれているので、せっかくならばそれを利用したい。OctoberCMSのドキュメントでは触れられていないが、OctoberCMSでDuskを使うことができたので、手順をまとめてみた。

ちなみに、Duskがどんなものかというと、結局のところPHPUnitfacebook/php-webdriverSelenium(またはスタンドアロン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.phpprovidersLaravel\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の設定をしなくて良くなるので、少しだけきれいになるのではないか。

12
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?