メインコンテンツまでスキップ
バージョン: master

Laravel Dusk (Laravel Dusk)

導入 (Introduction)

害虫4 には自動ブラウザテストが含まれるようになり、Laravel Dusk と比較してパフォーマンスと使いやすさが大幅に向上しました。新しいプロジェクトの場合は、ブラウザーのテストに Pest を使用することをお勧めします。

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

インストール (Installation)

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

composer require laravel/dusk --dev

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

Dusk パッケージをインストールした後、dusk:install Artisan コマンドを実行します。 dusk:install コマンドは、Dusk テストのサンプルである tests/Browser ディレクトリを作成し、オペレーティング システム用の Chrome ドライバ バイナリをインストールします。

php artisan dusk:install

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

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

ChromeDriver インストールの管理

Laravel Dusk によって dusk:install コマンドを使用してインストールされるものとは異なるバージョンの 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();
}

次に、選択した URL とポートに接続するように driver メソッドを変更できます。さらに、WebDriver に渡す必要がある「必要な機能」を変更することもできます。

use Facebook\WebDriver\Remote\RemoteWebDriver;

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

はじめる (Getting Started)

テストの生成

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;

pest()->use(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;

pest()->use(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 コマンドは、特定の group のテストのみを実行できるようにするなど、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();
}

さらに、9515 以外のポートで ChromeDriver を起動する場合は、同じクラスの 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 ファイルが復元されます。

ブラウザの基本 (Browser Basics)

ブラウザの作成

まず、アプリケーションにログインできることを確認するテストを作成しましょう。テストを生成した後、ログイン ページに移動し、資格情報を入力して、[ログイン] ボタンをクリックするようにテストを変更できます。ブラウザー インスタンスを作成するには、Dusk テスト内から browse メソッドを呼び出すことができます。

<?php

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

pest()->use(DatabaseMigrations::class);

test('basic example', function () {
$user = User::factory()->create([
'email' => '[email protected]',
]);

$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' => '[email protected]',
]);

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

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

複数のブラウザの作成

テストを適切に実行するために複数のブラウザが必要になる場合があります。たとえば、WebSocket と対話するチャット画面をテストするには、複数のブラウザーが必要になる場合があります。複数のブラウザを作成するには、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($routeName, $parameters);

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 メソッドを使用して、暗号化された Cookie の値を取得または設定できます。デフォルトでは、Laravel によって作成されたすべての Cookie は暗号化されます。

$browser->cookie('name');

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

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

$browser->plainCookie('name');

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

deleteCookie メソッドを使用して、指定された Cookie を削除できます。

$browser->deleteCookie('name');

JavaScriptの実行

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

$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');

要素との対話 (Interacting With Elements)

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', '[email protected]');

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

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

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

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

$browser->clear('email');

typeSlowly メソッドを使用して、Dusk にゆっくり入力するように指示できます。デフォルトでは、Dusk はキーを押すまでの間に 100 ミリ秒間一時停止します。キーを押すまでの時間をカスタマイズするには、メソッドの 3 番目の引数として適切なミリ秒数を渡します。

$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 メソッドの 2 番目の引数として配列を指定すると、メソッドに複数のオプションを選択するように指示できます。

$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');

アタッチ機能を使用するには、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 はそれをページに自動的に挿入し、テスト期間中使用できるようにします。

キーボードの使用

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 クラスは、pressreleasetype、および pause メソッドを提供します。

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();

インラインフレームの操作

iframe 内の要素を操作する必要がある場合は、withinFrame メソッドを使用できます。 withinFrame メソッドに提供されたクロージャー内で行われるすべての要素の対話は、指定された iframe のコンテキストにスコープされます。

$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 の「待機」メソッドの多くは、基礎となる 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');

利用可能なアサーション (Available Assertions)

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

アサートタイトル

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

$browser->assertTitle($title);

アサートタイトル次を含む

ページ タイトルに指定されたテキストが含まれていることをアサートします。

$browser->assertTitleContains($title);

アサートURL

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

$browser->assertUrlIs($url);

アサートスキーム

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

$browser->assertSchemeIs($scheme);

アサートスキームがありません

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

$browser->assertSchemeIsNot($scheme);

アサートホスト

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

$browser->assertHostIs($host);

ホストが存在しないことをアサート

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

$browser->assertHostIsNot($host);

アサートポートI

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

$browser->assertPortIs($port);

アサートポートがありません

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

$browser->assertPortIsNot($port);

アサートパスの始まり

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

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

assertPathEndsWith

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

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

アサートパスが含まれる

現在の URL パスに指定されたパスが含まれていることをアサートします。

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

アサートパス

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

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

アサートパスがありません

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

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

アサートルートI

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

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

assertQueryStringHas

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

$browser->assertQueryStringHas($name);

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

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

assertQueryStringMissing

指定されたクエリ文字列パラメータが欠落していることをアサートします。

$browser->assertQueryStringMissing($name);

アサートフラグメントIs

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

$browser->assertFragmentIs('anchor');

アサートフラグメントで始まる

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

$browser->assertFragmentBeginsWith('anchor');

アサートフラグメントはありません

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

$browser->assertFragmentIsNot('anchor');

指定された暗号化された Cookie が存在することをアサートします。

$browser->assertHasCookie($name);

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

$browser->assertHasPlainCookie($name);

指定された暗号化された Cookie が存在しないことをアサートします。

$browser->assertCookieMissing($name);

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

$browser->assertPlainCookieMissing($name);

暗号化された Cookie が指定された値を持つことをアサートします。

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

暗号化されていない Cookie が指定された値を持つことをアサートします。

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

アサートを参照

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

$browser->assertSee($text);

主張しないでください

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

$browser->assertDontSee($text);

アサート見る

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

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

主張しないで見てください

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

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

アサート何でも見る

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

$browser->assertSeeAnythingIn($selector);

アサートSeeNothingIn

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

$browser->assertSeeNothingIn($selector);

アサートカウント

指定されたセレクターに一致する要素が指定された回数出現することをアサートします。

$browser->assertCount($selector, $count);

アサートスクリプト

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

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

アサートソースが持っています

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

$browser->assertSourceHas($code);

アサートソースが見つかりません

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

$browser->assertSourceMissing($code);

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

$browser->assertSeeLink($linkText);

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

$browser->assertDontSeeLink($linkText);

アサート入力値

指定された入力フィールドに指定された値があることをアサートします。

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

アサート入力値がありません

指定された入力フィールドに指定された値が存在しないことをアサートします。

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

アサートチェック済み

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

$browser->assertChecked($field);

アサート未チェック

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

$browser->assertNotChecked($field);

アサート不定

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

$browser->assertIndeterminate($field);

アサートラジオ選択済み

指定された無線フィールドが選択されていることをアサートします。

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

アサートラジオが選択されていません

指定された無線フィールドが選択されていないことをアサートします。

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

アサート選択済み

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

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

アサート未選択

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

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

assertSelectHasOptions

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

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

アサート選択欠落オプション

指定された値の配列が選択できないことをアサートします。

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

assertSelectHasOption

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

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

アサート選択欠落オプション

指定された値が選択できないことをアサートします。

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

アサート値

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

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

アサート値はありません

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

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

アサート属性

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

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

アサート属性がありません

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

$browser->assertAttributeMissing($selector, $attribute);

assertAttributeContains

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

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

assertAttributeDoesntContain

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

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

アサートアリア属性

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

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

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

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

アサートデータ属性

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

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

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

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

アサート可視

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

$browser->assertVisible($selector);

アサート現在

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

$browser->assertPresent($selector);

アサートされていません

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

$browser->assertNotPresent($selector);

アサート欠落しています

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

$browser->assertMissing($selector);

アサート入力現在

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

$browser->assertInputPresent($name);

アサート入力がありません

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

$browser->assertInputMissing($name);

アサートダイアログが開きました

指定されたメッセージを含む JavaScript ダイアログが開いたことをアサートします。

$browser->assertDialogOpened($message);

アサート有効

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

$browser->assertEnabled($field);

アサート無効

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

$browser->assertDisabled($field);

アサートボタン有効

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

$browser->assertButtonEnabled($button);

アサートボタン無効

指定されたボタンが無効になっていることをアサートします。

$browser->assertButtonDisabled($button);

アサートフォーカス

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

$browser->assertFocused($field);

アサートノットフォーカス

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

$browser->assertNotFocused($field);

認証済み

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

$browser->assertAuthenticated();

アサートゲスト

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

$browser->assertGuest();

認証済みとしてアサート

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

$browser->assertAuthenticatedAs($user);

アサートVue

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');
});
}

アサートVueがありません

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

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

アサートVueが含まれている

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

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

assertVueDoesntContain

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

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

ページ (Pages)

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

ページの生成

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

php artisan dusk:page Login

ページの構成

デフォルトでは、ページには urlassert、および elements の 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 セレクターにすばやく覚えやすいショートカットを定義できます。たとえば、アプリケーションのログイン ページの「電子メール」入力フィールドのショートカットを定義してみましょう。

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

ショートカットが定義されたら、通常は完全な CSS セレクターを使用する場所であればどこでも短縮セレクターを使用できます。

$browser->type('@email', '[email protected]');

グローバル短縮表記セレクター

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

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

ページメソッド

ページで定義されているデフォルトのメソッドに加えて、テスト全体で使用できる追加のメソッドを定義できます。たとえば、音楽管理アプリケーションを構築していると想像してみましょう。アプリケーションの 1 ページに対する一般的なアクションは、プレイリストの作成です。各テストでプレイリストを作成するロジックを書き直す代わりに、ページ クラスで 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');

コンポーネント (Components)

コンポーネントは 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;

pest()->use(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');
});
}
}

component メソッドは、指定されたコンポーネントをスコープとするブラウザー インスタンスを取得するために使用できます。

$datePicker = $browser->component(new DatePickerComponent);

$datePicker->selectDate(2019, 1, 30);

$datePicker->assertSee('January');

継続的インテグレーション (Continuous Integration)

ほとんどの Dusk 継続的統合構成では、Laravel アプリケーションがポート 8000 の組み込み PHP 開発サーバーを使用して提供されることを想定しています。 したがって、続行する前に、継続的統合環境の APP_URL 環境変数値が http://127.0.0.1:8000 であることを確認する必要があります。

Heroku CI

Heroku CI で Dusk テストを実行するには、次の Google Chrome ビルドパックとスクリプトを Heroku app.json ファイルに追加します。

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

トラヴィスCI

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

language: php

php:
- 8.2

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 アクション

GitHub アクション を使用して 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@v5
- 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 --port=9515 &
- 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@v4
with:
name: screenshots
path: tests/Browser/screenshots
- name: Upload Console Logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: console
path: tests/Browser/console

チッパーCI

チッパーCI を使用して Dusk テストを実行している場合は、開始点として次の構成ファイルを使用できます。 PHP の組み込みサーバーを使用して Laravel を実行し、リクエストをリッスンできるようにします。

# 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 ドキュメント を参照してください。