【Laravel Dusk】テストの生成と基本的な操作

# はじめに
`E2Eテスト`を行う際に、初めて`Laravel Dusk`を使う機会がありました。
テストを生成する方法やよく使うメソッド、アサートなど、忘れないよう備忘録として残したいと思います。

# 目次
・ **[コマンド](#コマンド)**
　- [テストを生成](#テストを生成) 
　- [テストを実行](#テストを実行) 
・ **[ブラウザ](#ブラウザ)**
　- [ブラウザの生成](#ブラウザの生成) 
　- [URIに移動](#uriに移動) 
　- [ウィンドウのサイズ変更](#ウィンドウのサイズ変更) 
　- [認証](#認証) 
　- [スクリーンショットの取得](#スクリーンショットの取得) 
・ **[要素の操作](#要素の操作)**
　- [Duskセレクタ](#duskセレクタ) 
　- [値の取得と設定](#値の取得と設定) 
　- [テキストの取得](#テキストの取得) 
　- [フォーム操作](#フォーム操作) 
　- [ボタンの押下](#ボタンの押下) 
　- [待機](#待機) 
・ **[アサート](#アサート)**
　- [assertSee/assertDontSee](#assertseeassertdontsee) 
　- [assertSeeIn/assertDontSeeIn](#assertseeinassertdontseein) 
　- [assertChecked/assertNotChecked](#assertcheckedassertnotchecked) 
　- [assertSelected/assertNotSelected](#assertselectedassertnotselected) 
　- [assertInputValue/assertInputValueIsNot](#assertinputvalueassertinputvalueisnot) 

# コマンド

## テストを生成
```
php artisan dusk:make クラス名
```
テストを生成するには`Artisan`コマンドの`dusk:make`を使います。
生成されたテストは`tests/Browser`の配下に置かれます。
`tests/Browser`の配下でディレクトリに分けたい場合は、コマンドの`クラス名`の部分を`ディレクトリ名/クラス名`と変更すると実現できます。

テストを生成するとデフォルトで下記のようなソースコードが実装されています。
下記で言うと`testExample()`が一つのテストとなるので、その中にテスト内容を実装していきます。
```php:tests/Browser/IndexTest.php
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;

class IndexTest extends DuskTestCase
{
    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function testExample()
    {
        $this->browse(function (Browser $browser) {
            $browser->visit('/')
                    ->assertSee('Laravel');
        });
    }
}
```

## テストを実行
```
php artisan dusk
```
テストを実行するには`Artisan`コマンドの`dusk`を使います。
実行すると`tests/Browser`の配下にあるテストが全て実行されます。
特定のディレクトリやテストファイルのみ実行したい場合は、コマンドの後ろにパスを指定します。
```
php artisan dusk test/Browser/ディレクトリ名/クラス名
```

# ブラウザ

## ブラウザの生成
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        // ブラウザテスト内容
    });
}
```
#### $this->browse(テスト内容を実装したクロージャ);
ブラウザを生成するにはテスト内から`browse()`メソッドを呼び出します。
引数には行いたいテスト内容の`クロージャ`を実装します。

## URIに移動
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->visit('/login');
        // or
        $browser->visitRoute('login');
    });
}
```
#### $this->visit(パス); <br> $this->visitRoute(名前付きルートの名前);
特定の`URI`に移動するには、`visit()`メソッドを使用し、引数には`移動先のパス`を指定します。
名前付きルートへの移動は`visitRoute()`メソッドを使用します。

## ウィンドウのサイズ変更
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->resize(1920, 1080);
        $browser->maximize();
    });
}
```
#### $this->resize(横, 縦); <br> $this->maximize();
ウィンドウサイズの変更は`resize()`メソッドを使用し、引数には`縦横のサイズ`を指定します。
またサイズを最大化するには`maximize()`メソッドを使用します。

## 認証
```php
use App\Models\User;
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->loginAs(User::find(1));
    });
}
```
#### $this->loginAs(モデル or モデルインスタンスに関連づけられた主キー);
テストを行うシステムにログインするには`loginAs()`メソッドを使用します。
`loginAs()`の引数には、ログインする`モデル`またはモデルインスタンスに関連づけられた`主キー`を指定します。

## スクリーンショットの取得
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->screenshot('filename');
    });
}
```
#### $this->screenshot(ファイル名);
ブラウザのスクリーンショットを取るには`screenshot()`メソッドを使用します。
スクリーンショットは`tests/Browser/screenshots`に保存されます。
`screenshot()`の引数には保存したい`ファイル名`を指定し、`tests/Browser/screenshots`配下でディレクトリを分けたい場合は`ディレクトリ名/ファイル名`を指定します。

# 要素の操作

## Duskセレクタ
例えばボタンをクリックするテストを行いたい場合下記のようなテストを実装します。
```php
// HTML
<div class="search-page">
    <button>検索</button>
</div>

// TEST
public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->click('.index-page button');
    });
}
```
クリックしたい要素の`CSSセレクタ`を`click()`メソッドの引数に指定しなければなりません。
しかし実際により複雑なHTMLとなると`CSSセレクタ`を指定することが難しくなります。
そのような場合に`Duskセレクタ`を使用すると、簡単に要素を操作することができます。
```php
// HTML
<div class="search-page">
    <button dusk="search-button">検索</button>
</div>

// TEST
public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->click('@search-button');
    });
}
```
対象となるHTML要素に`dusk`属性を追加し、テストでの要素指定には`@`と属性名を指定することで、簡単に要素の操作をすることができます。

## 値の取得と設定
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $value = $browser->value('@user-name');
        $browser->value('@user-name', 'テストユーザ');
    });
}
```
#### 取得 ： $this->value(セレクタ);<br>設定 ： $this->value(セレクタ, 設定値);
要素の値を取得、設定するには`value()`メソッドを使用します。
取得する際は引数に`セレクタ`を指定し、設定する際は`セレクタ`と`設定したい値`を指定します。

## テキストの取得
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $text = $browser->text('@title');
    });
}
```
#### 取得 ： $this->text(セレクタ);
要素の表示テキストを取得するには`text()`メソッドを使用し、引数には`セレクタ`を指定します。

## フォーム操作
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        // 入力
        $browser->type('name', 'テストユーザ');
        // 入力値をクリア
        $browser->clear('name');
        // ドロップダウンの選択
        $browser->select('size', 'Large');
        // チェックボックスをチェックする
        $browser->check('terms');
    });
}
```
#### $this->type(name属性, 入力値);
入力フィールドへのテキストの入力には`type()`メソッドを使用し、第一引数には`入力フィールドのname属性`を、第二引数には`入力値`を指定します。
#### $this->clear(name属性);
入力値をクリアするには`clear()`メソッドを使用し、引数には`入力フィールドのname属性`を指定します。
#### $this->select(name属性, optionのvalue値);
ドロップダウンを選択するには`select()`メソッドを使用し、第一引数には`select要素のname属性`を、第二引数には`選択するoptionのvalue値`を指定します。
#### $this->check(name属性);
チェックボックスをチェックするには`check()`メソッドを使用し、引数には`チェックボックスのname属性`を指定します。
チェックを解除するには`uncheck()`メソッドを使用します。

## ボタンの押下
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->press('検索');
    });
}
```
#### $this->press(表示テキスト or セレクタ);
ボタン要素を押下するには`press()`メソッドを使用します。
引数にはボタンの`表示テキスト`もしくは`セレクタ`を指定することができます。
`press()`メソッドは**ボタン要素**にのみ使用できるため、その他要素のクリックには`click()`要素を使用します。

## 待機
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        // セレクタの待機
        $browser->waitFor('@user-name');
        $browser->waitFor('@user-name', 1);
        // テキストの待機
        $browser->waitForText('Hello World!');
        $browser->waitForText('Hello World!', 2);
    });
}
```
#### $this->waitFor(セレクタ); / $this->waitFor(セレクタ, 秒数);<br>$this->waitForText(テキスト); / $this->waitForText(テキスト, 秒数);
特定の要素が表示されるまでテストの実行を待機(一時停止)するには`waitFor()`メソッドを使用します。
引数には待機したい対象の要素の`セレクタ`を指定し、最長5秒テストを一時停止します。
待機時間を指定したい場合は第二引数に`秒数`を指定します。
指定したテキストが表示されるまで待機したい場合は`waitForText()`メソッドを使用します。
引数には対象の`テキスト`を指定し、セレクタの待機と同じく時間を指定したい場合は第二引数に指定します。

# アサート

## assertSee/assertDontSee
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->assertSee('ログインユーザ/テストA');
        $browser->assertDontSee('ログインユーザ/テストB');
    });
}
```
#### $this->assertSee(テキスト); <br>$this->assertDontSee(テキスト);
特定のテキストが画面上に存在することを宣言するには`assertSee()`メソッドを、存在しないことを宣言するには`assertDontSee()`メソッドを使用します。
引数にはどちらも対象の`テキスト`を指定します。

## assertSeeIn/assertDontSeeIn
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->assertSeeIn('@login-user', 'ログインユーザ/テストA');
        $browser->assertDontSeeIn('@login-user', 'ログインユーザ/テストB');
    });
}
```
#### $this->assertSeeIn(セレクタ, テキスト); <br>$this->assertDontSeeIn(セレクタ, テキスト);
特定のテキストがセレクタに含まれていることを宣言するには`assertSeeIn()`メソッドを、含まれていないことを宣言するには`assertDontSeeIn()`メソッドを使用します。
引数にはどちらも対象の`セレクタ`と`テキスト`を指定します。

## assertChecked/assertNotChecked
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->assertChecked('red');
        $browser->assertNotChecked('blue');
    });
}
```
#### $this->assertChecked(セレクタ or name属性); <br>$this->assertNotChecked(セレクタ or name属性);
特定のチェックボックスがチェック済みであることを宣言するには`assertChecked()`メソッドを、チェックされていないことを宣言するには`assertNotChecked()`メソッドを使用します。
引数にはどちらも`セレクタ または name属性`を指定します。

## assertSelected/assertNotSelected
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->assertSelected('@age', '10');
        $browser->assertNotSelected('@age', '20');
    });
}
```
#### $this->assertSelected(セレクタ or name属性, 選択値); <br>$this->assertNotSelected(セレクタ or name属性, 選択値);
特定のドロップダウンで特定の値が選択されていることを宣言するには`assertSelected()`メソッドを、選択されていないことを宣言するには`assertNotSelected()`メソッドを使用します。
引数にはどちらも`セレクタ または name属性`と`選択するoptionのvalue値`を指定します。

## assertInputValue/assertInputValueIsNot
```php
use Laravel\Dusk\Browser;

public function testExample()
{
    $this->browse(function (Browser $browser) {
        $browser->assertInputValue('@name', 'テストユーザ');
        $browser->assertInputValueIsNot('name', '管理者ユーザ');
    });
}
```
#### $this->assertInputValue(セレクタ or name属性, 入力値); <br>$this->assertInputValueIsNot(セレクタ or name属性, 入力値);
特定の入力フィールドが特定の値を持っていることを宣言するには`assertInputValue()`メソッドを、持っていないことを宣言するには`assertInputValueIsNot()`メソッドを使用します。
引数にはどちらも`セレクタ または name属性`と`入力値`を指定します。

# 参考
https://readouble.com/laravel/8.x/ja/dusk.html