コンテンツへスキップ

Laravel Dusk

はじめに

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

インストール

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

composer require laravel/dusk --dev
exclamation

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

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

php artisan dusk:install

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

lightbulb

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

ChromeDriverのインストール管理

dusk:installコマンドを使用してLaravel Duskによってインストールされる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
exclamation

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;
 
//
}
exclamation

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プロパティを定義できます。

lightbulb

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
lightbulb

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

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

Cookie

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

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

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

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

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

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

要素の操作

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

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

use Laravel\Dusk\Dusk;
 
Dusk::selectorHtmlAttribute('data-dusk');

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

値の取得と設定

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

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

inputValueメソッドを使用して、指定されたフィールド名を持つ入力要素の「value」を取得できます。

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

テキストの取得

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

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

属性の取得

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

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

フォームの操作

値の入力

Duskには、フォームと入力要素を操作するためのさまざまなメソッドが用意されています。まず、入力フィールドにテキストを入力する例を見てみましょう。

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

メソッドは必要に応じて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ミリ秒間一時停止します。キープレス間の時間をカスタマイズするには、メソッドの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');
exclamation

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)) {
// ...
}
exclamation

これらのメソッドは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']);
lightbulb

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

Fluentキーボード操作

Duskは、Laravel\Dusk\Keyboardクラスを介して複雑なキーボード操作を流暢に実行できるwithKeyboardメソッドも提供します。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+クリックイベントをシミュレートするために使用できます。

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

assertPathIsNot

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

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

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

$browser->assertHasCookie($name);

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

$browser->assertHasPlainCookie($name);

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

$browser->assertCookieMissing($name);

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

$browser->assertPlainCookieMissing($name);

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

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

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

$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

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

$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

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

$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

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

$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

ページの設定

デフォルトでは、ページには 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 セレクターに対する簡単で覚えやすいショートカットを定義できます。例えば、アプリケーションのログインページの「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', '[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');

コンポーネント

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

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

exclamation

ほとんどの 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"
}
}
}
}

Travis CI

Travis 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 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 --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

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