LaradockでDuskやろうとしたらちょっと手間が必要だった件

# そもそもの話

最近、Laradock触ってないなぁ、と思ったので、試しにDuskを動かそうと思ったことから始まりました。
環境はすでに作成しているものを使っています。

# やってみたいこと

* Laravelをサブディレクトリとして構築
* Duskのテストが通る

# とりあえずの前提条件

* Webサーバのrootとしては、 `/var/www/public` を指定
* Laravelのrootは `/var/www/public/lara1` 、URLも `http://localhost/lara1`  でアクセスできるようにする
* 他の設定は標準(Seleniumアクセスのポートは4444で、など)

# Laradock起動コマンド

Webサーバはnginx、データベースはmysqlを使います。
Chromeはseleniumコンテナに入っているので同時に起動します。
あとは適当に

```
docker-compose up workspace nginx mysql selenium
```

# Dusk導入まで

やり方は２つの参考記事をもとに対応。

参考1: https://qiita.com/amymd/items/0a5f2705e29972d0d22e
参考2: https://qiita.com/hrkbyc/items/755e9799c205c092c323

コマンドは以下の順番で処理していきます。

```
cd /var/www/public
composer create-project laravel/laravel lara1 --prefer-dist
cd lara1
composer install
composer require --dev dusk
composer update # 念の為
npm install
npm run dev
php artisan dusk:install
```

キモは、

## AppServiceProvider.phpの修正

Duskをプロバイダに登録するコードを追加します。

```AppServerProvicer.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\DuskServiceProvider; // Duskの参照を追加

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        // Duskのプロバイダを登録
        if ($this->app->environment('local', 'testing')) {
            $this->app->register(DuskServiceProvider::class);
        }
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}
```

## DuskTestCase.php の修正

baseUrlを所定のURLに、driverをSeleniumのサーバーに変更します。

```DuskTestCase.php
<?php

namespace Tests;

use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Laravel\Dusk\TestCase as BaseTestCase;

abstract class DuskTestCase extends BaseTestCase
{
    use CreatesApplication;

    // baseUrlは別サーバのサブディレクトリになるため明記
    protected function baseUrl()
    {
        return 'http://nginx/lara1';
    }

    /**
     * Prepare for Dusk test execution.
     *
     * @beforeClass
     * @return void
     */
    public static function prepare()
    {
        if (! static::runningInSail()) {
            static::startChromeDriver();
        }
    }

    /**
     * Create the RemoteWebDriver instance.
     *
     * @return \Facebook\WebDriver\Remote\RemoteWebDriver
     */
    // seleniumコンテナのChromeを使用する
    protected function driver()
    {
        return RemoteWebDriver::create(
            'http://selenium:4444/wd/hub',
            DesiredCapabilities::chrome()
        );
    }

    /**
     * Determine whether the Dusk command has disabled headless mode.
     *
     * @return bool
     */
    protected function hasHeadlessDisabled()
    {
        return isset($_SERVER['DUSK_HEADLESS_DISABLED']) ||
               isset($_ENV['DUSK_HEADLESS_DISABLED']);
    }
}
```

# さあテスト開始…ところが！？

```
php artisan dusk
```

ところが、エラーを出してしまうわけです。
Duskはちゃんと動いているようですが、どうやらLaravelのアプリがまともに動いていないと予想しました。
そこで、参考記事を元にnginxの設定をいじることにしました。

参考：https://qiita.com/saba1024/items/2d50fb8284d699924360

# 対策とってみた

## default.confの設定変更

```
vi /etc/nginx/sites-available/default.conf
```

先の記事で参照していたnginxの設定ではサブディレクトリを考慮していなかったので、色々設定を変えました。


最終的にはこういう形になりました。

特にハマったのはSCRIPT_FILENAME。
index.phpの場所が変わっているのにすぐに気づきませんでした…。
パスの指定を現在の配置に合わせました。

```
fastcgi_param SCRIPT_FILENAME $document_root/public/index.php;
```

あと、fastcgi_passの指定。
もともとあったLaravel向けの設定を読んでみて、php-upstreamコンテナを指定すれば良いことがわかりました。

```
fastcgi_pass php-upstream;
```

あとは、locationやtry_filesの設定に注意して出来上がりました。

```default.conf
    location ~ ^/lara1((/)?(.+))?$ {
        root /var/www/public/lara1;

        try_files $1 /lara1/index.php?$query_string;

        location ~ ^/lara1/index.php$ {
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root/public/index.php;
            fastcgi_param PATHINFO $fastcgi_path_info;
            fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass php-upstream;
            fastcgi_index index.php;
        }
    }
```

そして、nginxの再起動…エラーなし。

```
nginx -s reload
```

これでLaravelが動くだろう…世の中そんなに甘くありませんでした。

## 書き込み権限の変更

…Dockerのコマンドラインではrootなのに、nginx上ではnginxユーザで動かしているのをすっかり忘れていました。
storageディレクトリに書き込み権限を付記します。

```
cd /var/www/public/lara1
chmod -R a+w storage
```

# さあリベンジ！

ブラウザでは無事Laravelのアプリが表示されました。
続いてDuskでは…

```
root@6580d8cd10f5:/var/www/public/lara1# php artisan dusk
PHPUnit 9.5.2 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 00:10.353, Memory: 20.00 MB

OK (1 test, 1 assertion)
```

動いたー！　やったー！

# まとめ

過去の知見となんとか駆使すればなんとかなるということです、はい。