2018-04-12 追記
出来る限りシンプルな構成で Laravel Dusk x Wercker x Headless Chrome のサンプルを新たに作ってみました。
Dockerイメージ
Docker Hub
GitHub
Laravel Dusk サンプル
Wercker実行結果
尚、以前のWercker実行結果は誤って削除してしまいました orz
概要
Laravel DuskをWerckerで動かすためのDockerイメージを作成しました。このイメージはDocker Hubで公開してあります。
Werckerで複雑な設定無しに実行できることを意識したので、必要なものが一式揃っているDockerイメージです。主に次の通りです。(シンプルな設定を保ちつつ合理的に分割できるならそうしたい。。。)
- PHP 7.1.2
- PHP-FPM
- Nginx
- MariaDB
- webdriver-manager (for Selenium Server)
- PhantomJS
- Supervisor
- Capistrano
備忘録として、具体的な設定を書いたサンプルプロジェクトもGitHubに置いてあります。
https://github.com/mamor/dusk-on-wercker-example
この記事では、上記のサンプルプロジェクトを用いた実行方法と、躓いたポイント等を説明します。
実行方法
ダウンロード
$ git clone https://github.com/mamor/dusk-on-wercker-example.git
$ cd dusk-on-wercker-example/
$ yarn install # or "npm install"
ローカルでの実行方法
docker-composeを用います。
$ docker-compose run --rm testing bash -i -c "gulp --gulpfile=/var/app/gulpfile.js ci:testing:all"
これでdusk(と、ついでにphpunit)が実行できます。"ci:testing:all"の箇所を"ci:testing:phpunit"または"ci:testing:dusk"にすると、それぞれ単独でも実行できます。gulpを用いている理由は、phpunitとduskを並列で実行するためです。
docker-compose.ymlは次の通りです。
https://github.com/mamor/dusk-on-wercker-example/blob/master/docker-compose.yml
# PHPUnit
# docker-compose run --rm testing bash -i -c "gulp --gulpfile=/var/app/gulpfile.js ci:testing:phpunit"
# Laravel Dusk
# docker-compose run --rm testing bash -i -c "gulp --gulpfile=/var/app/gulpfile.js ci:testing:dusk"
# Both
# docker-compose run --rm testing bash -i -c "gulp --gulpfile=/var/app/gulpfile.js ci:testing:all"
version: "2"
services:
testing:
image: madworks/php-ci
command: tail -f /dev/null
volumes:
- ~/.composer/cache:/root/.composer/cache
- ./:/var/app
- .env.ci.app:/var/app/.env
- /var/app/vendor
Werckerでの実行方法
予め、Wercker側で"build"と"deploy"という名前のpipelineを用意します。"build"は最初からあるので、実質的には"deploy"を新規作成するだけでした。また、workflowで"build"の成功時に"deploy"を実行するように設定しておきます。
wercker.ymlは次の通りです。
https://github.com/mamor/dusk-on-wercker-example/blob/master/wercker.yml
box: madworks/php-ci
build:
steps:
- script:
name: build
code: |
yarn config set cache-folder ${WERCKER_CACHE_DIR}/yarn
source /root/.phpbrew/bashrc
cp -r ./ /var/app
cp .env.ci.app /var/app/.env
yarn install --prefer-offline --production
gulp ci:testing:all
deploy:
steps:
- script:
name: deploy
code: |
which cap
"ci:testing:all"の箇所は、docker-compose.ymlと同様です。"deploy"の内容は、capコマンドのパスを出力するだけになっています。実際にはCapistranoの設定や実行コマンドを書く想定です。もちろん、Deployerでも構いません。
実行結果は次の通りです。
以上が、実行方法です。ローカルとWerckerとで異なるのは、ファイルの設置方法だけで、後はgulpで共通化しています。次に、前述したgulpのタスク"ci:testing:all"の流れを説明します。細かなタスクの内容は、ソースをご覧下さい。
gulp ci:testing:all
gulp.task('ci:testing:all', (callback) => {
runSequence(
['ci:supervisord', 'ci:copy'], // 1
['ci:php'], // 2
['ci:mysql'], // 3
['ci:migrate'], // 4
['ci:run:dusk', 'ci:run:phpunit'], // 5
callback);
});
- "ci:supervisord"でwebdriver-manager,nginx,php-fpm,mariadbを起動。"ci:copy"でduskが実行される側(nginx配下 = /var/www)のファイルを配置
- "ci:php"でduskを実行する側(/var/app)と実行される側(/var/www)の準備
- "ci:mysql"でデータベースの準備
- "ci:migrate"でマイグレーションを実行
- "ci:run:dusk"でduskを実行。"ci:run:phpunit"でphpunitを実行
となります。"/var/app"はdev用ライブラリ込みでcomposer install、"/var/www"は--no-devでcomposer installしています。また、このテストではDBを用いていませんが、疎通確認を兼ねてマイグレーションを実行しています。gulpを使うと並列で良い処理、直列であるべき処理の管理が楽ですね。
躓いたポイントや問題点
"TTY mode requires /dev/tty to be read/writable."エラー
追記: この問題は https://github.com/laravel/dusk/pull/226 で解決されました。
dusk実行時に、次と同じ内容のエラーが出ました。
https://laracasts.com/discuss/channels/testing/tty-mode-requires-devtty-to-be-writable
次のissuesを真似して"script"コマンドにすると、確かに実行はできるのですが、テスト失敗時もWerckerのbuildが継続してしまいました。終了コードが伝播されない感じでしょうか。
https://github.com/wercker/wercker/issues/95
この問題を解決するために、とりあえず"DuskCommand"を拡張しました。実は、前述のサンプルプロジェクトでは、duskを"php artisan app:dusk"として実行しています。
https://github.com/mamor/dusk-on-wercker-example/commit/ac0666fa7d470f08fbf02fc162b4415f583ea8ff#diff-2188cf5d4ddf4333bd48355426788696
やりたかったことは"setTty(false)"です。オリジナルでは、Windowsの場合にfalse、それ以外の場合にtrueとなっていて、まだ、その意図をよく理解できていません。一応、PRは出しておきました。 https://github.com/laravel/dusk/pull/136
そして、--no-dev時にduskをインストールしたくなかったので"app/Console/Kernel.php"におけるコマンド登録が次のようになっています。
https://github.com/mamor/dusk-on-wercker-example/commit/ac0666fa7d470f08fbf02fc162b4415f583ea8ff#diff-dc9276478c4a31a6639a7c904c29ac04
ChromeとPhantomJSの切り分け
実用を考えると、普段はChromeで動かし、CI環境等ではPhantomJSで動かしたかったので、DuskTestCase.phpを次のようにしました。
https://github.com/mamor/dusk-on-wercker-example/commit/ac0666fa7d470f08fbf02fc162b4415f583ea8ff#diff-3d758536f1d68e823ad5ec04b8921a1e
以上となります。