メインコンテンツまでスキップ

Laravel Dusk

はじめに

Laravel Dusk は、表現力豊かで使いやすいブラウザ自動化およびテストAPIを提供します。デフォルトでは、DuskはローカルコンピュータにJDKやSeleniumをインストールする必要はありません。代わりに、DuskはスタンドアロンのChromeDriver インストールを使用します。ただし、他のSelenium互換のドライバを自由に利用することもできます。

インストール

始めるには、Google Chrome をインストールし、laravel/dusk Composer 依存関係をプロジェクトに追加する必要があります:

composer require laravel/dusk --dev
警告

Duskのサービスプロバイダを手動で登録する場合は、決して 本番環境で登録しないでください。そうすると、任意のユーザがアプリケーションに認証できる可能性があります。

Duskパッケージをインストールした後、dusk:install Artisan コマンドを実行します。dusk:install コマンドは、tests/Browser ディレクトリ、Dusk テストの例、およびオペレーティングシステム用の Chrome Driver バイナリをインストールします:

php artisan dusk:install

次に、アプリケーションの .env ファイルで APP_URL 環境変数を設定します。この値は、ブラウザでアプリケーションにアクセスするために使用するURLと一致する必要があります。

注記

Laravel Sail を使用してローカル開発環境を管理している場合は、Dusk テストの設定と実行に関するSailドキュメントも参照してください。

ChromeDriver インストールの管理

Laravel Duskによってdusk:installコマンドを介してインストールされるChromeDriverのバージョンとは異なるバージョンのChromeDriverをインストールしたい場合は、dusk:chrome-driverコマンドを使用できます:

# Install the latest version of ChromeDriver for your OS...
php artisan dusk:chrome-driver

# Install a given version of ChromeDriver for your OS...
php artisan dusk:chrome-driver 86

# Install a given version of ChromeDriver for all supported OSs...
php artisan dusk:chrome-driver --all

# Install the version of ChromeDriver that matches the detected version of Chrome / Chromium for your OS...
php artisan dusk:chrome-driver --detect
警告

Duskはchromedriverバイナリが実行可能であることを要求します。Duskの実行に問題がある場合は、次のコマンドを使用してバイナリが実行可能であることを確認してください: chmod -R 0755 vendor/laravel/dusk/bin/.

他のブラウザを使用する

デフォルトでは、Dusk は Google Chrome とスタンドアロンの ChromeDriver インストールを使用してブラウザテストを実行します。ただし、独自の Selenium サーバーを起動し、希望するブラウザでテストを実行することもできます。

開始するには、アプリケーションの基本的な Dusk テストケースである tests/DuskTestCase.php ファイルを開きます。このファイル内で、startChromeDriver メソッドの呼び出しを削除することができます。これにより、Dusk が ChromeDriver を自動的に起動しなくなります:

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

次に、driver メソッドを変更して、希望する URL とポートに接続することができます。さらに、WebDriver に渡すべき「desired capabilities」を変更することもできます:

    use Facebook\WebDriver\Remote\RemoteWebDriver;

/**
* Create the RemoteWebDriver instance.
*/
protected function driver(): RemoteWebDriver
{
return RemoteWebDriver::create(
'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()
);
}

はじめに

テストの生成

Dusk テストを生成するには、dusk:make Artisan コマンドを使用します。生成されたテストは tests/Browser ディレクトリに配置されます:

php artisan dusk:make LoginTest

各テスト後にデータベースをリセットする

書くほとんどのテストは、アプリケーションのデータベースからデータを取得するページとやり取りします。ただし、Dusk テストでは RefreshDatabase トレイトを使用すべきではありません。RefreshDatabase トレイトはデータベーストランザクションを利用しており、HTTP リクエスト間で適用されないか利用できません。代わりに、DatabaseMigrations トレイトと DatabaseTruncation トレイトの 2 つのオプションがあります。

データベースマイグレーションの使用

DatabaseMigrations トレイトは、各テストの前にデータベースマイグレーションを実行します。ただし、各テストごとにデータベーステーブルを削除して再作成することは通常、テーブルを切り捨てるよりも遅くなります:

<?php

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;

uses(DatabaseMigrations::class);

//
<?php

namespace Tests\Browser;

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;

class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;

//
}
警告

Dusk テストを実行する際には、SQLite のインメモリデータベースは使用できません。ブラウザは独自のプロセス内で実行されるため、他のプロセスのインメモリデータベースにアクセスできません。

データベース切り捨ての使用

DatabaseTruncation トレイトは、最初のテストでデータベースをマイグレーションして、データベーステーブルが適切に作成されていることを確認します。ただし、後続のテストでは、データベースのテーブルは単純に切り捨てられます - すべてのデータベースマイグレーションを再実行するよりも高速化されます:

<?php

use Illuminate\Foundation\Testing\DatabaseTruncation;
use Laravel\Dusk\Browser;

uses(DatabaseTruncation::class);

//
<?php

namespace Tests\Browser;

use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTruncation;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;

class ExampleTest extends DuskTestCase
{
use DatabaseTruncation;

//
}

デフォルトでは、このトレイトは migrations テーブルを除くすべてのテーブルを切り捨てます。切り捨てるテーブルをカスタマイズしたい場合は、テストクラスに $tablesToTruncate プロパティを定義できます:

注記

Pest を使用している場合は、プロパティやメソッドをベースの DuskTestCase クラスまたはテストファイルが拡張する任意のクラスに定義する必要があります。

    /**
* Indicates which tables should be truncated.
*
* @var array
*/
protected $tablesToTruncate = ['users'];

または、テストクラスに $exceptTables プロパティを定義して、切り捨てから除外するテーブルを指定できます:

    /**
* Indicates which tables should be excluded from truncation.
*
* @var array
*/
protected $exceptTables = ['users'];

テーブルを切り捨てるべきデータベース接続を指定するには、テストクラスに $connectionsToTruncate プロパティを定義できます:

    /**
* Indicates which connections should have their tables truncated.
*
* @var array
*/
protected $connectionsToTruncate = ['mysql'];

データベース切り捨てが実行される前または後にコードを実行したい場合は、テストクラスに beforeTruncatingDatabase または afterTruncatingDatabase メソッドを定義できます:

    /**
* Perform any work that should take place before the database has started truncating.
*/
protected function beforeTruncatingDatabase(): void
{
//
}

/**
* Perform any work that should take place after the database has finished truncating.
*/
protected function afterTruncatingDatabase(): void
{
//
}

テストの実行

ブラウザテストを実行するには、dusk Artisan コマンドを実行します:

php artisan dusk

前回 dusk コマンドを実行した際にテストに失敗があった場合は、dusk:fails コマンドを使用して最初に失敗したテストを再実行することで時間を節約できます:

php artisan dusk:fails

dusk コマンドは、通常 Pest / PHPUnit テストランナーで受け入れられる任意の引数を受け入れるため、指定した グループ のテストのみを実行するなどの操作が可能です:

php artisan dusk --group=foo
注記

ローカル開発環境を管理するためにLaravel Sailを使用している場合は、Dusk テストの設定と実行に関する Sail ドキュメントを参照してください。

ChromeDriver の手動起動

デフォルトでは、Dusk は自動的に ChromeDriver を起動しようとします。これが特定のシステムで機能しない場合は、dusk コマンドを実行する前に ChromeDriver を手動で起動することができます。ChromeDriver を手動で起動する場合は、tests/DuskTestCase.php ファイルの次の行をコメントアウトする必要があります:

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

さらに、ChromeDriver を 9515 以外のポートで起動する場合は、同じクラスの driver メソッドを正しいポートに合わせて修正する必要があります:

    use Facebook\WebDriver\Remote\RemoteWebDriver;

/**
* Create the RemoteWebDriver instance.
*/
protected function driver(): RemoteWebDriver
{
return RemoteWebDriver::create(
'http://localhost:9515', DesiredCapabilities::chrome()
);
}

環境の処理

テストを実行する際に Dusk が独自の環境ファイルを使用するように強制するには、プロジェクトのルートに .env.dusk.{environment} ファイルを作成してください。たとえば、local 環境から dusk コマンドを開始する場合は、.env.dusk.local ファイルを作成する必要があります。

テストを実行すると、Dusk は .env ファイルをバックアップし、Dusk 環境を .env にリネームします。テストが完了すると、.env ファイルが復元されます。

ブラウザの基本

ブラウザの作成

始めに、アプリケーションにログインできることを検証するテストを書いてみましょう。テストを生成した後、ログインページに移動し、いくつかの資格情報を入力して「ログイン」ボタンをクリックするように変更できます。ブラウザインスタンスを作成するには、Dusk テスト内から browse メソッドを呼び出すことができます:

<?php

use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;

uses(DatabaseMigrations::class);

test('basic example', function () {
$user = User::factory()->create([
'email' => 'taylor@laravel.com',
]);

$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/login')
->type('email', $user->email)
->type('password', 'password')
->press('Login')
->assertPathIs('/home');
});
});
<?php

namespace Tests\Browser;

use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;

class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;

/**
* A basic browser test example.
*/
public function test_basic_example(): void
{
$user = User::factory()->create([
'email' => 'taylor@laravel.com',
]);

$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/login')
->type('email', $user->email)
->type('password', 'password')
->press('Login')
->assertPathIs('/home');
});
}
}

上記の例でわかるように、browse メソッドはクロージャを受け入れます。ブラウザインスタンスは Dusk によってこのクロージャに自動的に渡され、アプリケーションとのやり取りやアサーションを行うための主要なオブジェクトとして使用されます。

複数のブラウザを作成する

テストを適切に実行するためには、複数のブラウザが必要な場合があります。たとえば、Webソケットとやり取りするチャット画面をテストするには複数のブラウザが必要です。複数のブラウザを作成するには、単純にbrowseメソッドに与えられるクロージャのシグネチャにさらにブラウザ引数を追加してください:

    $this->browse(function (Browser $first, Browser $second) {
$first->loginAs(User::find(1))
->visit('/home')
->waitForText('Message');

$second->loginAs(User::find(2))
->visit('/home')
->waitForText('Message')
->type('message', 'Hey Taylor')
->press('Send');

$first->waitForText('Hey Taylor')
->assertSee('Jeffrey Way');
});

ナビゲーション

visitメソッドを使用して、アプリケーション内の指定されたURIに移動できます:

    $browser->visit('/login');

名前付きルートに移動するには、visitRouteメソッドを使用できます:

    $browser->visitRoute('login');

backおよびforwardメソッドを使用して、「戻る」と「進む」をナビゲートできます:

    $browser->back();

$browser->forward();

ページをリフレッシュするには、refreshメソッドを使用できます:

    $browser->refresh();

ブラウザウィンドウのサイズ変更

resizeメソッドを使用して、ブラウザウィンドウのサイズを調整できます:

    $browser->resize(1920, 1080);

maximizeメソッドを使用して、ブラウザウィンドウを最大化できます:

    $browser->maximize();

fitContentメソッドを使用すると、ブラウザウィンドウをコンテンツのサイズに合わせることができます:

    $browser->fitContent();

テストが失敗した場合、Duskはスクリーンショットを撮る前にブラウザを自動的にコンテンツに合わせてリサイズします。この機能を無効にするには、テスト内でdisableFitOnFailureメソッドを呼び出すことができます:

    $browser->disableFitOnFailure();

moveメソッドを使用して、ブラウザウィンドウを画面上の異なる位置に移動できます:

    $browser->move($x = 100, $y = 100);

ブラウザマクロ

さまざまなテストで再利用できるカスタムブラウザメソッドを定義したい場合は、Browserクラスのmacroメソッドを使用できます。通常、これをサービスプロバイダbootメソッドから呼び出すべきです:

    <?php

namespace App\Providers;

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

class DuskServiceProvider extends ServiceProvider
{
/**
* Register Dusk's browser macros.
*/
public function boot(): void
{
Browser::macro('scrollToElement', function (string $element = null) {
$this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);");

return $this;
});
}
}

macro関数は、最初の引数として名前、2番目の引数としてクロージャを受け入れます。マクロのクロージャは、Browserインスタンスのメソッドとしてマクロを呼び出すときに実行されます。

    $this->browse(function (Browser $browser) use ($user) {
$browser->visit('/pay')
->scrollToElement('#credit-card-details')
->assertSee('Enter Credit Card Details');
});

認証

しばしば、認証が必要なページをテストすることになります。各テストでアプリケーションのログイン画面とやり取りする必要がないように、Duskの loginAs メソッドを使用できます。loginAs メソッドは、認証可能なモデルに関連付けられたプライマリキーまたは認証可能なモデルインスタンスを受け入れます:

    use App\Models\User;
use Laravel\Dusk\Browser;

$this->browse(function (Browser $browser) {
$browser->loginAs(User::find(1))
->visit('/home');
});

警告

loginAs メソッドを使用した後は、ファイル内のすべてのテストでユーザーセッションが維持されます。

クッキー

cookie メソッドを使用して、暗号化されたクッキーの値を取得または設定できます。デフォルトでは、Laravel によって作成されたすべてのクッキーは暗号化されています:

    $browser->cookie('name');

$browser->cookie('name', 'Taylor');

plainCookie メソッドを使用して、暗号化されていないクッキーの値を取得または設定できます:

    $browser->plainCookie('name');

$browser->plainCookie('name', 'Taylor');

指定されたクッキーを削除するには、deleteCookie メソッドを使用できます:

    $browser->deleteCookie('name');

JavaScript の実行

ブラウザ内で任意の JavaScript ステートメントを実行するには、script メソッドを使用できます:

    $browser->script('document.documentElement.scrollTop = 0');

$browser->script([
'document.body.scrollTop = 0',
'document.documentElement.scrollTop = 0',
]);

$output = $browser->script('return window.location.pathname');

スクリーンショットの撮影

screenshot メソッドを使用して、スクリーンショットを撮影し、指定されたファイル名で保存できます。すべてのスクリーンショットは tests/Browser/screenshots ディレクトリに保存されます:

    $browser->screenshot('filename');

responsiveScreenshots メソッドを使用して、さまざまなブレークポイントで一連のスクリーンショットを撮影できます:

    $browser->responsiveScreenshots('filename');

screenshotElement メソッドを使用して、ページ上の特定の要素のスクリーンショットを撮影できます:

    $browser->screenshotElement('#selector', 'filename');

コンソール出力をディスクに保存

storeConsoleLog メソッドを使用して、現在のブラウザのコンソール出力を指定されたファイル名でディスクに書き込むことができます。コンソール出力は tests/Browser/console ディレクトリに保存されます:

    $browser->storeConsoleLog('filename');

ページソースをディスクに保存

storeSource メソッドを使用して、現在のページのソースを指定されたファイル名でディスクに書き込むことができます。ページのソースは tests/Browser/source ディレクトリ内に保存されます:

    $browser->storeSource('filename');

要素とのやり取り

Dusk セレクタ

要素とのやり取りに適した CSS セレクタを選択することは、Dusk テストを書く上で最も難しい部分の1つです。時間の経過とともに、フロントエンドの変更が次のような CSS セレクタを壊してしまうことがあります:

    // HTML...

<button>Login</button>

// Test...

$browser->click('.login-page .container div > button');

Dusk セレクタを使用すると、効果的なテストの記述に集中することができ、CSS セレクタを覚える必要がありません。セレクタを定義するには、HTML 要素に dusk 属性を追加します。その後、Dusk ブラウザとやり取りする際には、テスト内でアタッチされた要素を操作するためにセレクタの前に @ を付けます:

    // HTML...

<button dusk="login-button">Login</button>

// Test...

$browser->click('@login-button');

必要に応じて、selectorHtmlAttribute メソッドを使用して、Dusk セレクタが利用する HTML 属性をカスタマイズすることができます。通常、このメソッドはアプリケーションの AppServiceProviderboot メソッドから呼び出すべきです:

    use Laravel\Dusk\Dusk;

Dusk::selectorHtmlAttribute('data-dusk');

テキスト、値、および属性

値の取得と設定

Dusk は、ページ上の要素の現在の値、表示テキスト、および属性に対してやり取りするためのいくつかのメソッドを提供しています。たとえば、指定された CSS または Dusk セレクタに一致する要素の「値」を取得するには、value メソッドを使用します:

    // Retrieve the value...
$value = $browser->value('selector');

// Set the value...
$browser->value('selector', 'value');

指定されたフィールド名を持つ入力要素の「値」を取得するには、inputValue メソッドを使用できます:

    $value = $browser->inputValue('field');

テキストの取得

指定されたセレクタに一致する要素の表示テキストを取得するには、text メソッドを使用できます:

    $text = $browser->text('selector');

属性の取得

最後に、指定されたセレクタに一致する要素の属性の値を取得するには、attribute メソッドを使用できます:

    $attribute = $browser->attribute('selector', 'value');

フォームとのやり取り

値の入力

Dusk はフォームや入力要素とやり取りするためのさまざまなメソッドを提供しています。まずは、入力フィールドにテキストを入力する例を見てみましょう:

    $browser->type('email', 'taylor@laravel.com');

メソッドが必要に応じて 1 つ受け入れることに注意してくださいが、type メソッドに CSS セレクタを渡す必要はありません。CSS セレクタが提供されない場合、Dusk は指定された name 属性を持つ input または textarea フィールドを検索します。

コンテンツをクリアせずにフィールドにテキストを追加するには、append メソッドを使用できます:

    $browser->type('tags', 'foo')
->append('tags', ', bar, baz');

clear メソッドを使用して入力値をクリアできます:

    $browser->clear('email');

typeSlowly メソッドを使用して Dusk にゆっくりと入力させることができます。デフォルトでは、Dusk はキーを押す間に 100 ミリ秒の一時停止を行います。キーを押す間の時間をカスタマイズするには、メソッドの第三引数として適切なミリ秒数を渡すことができます:

    $browser->typeSlowly('mobile', '+1 (202) 555-5555');

$browser->typeSlowly('mobile', '+1 (202) 555-5555', 300);

appendSlowly メソッドを使用してテキストをゆっくり追加できます:

    $browser->type('tags', 'foo')
->appendSlowly('tags', ', bar, baz');

ドロップダウン

select 要素で利用可能な値を選択するには、select メソッドを使用できます。type メソッドと同様に、select メソッドは完全な CSS セレクタを必要としません。select メソッドに値を渡す際には、表示テキストではなく基礎となるオプション値を渡す必要があります:

    $browser->select('size', 'Large');

2 番目の引数を省略することでランダムなオプションを選択できます:

    $browser->select('size');

select メソッドに配列を第二引数として提供することで、複数のオプションを選択するようにメソッドに指示できます:

    $browser->select('categories', ['Art', 'Music']);

チェックボックス

チェックボックス入力を「チェック」するには、check メソッドを使用できます。他の多くの入力関連メソッドと同様に、完全な CSS セレクタは必要ありません。CSS セレクタに一致するものが見つからない場合、Dusk は一致する name 属性を持つチェックボックスを検索します:

    $browser->check('terms');

uncheckメソッドは、チェックボックス入力を「チェック解除」するために使用できます:

    $browser->uncheck('terms');

ラジオボタン

radio入力オプションを「選択」するには、radioメソッドを使用できます。他の多くの入力関連メソッドと同様に、完全なCSSセレクタは必要ありません。CSSセレクタに一致しない場合、Duskは一致するname属性とvalue属性を持つradio入力を検索します:

    $browser->radio('size', 'large');

ファイルの添付

attachメソッドは、file入力要素にファイルを添付するために使用できます。他の多くの入力関連メソッドと同様に、完全なCSSセレクタは必要ありません。CSSセレクタに一致しない場合、Duskは一致するname属性を持つfile入力を検索します:

    $browser->attach('photo', __DIR__.'/photos/mountains.png');

警告

attach関数を使用するには、サーバーにZip PHP拡張機能がインストールおよび有効化されている必要があります。

ボタンの押下

pressメソッドは、ページ上のボタン要素をクリックするために使用できます。pressメソッドに与えられる引数は、ボタンの表示テキストまたはCSS / Duskセレクタのいずれかです:

    $browser->press('Login');

フォームを送信する際、多くのアプリケーションはフォームの送信ボタンを押した後に無効にし、フォーム送信のHTTPリクエストが完了するとボタンを再度有効にします。ボタンを押してボタンが再度有効になるのを待つには、pressAndWaitForメソッドを使用できます:

    // Press the button and wait a maximum of 5 seconds for it to be enabled...
$browser->pressAndWaitFor('Save');

// Press the button and wait a maximum of 1 second for it to be enabled...
$browser->pressAndWaitFor('Save', 1);

リンクのクリック

リンクをクリックするには、ブラウザインスタンスでclickLinkメソッドを使用できます。clickLinkメソッドは、指定された表示テキストを持つリンクをクリックします:

    $browser->clickLink($linkText);

指定された表示テキストを持つリンクがページ上に表示されているかどうかを判断するには、seeLinkメソッドを使用できます:

    if ($browser->seeLink($linkText)) {
// ...
}

警告

これらのメソッドはjQueryと連携します。ページでjQueryが利用できない場合、Duskは自動的にページにjQueryを注入してテストの期間中に利用できるようにします。

キーボードの使用

keys メソッドを使用すると、type メソッドで通常許可されているよりも複雑な入力シーケンスを指定した要素に提供できます。たとえば、Duskに修飾キーを押しながら値を入力するよう指示することができます。この例では、指定されたセレクタに一致する要素に taylor が入力される間、shift キーが押されます。taylor が入力された後、修飾キーなしで swift が入力されます:

    $browser->keys('selector', ['{shift}', 'taylor'], 'swift');

keys メソッドのもう1つの有用な使用例は、アプリケーションの主要な CSS セレクタに "キーボードショートカット" の組み合わせを送信することです:

    $browser->keys('.app', ['{command}', 'j']);

注記

{command} などのすべての修飾キーは {} 文字で囲まれており、Facebook\WebDriver\WebDriverKeys クラスで定義された定数と一致します。これらの定数は GitHub で見つけることができます

フルーエントキーボードインタラクション

Dusk は withKeyboard メソッドも提供しており、Laravel\Dusk\Keyboard クラスを介して複雑なキーボードインタラクションをスムーズに実行できます。Keyboard クラスには pressreleasetypepause メソッドが用意されています:

    use Laravel\Dusk\Keyboard;

$browser->withKeyboard(function (Keyboard $keyboard) {
$keyboard->press('c')
->pause(1000)
->release('c')
->type(['c', 'e', 'o']);
});

キーボードマクロ

テストスイート全体で簡単に再利用できるカスタムキーボードインタラクションを定義したい場合は、Keyboard クラスが提供する macro メソッドを使用できます。通常、これを サービスプロバイダの boot メソッドから呼び出すべきです:

    <?php

namespace App\Providers;

use Facebook\WebDriver\WebDriverKeys;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\Keyboard;
use Laravel\Dusk\OperatingSystem;

class DuskServiceProvider extends ServiceProvider
{
/**
* Register Dusk's browser macros.
*/
public function boot(): void
{
Keyboard::macro('copy', function (string $element = null) {
$this->type([
OperatingSystem::onMac() ? WebDriverKeys::META : WebDriverKeys::CONTROL, 'c',
]);

return $this;
});

Keyboard::macro('paste', function (string $element = null) {
$this->type([
OperatingSystem::onMac() ? WebDriverKeys::META : WebDriverKeys::CONTROL, 'v',
]);

return $this;
});
}
}

macro 関数は、最初の引数として名前、2番目の引数としてクロージャを受け入れます。マクロのクロージャは、Keyboard インスタンスでメソッドとしてマクロを呼び出すときに実行されます:

    $browser->click('@textarea')
->withKeyboard(fn (Keyboard $keyboard) => $keyboard->copy())
->click('@another-textarea')
->withKeyboard(fn (Keyboard $keyboard) => $keyboard->paste());

マウスの使用

要素をクリックする

click メソッドを使用して、指定された CSS または Dusk セレクタに一致する要素をクリックできます。

    $browser->click('.selector');

clickAtXPathメソッドは、指定されたXPath式に一致する要素をクリックするために使用できます:

    $browser->clickAtXPath('//div[@class = "selector"]');

clickAtPointメソッドは、ブラウザの表示領域に対して指定された座標の上にある要素をクリックするために使用できます:

    $browser->clickAtPoint($x = 0, $y = 0);

doubleClickメソッドは、マウスのダブルクリックをシミュレートするために使用できます:

    $browser->doubleClick();

$browser->doubleClick('.selector');

rightClickメソッドは、マウスの右クリックをシミュレートするために使用できます:

    $browser->rightClick();

$browser->rightClick('.selector');

clickAndHoldメソッドは、マウスボタンがクリックされた状態をシミュレートするために使用できます。releaseMouseメソッドを後続して呼び出すと、この動作が元に戻り、マウスボタンが解放されます:

    $browser->clickAndHold('.selector');

$browser->clickAndHold()
->pause(1000)
->releaseMouse();

controlClickメソッドは、ブラウザ内でctrl+clickイベントをシミュレートするために使用できます:

    $browser->controlClick();

$browser->controlClick('.selector');

マウスオーバー

mouseoverメソッドは、指定されたCSSまたはDuskセレクタに一致する要素にマウスを移動する必要がある場合に使用できます:

    $browser->mouseover('.selector');

ドラッグアンドドロップ

dragメソッドは、指定されたセレクタに一致する要素を別の要素にドラッグするために使用できます:

    $browser->drag('.from-selector', '.to-selector');

または、単一の方向に要素をドラッグすることもできます:

    $browser->dragLeft('.selector', $pixels = 10);
$browser->dragRight('.selector', $pixels = 10);
$browser->dragUp('.selector', $pixels = 10);
$browser->dragDown('.selector', $pixels = 10);

最後に、指定されたオフセットで要素をドラッグすることもできます:

    $browser->dragOffset('.selector', $x = 10, $y = 10);

JavaScriptダイアログ

Duskは、JavaScriptダイアログとやり取りするためのさまざまなメソッドを提供しています。たとえば、waitForDialogメソッドを使用してJavaScriptダイアログが表示されるのを待つことができます。このメソッドは、ダイアログが表示されるのを待つ秒数を示すオプションの引数を受け入れます:

    $browser->waitForDialog($seconds = null);

assertDialogOpenedメソッドは、ダイアログが表示され、指定されたメッセージを含んでいることをアサートするために使用できます:

    $browser->assertDialogOpened('Dialog message');

JavaScriptダイアログにプロンプトが含まれている場合、typeInDialogメソッドを使用してプロンプトに値を入力できます:

    $browser->typeInDialog('Hello World');

"OK" ボタンをクリックして開いている JavaScript ダイアログを閉じるには、acceptDialog メソッドを呼び出すことができます:

    $browser->acceptDialog();

"キャンセル" ボタンをクリックして開いている JavaScript ダイアログを閉じるには、dismissDialog メソッドを呼び出すことができます:

    $browser->dismissDialog();

インラインフレームとのやり取り

インラインフレーム内の要素とやり取りする必要がある場合は、withinFrame メソッドを使用できます。withinFrame メソッドに提供されたクロージャ内で行われるすべての要素のやり取りは、指定されたインラインフレームのコンテキストにスコープされます:

    $browser->withinFrame('#credit-card-details', function ($browser) {
$browser->type('input[name="cardnumber"]', '4242424242424242')
->type('input[name="exp-date"]', '1224')
->type('input[name="cvc"]', '123')
->press('Pay');
});

セレクタのスコープ

時には、特定のセレクタ内ですべての操作をスコープ内に行いたい場合があります。たとえば、あるテーブル内にのみテキストが存在し、そのテーブル内のボタンをクリックすることをアサートしたい場合があります。これを達成するには、with メソッドを使用します。with メソッドに与えられたクロージャ内で行われるすべての操作は、元のセレクタにスコープされます:

    $browser->with('.table', function (Browser $table) {
$table->assertSee('Hello World')
->clickLink('Delete');
});

現在のスコープ外でアサーションを実行する必要がある場合があります。これを達成するには、elsewhere メソッドと elsewhereWhenAvailable メソッドを使用できます:

     $browser->with('.table', function (Browser $table) {
// Current scope is `body .table`...

$browser->elsewhere('.page-title', function (Browser $title) {
// Current scope is `body .page-title`...
$title->assertSee('Hello World');
});

$browser->elsewhereWhenAvailable('.page-title', function (Browser $title) {
// Current scope is `body .page-title`...
$title->assertSee('Hello World');
});
});

要素の待機

JavaScript を広範囲に使用するアプリケーションをテストする際には、特定の要素やデータが利用可能になるのを待つ必要があることがよくあります。Dusk はこれを簡単にします。さまざまなメソッドを使用して、ページ上の要素が表示されるのを待つことも、特定の JavaScript 式が true に評価されるまで待つこともできます。

待機

テストを一定のミリ秒数一時停止するだけの場合は、pause メソッドを使用します:

    $browser->pause(1000);

特定の条件が true の場合にのみテストを一時停止する必要がある場合は、pauseIf メソッドを使用します:

    $browser->pauseIf(App::environment('production'), 1000);

同様に、特定の条件がtrueである場合にテストを一時停止する必要がある場合は、pauseUnlessメソッドを使用できます:

    $browser->pauseUnless(App::environment('testing'), 1000);

セレクタの待機

waitForメソッドは、指定されたCSSまたはDuskセレクタに一致する要素がページに表示されるまでテストの実行を一時停止するために使用できます。デフォルトでは、これは例外をスローする前に最大5秒間テストを一時停止します。必要に応じて、メソッドの第2引数としてカスタムのタイムアウト閾値を渡すことができます:

    // Wait a maximum of five seconds for the selector...
$browser->waitFor('.selector');

// Wait a maximum of one second for the selector...
$browser->waitFor('.selector', 1);

指定されたセレクタに一致する要素が指定されたテキストを含むまで待機することもできます:

    // Wait a maximum of five seconds for the selector to contain the given text...
$browser->waitForTextIn('.selector', 'Hello World');

// Wait a maximum of one second for the selector to contain the given text...
$browser->waitForTextIn('.selector', 'Hello World', 1);

指定されたセレクタに一致する要素がページから見つからなくなるまで待機することもできます:

    // Wait a maximum of five seconds until the selector is missing...
$browser->waitUntilMissing('.selector');

// Wait a maximum of one second until the selector is missing...
$browser->waitUntilMissing('.selector', 1);

また、指定されたセレクタに一致する要素が有効または無効になるまで待機することもできます:

    // Wait a maximum of five seconds until the selector is enabled...
$browser->waitUntilEnabled('.selector');

// Wait a maximum of one second until the selector is enabled...
$browser->waitUntilEnabled('.selector', 1);

// Wait a maximum of five seconds until the selector is disabled...
$browser->waitUntilDisabled('.selector');

// Wait a maximum of one second until the selector is disabled...
$browser->waitUntilDisabled('.selector', 1);

利用可能な場合のセレクタのスコープ

時々、指定されたセレクタに一致する要素が表示されるのを待ってからその要素とやり取りしたい場合があります。たとえば、モーダルウィンドウが利用可能になるまで待機し、そのモーダル内の「OK」ボタンを押したい場合があります。これを実現するためにwhenAvailableメソッドを使用できます。指定されたクロージャ内で実行されるすべての要素操作は元のセレクタにスコープされます:

    $browser->whenAvailable('.modal', function (Browser $modal) {
$modal->assertSee('Hello World')
->press('OK');
});

テキストの待機

waitForTextメソッドは、指定されたテキストがページに表示されるまで待機するために使用できます:

    // Wait a maximum of five seconds for the text...
$browser->waitForText('Hello World');

// Wait a maximum of one second for the text...
$browser->waitForText('Hello World', 1);

表示されているテキストがページから削除されるまで待機するには、waitUntilMissingTextメソッドを使用できます:

    // Wait a maximum of five seconds for the text to be removed...
$browser->waitUntilMissingText('Hello World');

// Wait a maximum of one second for the text to be removed...
$browser->waitUntilMissingText('Hello World', 1);

リンクの待機

waitForLinkメソッドは、指定されたリンクテキストがページに表示されるまで待機するために使用できます:

    // Wait a maximum of five seconds for the link...
$browser->waitForLink('Create');

// Wait a maximum of one second for the link...
$browser->waitForLink('Create', 1);

入力の待機

waitForInputメソッドは、指定された入力フィールドがページ上に表示されるまで待機するために使用できます:

    // Wait a maximum of five seconds for the input...
$browser->waitForInput($field);

// Wait a maximum of one second for the input...
$browser->waitForInput($field, 1);

ページの場所を待機

$browser->assertPathIs('/home')などのパスのアサーションを行う際、window.location.pathnameが非同期で更新されているとアサーションが失敗する可能性があります。waitForLocationメソッドを使用して、場所が特定の値になるのを待つことができます:

    $browser->waitForLocation('/secret');

waitForLocationメソッドは、現在のウィンドウの場所が完全修飾URLになるのを待つためにも使用できます:

    $browser->waitForLocation('https://example.com/path');

また、名前付きルートの場所を待つこともできます:

    $browser->waitForRoute($routeName, $parameters);

ページのリロードを待機

アクションを実行した後にページのリロードを待つ必要がある場合は、waitForReloadメソッドを使用してください:

    use Laravel\Dusk\Browser;

$browser->waitForReload(function (Browser $browser) {
$browser->press('Submit');
})
->assertSee('Success!');

通常、ページのリロードを待つ必要があるのはボタンをクリックした後ですので、便宜上clickAndWaitForReloadメソッドを使用できます:

    $browser->clickAndWaitForReload('.selector')
->assertSee('something');

JavaScript式を待機

テストの実行を一時停止して、特定のJavaScript式がtrueに評価されるまで待機したい場合があります。waitUntilメソッドを使用すると簡単にこれを実現できます。このメソッドに式を渡す際には、returnキーワードや終了セミコロンを含める必要はありません:

    // Wait a maximum of five seconds for the expression to be true...
$browser->waitUntil('App.data.servers.length > 0');

// Wait a maximum of one second for the expression to be true...
$browser->waitUntil('App.data.servers.length > 0', 1);

Vue式を待機

waitUntilVueおよびwaitUntilVueIsNotメソッドを使用して、Vueコンポーネントの属性が特定の値になるまで待機できます:

    // Wait until the component attribute contains the given value...
$browser->waitUntilVue('user.name', 'Taylor', '@user');

// Wait until the component attribute doesn't contain the given value...
$browser->waitUntilVueIsNot('user.name', null, '@user');

JavaScriptイベントを待機

waitForEventメソッドを使用して、JavaScriptイベントが発生するまでテストの実行を一時停止できます:

    $browser->waitForEvent('load');

イベントリスナーはデフォルトでbody要素にアタッチされます。スコープ付きセレクタを使用する場合、イベントリスナーは一致する要素にアタッチされます:

    $browser->with('iframe', function (Browser $iframe) {
// Wait for the iframe's load event...
$iframe->waitForEvent('load');
});

waitForEventメソッドの第2引数としてセレクタを指定することもできます。これにより、特定の要素にイベントリスナーをアタッチすることができます:

    $browser->waitForEvent('load', '.selector');

documentおよびwindowオブジェクトでイベントを待つこともできます:

    // Wait until the document is scrolled...
$browser->waitForEvent('scroll', 'document');

// Wait a maximum of five seconds until the window is resized...
$browser->waitForEvent('resize', 'window', 5);

コールバックを使用した待機

Duskの多くの「wait」メソッドは、基礎となるwaitUsingメソッドに依存しています。このメソッドを直接使用して、指定されたクロージャがtrueを返すまで待機できます。waitUsingメソッドは、最大待機秒数、クロージャの評価間隔、クロージャ、およびオプションの失敗メッセージを受け入れます:

    $browser->waitUsing(10, 1, function () use ($something) {
return $something->isReady();
}, "Something wasn't ready in time.");

要素をビューにスクロール

ブラウザの表示領域外にあるため要素をクリックできない場合があります。scrollIntoViewメソッドは、指定されたセレクタの要素がビュー内にあるまでブラウザウィンドウをスクロールします:

    $browser->scrollIntoView('.selector')
->click('.selector');

利用可能なアサーション

Duskでは、アプリケーションに対して行うことができるさまざまなアサーションが提供されています。利用可能なすべてのアサーションについては、以下のリストでドキュメント化されています:

assertTitle

ページのタイトルが指定されたテキストと一致することをアサートします:

    $browser->assertTitle($title);

assertTitleContains

ページのタイトルが指定されたテキストを含むことをアサートします:

    $browser->assertTitleContains($title);

assertUrlIs

現在のURL(クエリ文字列を除く)が指定された文字列と一致することをアサートします:

    $browser->assertUrlIs($url);

assertSchemeIs

現在のURLのスキームが指定されたスキームと一致することをアサートします:

    $browser->assertSchemeIs($scheme);

assertSchemeIsNot

現在のURLのスキームが指定されたスキームと一致しないことをアサートします:

    $browser->assertSchemeIsNot($scheme);

assertHostIs

現在のURLのホストが指定されたホストと一致することをアサートします:

    $browser->assertHostIs($host);

assertHostIsNot

現在のURLのホストが指定されたホストと一致しないことをアサートします:

    $browser->assertHostIsNot($host);

assertPortIs

現在のURLのポートが指定されたポートと一致することをアサートします:

    $browser->assertPortIs($port);

assertPortIsNot

現在のURLのポートが指定されたポートと一致しないことをアサートします:

    $browser->assertPortIsNot($port);

assertPathBeginsWith

現在のURLのパスが指定されたパスで始まることをアサートします:

    $browser->assertPathBeginsWith('/home');

assertPathEndsWith

現在のURLのパスが指定されたパスで終わることをアサートします:

    $browser->assertPathEndsWith('/home');

assertPathContains

現在のURLのパスが指定されたパスを含むことをアサートします:

    $browser->assertPathContains('/home');

assertPathIs

現在のパスが指定されたパスと一致することをアサートします:

    $browser->assertPathIs('/home');

現在のパスが指定されたパスと一致しないことをアサートします:

    $browser->assertPathIsNot('/home');

assertRouteIs

現在のURLが指定された名前付きルートのURLと一致することをアサートします:

    $browser->assertRouteIs($name, $parameters);

assertQueryStringHas

指定されたクエリ文字列パラメータが存在することをアサートします:

    $browser->assertQueryStringHas($name);

指定されたクエリ文字列パラメータが存在し、指定された値を持つことをアサートします:

    $browser->assertQueryStringHas($name, $value);

assertQueryStringMissing

指定されたクエリ文字列パラメータが存在しないことをアサートします:

    $browser->assertQueryStringMissing($name);

assertFragmentIs

URLの現在のハッシュフラグメントが指定されたフラグメントと一致することをアサートします:

    $browser->assertFragmentIs('anchor');

assertFragmentBeginsWith

URLの現在のハッシュフラグメントが指定されたフラグメントで始まることをアサートします:

    $browser->assertFragmentBeginsWith('anchor');

assertFragmentIsNot

URLの現在のハッシュフラグメントが指定されたフラグメントと一致しないことをアサートします:

    $browser->assertFragmentIsNot('anchor');

assertHasCookie

指定された暗号化されたクッキーが存在することをアサートします:

    $browser->assertHasCookie($name);

assertHasPlainCookie

指定された暗号化されていないクッキーが存在することをアサートします:

    $browser->assertHasPlainCookie($name);

assertCookieMissing

指定された暗号化されたクッキーが存在しないことをアサートします:

    $browser->assertCookieMissing($name);

assertPlainCookieMissing

指定された暗号化されていないクッキーが存在しないことをアサートします:

    $browser->assertPlainCookieMissing($name);

assertCookieValue

暗号化されたクッキーが指定された値を持つことをアサートします:

    $browser->assertCookieValue($name, $value);

assertPlainCookieValue

アンエンコードされたクッキーが指定された値を持っていることをアサートします:

    $browser->assertPlainCookieValue($name, $value);

assertSee

指定されたテキストがページに存在することをアサートします:

    $browser->assertSee($text);

assertDontSee

指定されたテキストがページに存在しないことをアサートします:

    $browser->assertDontSee($text);

assertSeeIn

指定されたテキストがセレクタ内に存在することをアサートします:

    $browser->assertSeeIn($selector, $text);

assertDontSeeIn

指定されたテキストがセレクタ内に存在しないことをアサートします:

    $browser->assertDontSeeIn($selector, $text);

assertSeeAnythingIn

任意のテキストがセレクタ内に存在することをアサートします:

    $browser->assertSeeAnythingIn($selector);

assertSeeNothingIn

テキストがセレクタ内に存在しないことをアサートします:

    $browser->assertSeeNothingIn($selector);

assertScript

指定されたJavaScript式が指定された値に評価されることをアサートします:

    $browser->assertScript('window.isLoaded')
->assertScript('document.readyState', 'complete');

assertSourceHas

指定されたソースコードがページに存在することをアサートします:

    $browser->assertSourceHas($code);

assertSourceMissing

指定されたソースコードがページに存在しないことをアサートします:

    $browser->assertSourceMissing($code);

指定されたリンクがページに存在することをアサートします:

    $browser->assertSeeLink($linkText);

指定されたリンクがページに存在しないことをアサートします:

    $browser->assertDontSeeLink($linkText);

assertInputValue

指定された入力フィールドが指定された値を持っていることをアサートします:

    $browser->assertInputValue($field, $value);

assertInputValueIsNot

指定された入力フィールドが指定された値を持っていないことをアサートします:

    $browser->assertInputValueIsNot($field, $value);

assertChecked



指定されたチェックボックスがチェックされていることをアサートします:

```php
$browser->assertChecked($field);

assertNotChecked

指定されたチェックボックスがチェックされていないことをアサートします:

    $browser->assertNotChecked($field);

assertIndeterminate

指定されたチェックボックスが不確定な状態にあることをアサートします:

    $browser->assertIndeterminate($field);

assertRadioSelected

指定されたラジオボタンが選択されていることをアサートします:

    $browser->assertRadioSelected($field, $value);

assertRadioNotSelected

指定されたラジオボタンが選択されていないことをアサートします:

    $browser->assertRadioNotSelected($field, $value);

assertSelected

指定されたドロップダウンが指定された値を選択していることをアサートします:

    $browser->assertSelected($field, $value);

assertNotSelected

指定されたドロップダウンが指定された値を選択していないことをアサートします:

    $browser->assertNotSelected($field, $value);

assertSelectHasOptions

指定された値の配列が選択可能であることをアサートします:

    $browser->assertSelectHasOptions($field, $values);

assertSelectMissingOptions

指定された値の配列が選択不可能であることをアサートします:

    $browser->assertSelectMissingOptions($field, $values);

assertSelectHasOption

指定された値が指定されたフィールドで選択可能であることをアサートします:

    $browser->assertSelectHasOption($field, $value);

assertSelectMissingOption

指定された値が選択不可能であることをアサートします:

    $browser->assertSelectMissingOption($field, $value);

assertValue

指定されたセレクタに一致する要素が指定された値を持っていることをアサートします:

    $browser->assertValue($selector, $value);

assertValueIsNot

指定されたセレクタに一致する要素が指定された値を持っていないことをアサートします:

    $browser->assertValueIsNot($selector, $value);

assertAttribute

    $browser->assertAttribute($selector, $attribute, $value);

assertAttributeContains

指定されたセレクタに一致する要素が指定された属性に指定された値を持っていることをアサートします。

    $browser->assertAttributeContains($selector, $attribute, $value);

assertAttributeDoesntContain

指定されたセレクタに一致する要素が指定された属性に指定された値を含んでいないことをアサートします。

    $browser->assertAttributeDoesntContain($selector, $attribute, $value);

assertAriaAttribute

指定されたセレクタに一致する要素が指定された aria 属性に指定された値を持っていることをアサートします。

    $browser->assertAriaAttribute($selector, $attribute, $value);

例えば、マークアップが <button aria-label="Add"></button> の場合、aria-label 属性に対して次のようにアサートできます:

    $browser->assertAriaAttribute('button', 'label', 'Add')

assertDataAttribute

指定されたセレクタに一致する要素が指定された data 属性に指定された値を持っていることをアサートします。

    $browser->assertDataAttribute($selector, $attribute, $value);

例えば、マークアップが <tr id="row-1" data-content="attendees"></tr> の場合、data-label 属性に対して次のようにアサートできます:

    $browser->assertDataAttribute('#row-1', 'content', 'attendees')

assertVisible

指定されたセレクタに一致する要素が表示されていることをアサートします。

    $browser->assertVisible($selector);

assertPresent

指定されたセレクタに一致する要素がソース内に存在することをアサートします。

    $browser->assertPresent($selector);

assertNotPresent

指定されたセレクタに一致する要素がソース内に存在しないことをアサートします。

    $browser->assertNotPresent($selector);

assertMissing

指定されたセレクタに一致する要素が表示されていないことをアサートします。

    $browser->assertMissing($selector);

assertInputPresent


アサート:指定された名前の入力が存在することを確認します:

```php
$browser->assertInputPresent($name);

assertInputMissing

ソースに指定された名前の入力が存在しないことをアサートします:

    $browser->assertInputMissing($name);

assertDialogOpened

指定されたメッセージを持つJavaScriptダイアログが開かれたことをアサートします:

    $browser->assertDialogOpened($message);

assertEnabled

指定されたフィールドが有効であることをアサートします:

    $browser->assertEnabled($field);

assertDisabled

指定されたフィールドが無効であることをアサートします:

    $browser->assertDisabled($field);

assertButtonEnabled

指定されたボタンが有効であることをアサートします:

    $browser->assertButtonEnabled($button);

assertButtonDisabled

指定されたボタンが無効であることをアサートします:

    $browser->assertButtonDisabled($button);

assertFocused

指定されたフィールドがフォーカスされていることをアサートします:

    $browser->assertFocused($field);

assertNotFocused

指定されたフィールドがフォーカスされていないことをアサートします:

    $browser->assertNotFocused($field);

assertAuthenticated

ユーザーが認証されていることをアサートします:

    $browser->assertAuthenticated();

assertGuest

ユーザーが認証されていないことをアサートします:

    $browser->assertGuest();

assertAuthenticatedAs

ユーザーが指定されたユーザーとして認証されていることをアサートします:

    $browser->assertAuthenticatedAs($user);

assertVue

Duskは、Vueコンポーネントのデータの状態についてもアサートできます。たとえば、アプリケーションに次のVueコンポーネントが含まれているとします:

    // HTML...

<profile dusk="profile-component"></profile>

// Component Definition...

Vue.component('profile', {
template: '<div>{{ user.name }}</div>',

data: function () {
return {
user: {
name: 'Taylor'
}
};
}
});

次のようにVueコンポーネントの状態をアサートできます:

test('vue', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertVue('user.name', 'Taylor', '@profile-component');
});
});
/**
* A basic Vue test example.
*/
public function test_vue(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertVue('user.name', 'Taylor', '@profile-component');
});
}

assertVueIsNot

指定されたVueコンポーネントのデータプロパティが指定された値と一致しないことをアサートします:

    $browser->assertVueIsNot($property, $value, $componentSelector = null);

assertVueContains

指定されたVueコンポーネントのデータプロパティが配列であり、指定された値を含んでいることをアサートします:

    $browser->assertVueContains($property, $value, $componentSelector = null);

assertVueDoesntContain

指定されたVueコンポーネントのデータプロパティが配列であり、指定された値を含んでいないことをアサートします:

    $browser->assertVueDoesntContain($property, $value, $componentSelector = null);

ページ

時には、テストには複数の複雑なアクションが順番に実行される必要があります。これにより、テストが読みにくく理解しにくくなることがあります。Duskページを使用すると、特定のページで実行できる表現力豊かなアクションを定義し、1つのメソッドを介して実行できます。ページを使用すると、アプリケーションまたは単一のページの一般的なセレクターへのショートカットを定義することもできます。

ページの生成

ページオブジェクトを生成するには、dusk:page Artisanコマンドを実行します。すべてのページオブジェクトは、アプリケーションのtests/Browser/Pagesディレクトリに配置されます:

    php artisan dusk:page Login

ページの設定

デフォルトでは、ページにはurlassertelementsの3つのメソッドがあります。urlおよびassertメソッドについて説明します。elementsメソッドについては、後述ので詳しく説明します。

urlメソッド

urlメソッドは、ページを表すURLのパスを返す必要があります。Duskは、ブラウザでページに移動する際にこのURLを使用します:

    /**
* Get the URL for the page.
*/
public function url(): string
{
return '/login';
}

assertメソッド

assertメソッドは、ブラウザが実際に指定されたページにいることを検証するために必要なアサーションを行うことができます。このメソッドに何も配置する必要は実際にはありませんが、必要に応じてこれらのアサーションを行うことができます。これらのアサーションは、ページに移動する際に自動的に実行されます:

    /**
* Assert that the browser is on the page.
*/
public function assert(Browser $browser): void
{
$browser->assertPathIs($this->url());
}

ページへの移動

ページが定義されたら、visit メソッドを使用してそのページに移動できます:

    use Tests\Browser\Pages\Login;

$browser->visit(new Login);

時々、既に特定のページにいて、そのページのセレクタやメソッドを現在のテストコンテキストに「ロード」する必要があることがあります。これは、ボタンを押して明示的にそのページに移動せずに特定のページにリダイレクトされる場合に一般的です。このような状況では、on メソッドを使用してページをロードできます:

    use Tests\Browser\Pages\CreatePlaylist;

$browser->visit('/dashboard')
->clickLink('Create Playlist')
->on(new CreatePlaylist)
->assertSee('@create');

短縮セレクタ

ページクラス内の elements メソッドを使用すると、ページの任意の CSS セレクタに対して簡単で覚えやすいショートカットを定義できます。例えば、アプリケーションのログインページの「email」入力フィールドのためのショートカットを定義してみましょう:

    /**
* Get the element shortcuts for the page.
*
* @return array<string, string>
*/
public function elements(): array
{
return [
'@email' => 'input[name=email]',
];
}

ショートカットが定義されたら、通常の CSS セレクタを使用する場所で短縮セレクタを使用できます:

    $browser->type('@email', 'taylor@laravel.com');

グローバル短縮セレクタ

Dusk をインストールすると、tests/Browser/Pages ディレクトリに基本的な Page クラスが配置されます。このクラスには、アプリケーション全体で利用可能であるべきグローバル短縮セレクタを定義するために使用できる siteElements メソッドが含まれています:

    /**
* Get the global element shortcuts for the site.
*
* @return array<string, string>
*/
public static function siteElements(): array
{
return [
'@element' => '#selector',
];
}

ページメソッド

ページに定義されたデフォルトのメソッドに加えて、テスト全体で使用できる追加のメソッドを定義することができます。例えば、音楽管理アプリケーションを構築しているとしましょう。アプリケーションのあるページでの一般的なアクションは、プレイリストを作成することかもしれません。各テストでプレイリストを作成するロジックを再度書く代わりに、ページクラスに createPlaylist メソッドを定義できます:

    <?php

namespace Tests\Browser\Pages;

use Laravel\Dusk\Browser;
use Laravel\Dusk\Page;

class Dashboard extends Page
{
// Other page methods...

/**
* Create a new playlist.
*/
public function createPlaylist(Browser $browser, string $name): void
{
$browser->type('name', $name)
->check('share')
->press('Create Playlist');
}
}

メソッドが定義されたら、そのメソッドをページを利用する任意のテスト内で使用できます。カスタムページメソッドには、ブラウザインスタンスが自動的に最初の引数として渡されます:

    use Tests\Browser\Pages\Dashboard;

$browser->visit(new Dashboard)
->createPlaylist('My Playlist')
->assertSee('My Playlist');

コンポーネント

コンポーネントは、Duskの「ページオブジェクト」と似ていますが、ナビゲーションバーや通知ウィンドウなど、アプリケーション全体で再利用されるUI部品や機能を意図しています。そのため、コンポーネントは特定のURLにバインドされていません。

コンポーネントの生成

コンポーネントを生成するには、dusk:component Artisanコマンドを実行します。新しいコンポーネントはtests/Browser/Componentsディレクトリに配置されます:

    php artisan dusk:component DatePicker

上記のように、「日付ピッカー」は、アプリケーション全体のさまざまなページで存在する可能性があるコンポーネントの例です。テストスイート全体の数十のテストで日付を選択するブラウザ自動化ロジックを手動で記述すると煩雑になることがあります。代わりに、日付ピッカーを表すDuskコンポーネントを定義して、そのロジックをコンポーネント内にカプセル化できます:

    <?php

namespace Tests\Browser\Components;

use Laravel\Dusk\Browser;
use Laravel\Dusk\Component as BaseComponent;

class DatePicker extends BaseComponent
{
/**
* Get the root selector for the component.
*/
public function selector(): string
{
return '.date-picker';
}

/**
* Assert that the browser page contains the component.
*/
public function assert(Browser $browser): void
{
$browser->assertVisible($this->selector());
}

/**
* Get the element shortcuts for the component.
*
* @return array<string, string>
*/
public function elements(): array
{
return [
'@date-field' => 'input.datepicker-input',
'@year-list' => 'div > div.datepicker-years',
'@month-list' => 'div > div.datepicker-months',
'@day-list' => 'div > div.datepicker-days',
];
}

/**
* Select the given date.
*/
public function selectDate(Browser $browser, int $year, int $month, int $day): void
{
$browser->click('@date-field')
->within('@year-list', function (Browser $browser) use ($year) {
$browser->click($year);
})
->within('@month-list', function (Browser $browser) use ($month) {
$browser->click($month);
})
->within('@day-list', function (Browser $browser) use ($day) {
$browser->click($day);
});
}
}

コンポーネントの使用

コンポーネントが定義されたら、どのテストからでも日付ピッカー内の日付を簡単に選択できます。また、日付を選択するために必要なロジックが変更された場合、コンポーネントを更新するだけで済みます:

<?php

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\Browser\Components\DatePicker;

uses(DatabaseMigrations::class);

test('basic example', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/')
->within(new DatePicker, function (Browser $browser) {
$browser->selectDate(2019, 1, 30);
})
->assertSee('January');
});
});
<?php

namespace Tests\Browser;

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\Browser\Components\DatePicker;
use Tests\DuskTestCase;

class ExampleTest extends DuskTestCase
{
/**
* A basic component test example.
*/
public function test_basic_example(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->within(new DatePicker, function (Browser $browser) {
$browser->selectDate(2019, 1, 30);
})
->assertSee('January');
});
}
}

継続的インテグレーション

警告

ほとんどのDusk継続的インテグレーションの設定では、Laravelアプリケーションが組み込みのPHP開発サーバーをポート8000で使用して提供されることが想定されています。そのため、継続的インテグレーション環境には、APP_URL環境変数の値をhttp://127.0.0.1:8000に設定しておく必要があります。

Heroku CI

Heroku CIでDuskテストを実行するには、Herokuのapp.jsonファイルに以下のGoogle Chromeのビルドパックとスクリプトを追加してください:

    {
"environments": {
"test": {
"buildpacks": [
{ "url": "heroku/php" },
{ "url": "https://github.com/heroku/heroku-buildpack-google-chrome" }
],
"scripts": {
"test-setup": "cp .env.testing .env",
"test": "nohup bash -c './vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &' && nohup bash -c 'php artisan serve --no-reload > /dev/null 2>&1 &' && php artisan dusk"
}
}
}
}

Travis CI


[Travis CI](https://travis-ci.org)でDuskテストを実行するには、次の`.travis.yml`構成を使用します。Travis CIはグラフィカルな環境ではないため、Chromeブラウザを起動するために追加の手順が必要です。さらに、`php artisan serve`を使用してPHPの組み込みWebサーバーを起動します:

```yaml
language: php

php:
- 7.3

addons:
chrome: stable

install:
- cp .env.testing .env
- travis_retry composer install --no-interaction --prefer-dist
- php artisan key:generate
- php artisan dusk:chrome-driver

before_script:
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
- php artisan serve --no-reload &

script:
- php artisan dusk

GitHub Actions

GitHub Actionsを使用してDuskテストを実行している場合は、次の構成ファイルを使用して開始点としてください。TravisCIと同様に、php artisan serveコマンドを使用してPHPの組み込みWebサーバーを起動します:

name: CI
on: [push]
jobs:

dusk-php:
runs-on: ubuntu-latest
env:
APP_URL: "http://127.0.0.1:8000"
DB_USERNAME: root
DB_PASSWORD: root
MAIL_MAILER: log
steps:
- uses: actions/checkout@v4
- name: Prepare The Environment
run: cp .env.example .env
- name: Create Database
run: |
sudo systemctl start mysql
mysql --user="root" --password="root" -e "CREATE DATABASE \`my-database\` character set UTF8mb4 collate utf8mb4_bin;"
- name: Install Composer Dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: Generate Application Key
run: php artisan key:generate
- name: Upgrade Chrome Driver
run: php artisan dusk:chrome-driver --detect
- name: Start Chrome Driver
run: ./vendor/laravel/dusk/bin/chromedriver-linux &
- name: Run Laravel Server
run: php artisan serve --no-reload &
- name: Run Dusk Tests
run: php artisan dusk
- name: Upload Screenshots
if: failure()
uses: actions/upload-artifact@v2
with:
name: screenshots
path: tests/Browser/screenshots
- name: Upload Console Logs
if: failure()
uses: actions/upload-artifact@v2
with:
name: console
path: tests/Browser/console

Chipper CI

Chipper CIを使用してDuskテストを実行している場合は、次の構成ファイルを使用して開始点としてください。Laravelを実行するためにPHPの組み込みサーバーを使用し、リクエストを受信できるようにします:

# file .chipperci.yml
version: 1

environment:
php: 8.2
node: 16

# Include Chrome in the build environment
services:
- dusk

# Build all commits
on:
push:
branches: .*

pipeline:
- name: Setup
cmd: |
cp -v .env.example .env
composer install --no-interaction --prefer-dist --optimize-autoloader
php artisan key:generate

# Create a dusk env file, ensuring APP_URL uses BUILD_HOST
cp -v .env .env.dusk.ci
sed -i "s@APP_URL=.*@APP_URL=http://$BUILD_HOST:8000@g" .env.dusk.ci

- name: Compile Assets
cmd: |
npm ci --no-audit
npm run build

- name: Browser Tests
cmd: |
php -S [::0]:8000 -t public 2>server.log &
sleep 2
php artisan dusk:chrome-driver $CHROME_DRIVER
php artisan dusk --env=ci

Chipper CIでDuskテストを実行する詳細やデータベースの使用方法などについては、公式Chipper CIドキュメントを参照してください。