Laravel Dusk テストコード作成時の困った場合の対処法

Laravel dusk でブラウザテストを作成していて困った部分の対処法のメモです。
間違っている箇所があればご指摘いただければ幸いです。

## dusk失敗時の画面スクリーンショット
app\tests\Browser\screenshots配下に失敗時の画面スクリーンショットが作成されます。

## 要素の表示をwaitで待つ

```
$browser->waitForText('検索', 30);
$browser->waitFor("#search", 30);
```

## 要素がクリックできないとき
素のjsで要素をクリックする(サービスプロバイダにマクロを登録する 参照)

```
//クリックする
$browser->clickToElement(".search_btn");
```

## 画面内に表示されていない要素がクリックできないとき
素のjsで要素にスクロールする(サービスプロバイダにマクロを登録する 参照)

```
//クリックする
$browser->scrollToElement(".search_btn");
```

## サービスプロバイダにマクロを登録する
ブラウザマクロを作成し、サービスプロバイダにマクロを登録する。

[参考]
https://readouble.com/laravel/5.7/ja/dusk.html (ブラウザマクロ 部分参照)
https://readouble.com/laravel/5.3/ja/providers.html (プロバイダの登録 部分参照)
https://github.com/laravel/dusk/issues/203 (マクロ登録例)

```
<?php
namespace App\Providers;

use Laravel\Dusk\Browser;
use Illuminate\Support\ServiceProvider;

class DuskServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        Browser::macro('scrollToElement', function ($element = null) {
            $this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);");

            return $this;
        });

        Browser::macro('clickToElement', function ($element = null) {
            $this->script("document.querySelector('$element').click();");

            return $this;
        });

        Browser::macro('switchFrame', function ($frame = null) {
            if ($frame) {
                $this->driver->switchTo()->defaultContent()->switchTo()->frame($frame);
            } else {
                // Main frame
                $this->driver->switchTo()->defaultContent();
            }
            return $this;
        });
    }
}
```
```
config/app.php
'providers' => [
    // Other Service Providers

    App\Providers\DuskServiceProvider::class,
],
```

※`Class 'App\Providers\DuskServiceProvider' not found`登録したマクロが見つからないというエラーが表示された場合、キャッシュファイルを削除すること。

```
artisan cache:clear
artisan config:clear
artisan route:clear
artisan view:clear
```

## testの中断(Ctrl + c)でDB接続先がずれた？
.env / .env.dusk.local(.env.dusk.{environment}) の中身を確認する。 
テスト中は.envの内容が一時backupファイルに退避され、.env.dusk.localの内容が.envに書き込まれるようですが、
中断により.envの内容が.env.dusk.localのまま、backupファイルが残った状態という現象が私のDockerテスト環境では起こりました。
.envを戻し、backupファイルを削除すると戻ります。
(そしてキャッシュファイルも削除)

## chromeの設定ファイル (UAを変えたい 画面サイズを変更したいなどはここで)
DuskTestCase.php


```
    protected function driver()
    {
        $options = (new ChromeOptions)->addArguments([
            '--disable-gpu',
            '--headless',
            '--window-size=375,667',
            '--no-sandbox',
            '--lang=ja_JP',
            '--disable-dev-shm-usage'
        ]);

        $ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.91 Mobile/15E148 Safari/605.1';
        $options->setExperimentalOption('mobileEmulation', ['userAgent' => $ua]);

        return RemoteWebDriver::create(
            'http://selenium:4444/wd/hub', DesiredCapabilities::chrome()->setCapability(
                ChromeOptions::CAPABILITY, $options
            )
        );
    }
```

## head部分のテスト 
duskはcssセレクターで検証しようとすると先頭に'body'がつくため、bodyタグより上の要素の検証をしたい場合はこの書き方で

```
 $browser->assertSourceHas("<meta name=\"description\" content=\"Qiitaは情報満載！\">");
```

## xpathを使って要素の値を取り出すことも可能

```
use Laravel\Dusk\Browser;
use Facebook\WebDriver\WebDriverBy;　//xpath用
略
$browser->driver->findElement(WebDriverBy::xpath("//link[@rel='canonical']"))->getAttribute('href')
```

## Rspec の before after のようなものを実装したい
[参考]
https://cpoint-lab.co.jp/article/201812/7155/

```
public function setUp() :void
{
    parent::setUp();
    // テストデーターの準備などを行う
}
```

## PHPUnitのアサーションも使えます

```
$this->assertEquals($element_count, 50);
```



## セッションの破棄

```
  $browser->driver->manage()->deleteAllCookies();
```

## function日本語化(@testつける)

```
/**
 * @test
 */
public function ステータステスト()
{
    $res = $this->get("url");
    $res->assertStatus(200);
}
```

## テストをグループ化して実行 (@group アノテーションでグループ化)

`php artisan dusk tests/Browser/ --group samplegroup`

```
/**
 * @group samplegroup
 */
public function sampleTest()
{
   //処理
```
## テストをファイル単位で実行

`php artisan dusk tests/Browser/SampleTest.php`


## Factoryで作成したデーターをテスト実行前に書き換える方法
```
$this->test_data->fill(["time" => "9:00"])->save();
複数でもOK
$data = ["status" => 1, "time" => "9:00", "end_time" => "10:00"];
$this->test_data->fill($data)->save();
```
## The MAC is invalid.
暗号化キーを再生成する → php artisan key:generate 
※暗号化したパスワードが複号できなくなるので取り扱い注意
[引用]
https://error-search.com/error-post/detail/144/The%2BMAC%2Bis%2Binvalid.

## APP_DEBUG=true のデバックモードにしたままでテストを実行するとfailする
デバックバーが邪魔をして要素が見えていないため
APP_DEBUG=true は.env.dusk.localに入れない

## HTML5 Form Validation ブラウザに依存するエラーメッセージがテストの邪魔をする
問題なければ、ブラウザ自動バリデーションを無効化してしまう

```
<form action="test.php" method="post" novalidate="novalidate">
```