Introduction

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

Installation

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

  1. composer require laravel/dusk --dev

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

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

  1. php artisan dusk:install

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

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

Managing ChromeDriver Installations

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

  1. # Install the latest version of ChromeDriver for your OS...
  2. php artisan dusk:chrome-driver
  3. # Install a given version of ChromeDriver for your OS...
  4. php artisan dusk:chrome-driver 86
  5. # Install a given version of ChromeDriver for all supported OSs...
  6. php artisan dusk:chrome-driver --all
  7. # Install the version of ChromeDriver that matches the detected version of Chrome / Chromium for your OS...
  8. php artisan dusk:chrome-driver --detect

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

Using Other Browsers

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

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

  1. /**
  2. * Prepare for Dusk test execution.
  3. *
  4. * @beforeClass
  5. */
  6. public static function prepare(): void
  7. {
  8. // static::startChromeDriver();
  9. }

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

  1. use Facebook\WebDriver\Remote\RemoteWebDriver;
  2. /**
  3. * Create the RemoteWebDriver instance.
  4. */
  5. protected function driver(): RemoteWebDriver
  6. {
  7. return RemoteWebDriver::create(
  8. 'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()
  9. );
  10. }

Getting Started

Generating Tests

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

  1. php artisan dusk:make LoginTest

Resetting the Database After Each Test

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

Using Database Migrations

  1. ``````php
  2. <?php
  3. use Illuminate\Foundation\Testing\DatabaseMigrations;
  4. use Laravel\Dusk\Browser;
  5. uses(DatabaseMigrations::class);
  6. //
  7. `
  1. <?php
  2. namespace Tests\Browser;
  3. use Illuminate\Foundation\Testing\DatabaseMigrations;
  4. use Laravel\Dusk\Browser;
  5. use Tests\DuskTestCase;
  6. class ExampleTest extends DuskTestCase
  7. {
  8. use DatabaseMigrations;
  9. //
  10. }

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

Using Database Truncation

DatabaseTruncationトレイトは、最初のテストでデータベースをマイグレーションして、データベーステーブルが正しく作成されていることを確認します。ただし、以降のテストでは、データベースのテーブルは単にトランケートされます - すべてのデータベースマイグレーションを再実行するよりも速度が向上します:

  1. <?php
  2. use Illuminate\Foundation\Testing\DatabaseTruncation;
  3. use Laravel\Dusk\Browser;
  4. uses(DatabaseTruncation::class);
  5. //
  1. <?php
  2. namespace Tests\Browser;
  3. use App\Models\User;
  4. use Illuminate\Foundation\Testing\DatabaseTruncation;
  5. use Laravel\Dusk\Browser;
  6. use Tests\DuskTestCase;
  7. class ExampleTest extends DuskTestCase
  8. {
  9. use DatabaseTruncation;
  10. //
  11. }

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

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

  1. /**
  2. * Indicates which tables should be truncated.
  3. *
  4. * @var array
  5. */
  6. protected $tablesToTruncate = ['users'];

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

  1. /**
  2. * Indicates which tables should be excluded from truncation.
  3. *
  4. * @var array
  5. */
  6. protected $exceptTables = ['users'];

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

  1. /**
  2. * Indicates which connections should have their tables truncated.
  3. *
  4. * @var array
  5. */
  6. protected $connectionsToTruncate = ['mysql'];

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

  1. /**
  2. * Perform any work that should take place before the database has started truncating.
  3. */
  4. protected function beforeTruncatingDatabase(): void
  5. {
  6. //
  7. }
  8. /**
  9. * Perform any work that should take place after the database has finished truncating.
  10. */
  11. protected function afterTruncatingDatabase(): void
  12. {
  13. //
  14. }

Running Tests

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

  1. php artisan dusk

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

  1. php artisan dusk:fails

duskコマンドは、通常Pest / PHPUnitテストランナーによって受け入れられる任意の引数を受け入れます。たとえば、特定のgroupのテストのみを実行することができます:

  1. php artisan dusk --group=foo

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

Manually Starting ChromeDriver

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

  1. /**
  2. * Prepare for Dusk test execution.
  3. *
  4. * @beforeClass
  5. */
  6. public static function prepare(): void
  7. {
  8. // static::startChromeDriver();
  9. }

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

  1. use Facebook\WebDriver\Remote\RemoteWebDriver;
  2. /**
  3. * Create the RemoteWebDriver instance.
  4. */
  5. protected function driver(): RemoteWebDriver
  6. {
  7. return RemoteWebDriver::create(
  8. 'http://localhost:9515', DesiredCapabilities::chrome()
  9. );
  10. }

Environment Handling

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

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

Browser Basics

Creating Browsers

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

  1. <?php
  2. use App\Models\User;
  3. use Illuminate\Foundation\Testing\DatabaseMigrations;
  4. use Laravel\Dusk\Browser;
  5. uses(DatabaseMigrations::class);
  6. test('basic example', function () {
  7. $user = User::factory()->create([
  8. 'email' => '',
  9. ]);
  10. $this->browse(function (Browser $browser) use ($user) {
  11. $browser->visit('/login')
  12. ->type('email', $user->email)
  13. ->type('password', 'password')
  14. ->press('Login')
  15. ->assertPathIs('/home');
  16. });
  17. });
  1. <?php
  2. namespace Tests\Browser;
  3. use App\Models\User;
  4. use Illuminate\Foundation\Testing\DatabaseMigrations;
  5. use Laravel\Dusk\Browser;
  6. use Tests\DuskTestCase;
  7. class ExampleTest extends DuskTestCase
  8. {
  9. use DatabaseMigrations;
  10. /**
  11. * A basic browser test example.
  12. */
  13. public function test_basic_example(): void
  14. {
  15. $user = User::factory()->create([
  16. 'email' => '',
  17. ]);
  18. $this->browse(function (Browser $browser) use ($user) {
  19. $browser->visit('/login')
  20. ->type('email', $user->email)
  21. ->type('password', 'password')
  22. ->press('Login')
  23. ->assertPathIs('/home');
  24. });
  25. }
  26. }

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

Creating Multiple Browsers

テストを適切に実行するために、複数のブラウザが必要な場合があります。たとえば、WebSocketと対話するチャット画面をテストするには、複数のブラウザが必要です。複数のブラウザを作成するには、browseメソッドに渡すクロージャのシグネチャにブラウザ引数を追加するだけです:

  1. $this->browse(function (Browser $first, Browser $second) {
  2. $first->loginAs(User::find(1))
  3. ->visit('/home')
  4. ->waitForText('Message');
  5. $second->loginAs(User::find(2))
  6. ->visit('/home')
  7. ->waitForText('Message')
  8. ->type('message', 'Hey Taylor')
  9. ->press('Send');
  10. $first->waitForText('Hey Taylor')
  11. ->assertSee('Jeffrey Way');
  12. });

Navigation

  1. ``````php
  2. $browser->visit('/login');
  3. `
  1. ``````php
  2. $browser->visitRoute($routeName, $parameters);
  3. `
  1. ``````php
  2. $browser->back();
  3. $browser->forward();
  4. `
  1. ``````php
  2. $browser->refresh();
  3. `

Resizing Browser Windows

  1. ``````php
  2. $browser->resize(1920, 1080);
  3. `
  1. ``````php
  2. $browser->maximize();
  3. `
  1. ``````php
  2. $browser->fitContent();
  3. `

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

  1. $browser->disableFitOnFailure();
  1. ``````php
  2. $browser->move($x = 100, $y = 100);
  3. `

Browser Macros

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

  1. <?php
  2. namespace App\Providers;
  3. use Illuminate\Support\ServiceProvider;
  4. use Laravel\Dusk\Browser;
  5. class DuskServiceProvider extends ServiceProvider
  6. {
  7. /**
  8. * Register Dusk's browser macros.
  9. */
  10. public function boot(): void
  11. {
  12. Browser::macro('scrollToElement', function (string $element = null) {
  13. $this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);");
  14. return $this;
  15. });
  16. }
  17. }
  1. ``````php
  2. $this->browse(function (Browser $browser) use ($user) {
  3. $browser->visit('/pay')
  4. ->scrollToElement('#credit-card-details')
  5. ->assertSee('Enter Credit Card Details');
  6. });
  7. `

Authentication

多くの場合、認証が必要なページをテストします。DuskのloginAsメソッドを使用して、すべてのテスト中にアプリケーションのログイン画面と対話しないようにできます。loginAsメソッドは、認証可能なモデルに関連付けられた主キーまたは認証可能なモデルインスタンスを受け取ります:

  1. use App\Models\User;
  2. use Laravel\Dusk\Browser;
  3. $this->browse(function (Browser $browser) {
  4. $browser->loginAs(User::find(1))
  5. ->visit('/home');
  6. });
  1. <a name="cookies"></a>
  2. ### Cookies
  3. `````cookie`````メソッドを使用して、暗号化されたクッキーの値を取得または設定できます。デフォルトでは、Laravelによって作成されたすべてのクッキーは暗号化されています:
  4. ``````php
  5. $browser->cookie('name');
  6. $browser->cookie('name', 'Taylor');
  7. `
  1. ``````php
  2. $browser->plainCookie('name');
  3. $browser->plainCookie('name', 'Taylor');
  4. `
  1. ``````php
  2. $browser->deleteCookie('name');
  3. `

Executing JavaScript

  1. ``````php
  2. $browser->script('document.documentElement.scrollTop = 0');
  3. $browser->script([
  4. 'document.body.scrollTop = 0',
  5. 'document.documentElement.scrollTop = 0',
  6. ]);
  7. $output = $browser->script('return window.location.pathname');
  8. `

Taking a Screenshot

  1. ``````php
  2. $browser->screenshot('filename');
  3. `
  1. ``````php
  2. $browser->responsiveScreenshots('filename');
  3. `
  1. ``````php
  2. $browser->screenshotElement('#selector', 'filename');
  3. `

Storing Console Output to Disk

  1. ``````php
  2. $browser->storeConsoleLog('filename');
  3. `

Storing Page Source to Disk

  1. ``````php
  2. $browser->storeSource('filename');
  3. `

Interacting With Elements

Dusk Selectors

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

  1. // HTML...
  2. <button>Login</button>
  3. // Test...
  4. $browser->click('.login-page .container div > button');

Duskセレクタを使用すると、CSSセレクタを記憶するのではなく、効果的なテストを書くことに集中できます。セレクタを定義するには、HTML要素にdusk属性を追加します。次に、Duskブラウザと対話する際に、セレクタを@で接頭辞を付けて、テスト内で添付された要素を操作します:

  1. // HTML...
  2. <button dusk="login-button">Login</button>
  3. // Test...
  4. $browser->click('@login-button');

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

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

Text, Values, and Attributes

Retrieving and Setting Values

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

  1. // Retrieve the value...
  2. $value = $browser->value('selector');
  3. // Set the value...
  4. $browser->value('selector', 'value');
  1. ``````php
  2. $value = $browser->inputValue('field');
  3. `

Retrieving Text

  1. ``````php
  2. $text = $browser->text('selector');
  3. `

Retrieving Attributes

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

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

Interacting With Forms

Typing Values

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

  1. $browser->type('email', '');

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

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

  1. $browser->type('tags', 'foo')
  2. ->append('tags', ', bar, baz');
  1. ``````php
  2. $browser->clear('email');
  3. `

Duskに遅く入力するよう指示するには、typeSlowlyメソッドを使用します。デフォルトでは、Duskはキー入力の間に100ミリ秒の間隔を置きます。キー入力の間の時間をカスタマイズするには、メソッドの第3引数として適切なミリ秒数を渡します:

  1. $browser->typeSlowly('mobile', '+1 (202) 555-5555');
  2. $browser->typeSlowly('mobile', '+1 (202) 555-5555', 300);
  1. ``````php
  2. $browser->type('tags', 'foo')
  3. ->appendSlowly('tags', ', bar, baz');
  4. `

Dropdowns

  1. ``````php
  2. $browser->select('size', 'Large');
  3. `

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

  1. $browser->select('size');
  1. ``````php
  2. $browser->select('categories', ['Art', 'Music']);
  3. `

Checkboxes

  1. ``````php
  2. $browser->check('terms');
  3. `
  1. ``````php
  2. $browser->uncheck('terms');
  3. `

Radio Buttons

  1. ``````php
  2. $browser->radio('size', 'large');
  3. `

Attaching Files

  1. ``````php
  2. $browser->attach('photo', __DIR__.'/photos/mountains.png');
  3. `

添付機能を使用するには、サーバーにZip PHP拡張がインストールされ、有効になっている必要があります。

Pressing Buttons

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

  1. $browser->press('Login');

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

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

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

  1. $browser->clickLink($linkText);

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

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

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

Using the Keyboard

  1. ``````php
  2. $browser->keys('selector', ['{shift}', 'taylor'], 'swift');
  3. `
  1. ``````php
  2. $browser->keys('.app', ['{command}', 'j']);
  3. `

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

Fluent Keyboard Interactions

DuskはwithKeyboardメソッドも提供しており、Laravel\Dusk\Keyboardクラスを介して複雑なキーボード操作を流暢に実行できます。Keyboardクラスは、pressreleasetype、およびpauseメソッドを提供します:

  1. use Laravel\Dusk\Keyboard;
  2. $browser->withKeyboard(function (Keyboard $keyboard) {
  3. $keyboard->press('c')
  4. ->pause(1000)
  5. ->release('c')
  6. ->type(['c', 'e', 'o']);
  7. });

Keyboard Macros

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

  1. <?php
  2. namespace App\Providers;
  3. use Facebook\WebDriver\WebDriverKeys;
  4. use Illuminate\Support\ServiceProvider;
  5. use Laravel\Dusk\Keyboard;
  6. use Laravel\Dusk\OperatingSystem;
  7. class DuskServiceProvider extends ServiceProvider
  8. {
  9. /**
  10. * Register Dusk's browser macros.
  11. */
  12. public function boot(): void
  13. {
  14. Keyboard::macro('copy', function (string $element = null) {
  15. $this->type([
  16. OperatingSystem::onMac() ? WebDriverKeys::META : WebDriverKeys::CONTROL, 'c',
  17. ]);
  18. return $this;
  19. });
  20. Keyboard::macro('paste', function (string $element = null) {
  21. $this->type([
  22. OperatingSystem::onMac() ? WebDriverKeys::META : WebDriverKeys::CONTROL, 'v',
  23. ]);
  24. return $this;
  25. });
  26. }
  27. }
  1. ``````php
  2. $browser->click('@textarea')
  3. ->withKeyboard(fn (Keyboard $keyboard) => $keyboard->copy())
  4. ->click('@another-textarea')
  5. ->withKeyboard(fn (Keyboard $keyboard) => $keyboard->paste());
  6. `

Using the Mouse

Clicking on Elements

  1. ``````php
  2. $browser->click('.selector');
  3. `
  1. ``````php
  2. $browser->clickAtXPath('//div[@class = "selector"]');
  3. `
  1. ``````php
  2. $browser->clickAtPoint($x = 0, $y = 0);
  3. `
  1. ``````php
  2. $browser->doubleClick();
  3. $browser->doubleClick('.selector');
  4. `
  1. ``````php
  2. $browser->rightClick();
  3. $browser->rightClick('.selector');
  4. `
  1. ``````php
  2. $browser->clickAndHold('.selector');
  3. $browser->clickAndHold()
  4. ->pause(1000)
  5. ->releaseMouse();
  6. `
  1. ``````php
  2. $browser->controlClick();
  3. $browser->controlClick('.selector');
  4. `

Mouseover

  1. ``````php
  2. $browser->mouseover('.selector');
  3. `

Drag and Drop

  1. ``````php
  2. $browser->drag('.from-selector', '.to-selector');
  3. `

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

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

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

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

JavaScript Dialogs

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

  1. $browser->waitForDialog($seconds = null);
  1. ``````php
  2. $browser->assertDialogOpened('Dialog message');
  3. `

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

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

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

  1. $browser->acceptDialog();

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

  1. $browser->dismissDialog();

Interacting With Inline Frames

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

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

Scoping Selectors

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

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

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

  1. $browser->with('.table', function (Browser $table) {
  2. // Current scope is `body .table`...
  3. $browser->elsewhere('.page-title', function (Browser $title) {
  4. // Current scope is `body .page-title`...
  5. $title->assertSee('Hello World');
  6. });
  7. $browser->elsewhereWhenAvailable('.page-title', function (Browser $title) {
  8. // Current scope is `body .page-title`...
  9. $title->assertSee('Hello World');
  10. });
  11. });

Waiting for Elements

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

Waiting

指定されたミリ秒数だけテストを一時停止する必要がある場合は、pauseメソッドを使用します:

  1. $browser->pause(1000);

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

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

同様に、指定された条件がtrueでない限りテストを一時停止する必要がある場合は、pauseUnlessメソッドを使用します:

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

Waiting for Selectors

  1. ``````php
  2. // Wait a maximum of five seconds for the selector...
  3. $browser->waitFor('.selector');
  4. // Wait a maximum of one second for the selector...
  5. $browser->waitFor('.selector', 1);
  6. `

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

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

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

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

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

  1. // Wait a maximum of five seconds until the selector is enabled...
  2. $browser->waitUntilEnabled('.selector');
  3. // Wait a maximum of one second until the selector is enabled...
  4. $browser->waitUntilEnabled('.selector', 1);
  5. // Wait a maximum of five seconds until the selector is disabled...
  6. $browser->waitUntilDisabled('.selector');
  7. // Wait a maximum of one second until the selector is disabled...
  8. $browser->waitUntilDisabled('.selector', 1);

Scoping Selectors When Available

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

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

テキストの待機

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

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

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

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

リンクの待機

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

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

入力の待機

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

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

ページの位置の待機

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

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

waitForLocation メソッドを使用して、現在のウィンドウの位置が完全修飾URLになるまで待機することもできます:

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

名前付きルートの位置を待機することもできます:

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

ページのリロードの待機

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

  1. use Laravel\Dusk\Browser;
  2. $browser->waitForReload(function (Browser $browser) {
  3. $browser->press('Submit');
  4. })
  5. ->assertSee('Success!');

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

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

JavaScript式の待機

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

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

Vue式の待機

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

  1. // Wait until the component attribute contains the given value...
  2. $browser->waitUntilVue('user.name', 'Taylor', '@user');
  3. // Wait until the component attribute doesn't contain the given value...
  4. $browser->waitUntilVueIsNot('user.name', null, '@user');

JavaScriptイベントの待機

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

  1. $browser->waitForEvent('load');

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

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

waitForEvent メソッドの第2引数としてセレクタを提供して、特定の要素にイベントリスナーを添付することもできます:

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

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

  1. // Wait until the document is scrolled...
  2. $browser->waitForEvent('scroll', 'document');
  3. // Wait a maximum of five seconds until the window is resized...
  4. $browser->waitForEvent('resize', 'window', 5);

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

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

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

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

時々、要素がブラウザの表示可能エリアの外にあるため、要素をクリックできないことがあります。scrollIntoView メソッドは、指定されたセレクタの要素が表示されるまでブラウザウィンドウをスクロールします:

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

利用可能なアサーション

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

assertTitle assertTitleContains assertUrlIs assertSchemeIs assertSchemeIsNot assertHostIs assertHostIsNot assertPortIs assertPortIsNot assertPathBeginsWith assertPathEndsWith assertPathContains assertPathIs assertPathIsNot assertRouteIs assertQueryStringHas assertQueryStringMissing assertFragmentIs assertFragmentBeginsWith assertFragmentIsNot assertHasCookie assertHasPlainCookie assertCookieMissing assertPlainCookieMissing assertCookieValue assertPlainCookieValue assertSee assertDontSee assertSeeIn assertDontSeeIn assertSeeAnythingIn assertSeeNothingIn assertScript assertSourceHas assertSourceMissing assertSeeLink assertDontSeeLink assertInputValue assertInputValueIsNot assertChecked assertNotChecked assertIndeterminate assertRadioSelected assertRadioNotSelected assertSelected assertNotSelected assertSelectHasOptions assertSelectMissingOptions assertSelectHasOption assertSelectMissingOption assertValue assertValueIsNot assertAttribute assertAttributeContains assertAttributeDoesntContain assertAriaAttribute assertDataAttribute assertVisible assertPresent assertNotPresent assertMissing assertInputPresent assertInputMissing assertDialogOpened assertEnabled assertDisabled assertButtonEnabled assertButtonDisabled assertFocused assertNotFocused assertAuthenticated assertGuest assertAuthenticatedAs assertVue assertVueIsNot assertVueContains assertVueDoesntContain

assertTitle

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

  1. $browser->assertTitle($title);

assertTitleContains

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

  1. $browser->assertTitleContains($title);

assertUrlIs

現在のURL(クエリ文字列なし)が指定された文字列と一致することを確認します:

  1. $browser->assertUrlIs($url);

assertSchemeIs

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

  1. $browser->assertSchemeIs($scheme);

assertSchemeIsNot

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

  1. $browser->assertSchemeIsNot($scheme);

assertHostIs

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

  1. $browser->assertHostIs($host);

assertHostIsNot

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

  1. $browser->assertHostIsNot($host);

assertPortIs

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

  1. $browser->assertPortIs($port);

assertPortIsNot

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

  1. $browser->assertPortIsNot($port);

assertPathBeginsWith

現在のURLパスが指定されたパスで始まることを確認します:

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

assertPathEndsWith

現在のURLパスが指定されたパスで終わることを確認します:

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

assertPathContains

現在のURLパスが指定されたパスを含むことを確認します:

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

assertPathIs

現在のパスが指定されたパスと一致することを確認します:

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

assertPathIsNot

現在のパスが指定されたパスと一致しないことを確認します:

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

assertRouteIs

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

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

assertQueryStringHas

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

  1. $browser->assertQueryStringHas($name);

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

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

assertQueryStringMissing

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

  1. $browser->assertQueryStringMissing($name);

assertFragmentIs

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

  1. $browser->assertFragmentIs('anchor');

assertFragmentBeginsWith

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

  1. $browser->assertFragmentBeginsWith('anchor');

assertFragmentIsNot

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

  1. $browser->assertFragmentIsNot('anchor');

assertHasCookie

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

  1. $browser->assertHasCookie($name);

assertHasPlainCookie

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

  1. $browser->assertHasPlainCookie($name);

assertCookieMissing

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

  1. $browser->assertCookieMissing($name);

assertPlainCookieMissing

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

  1. $browser->assertPlainCookieMissing($name);

assertCookieValue

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

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

assertPlainCookieValue

暗号化されていないクッキーが指定された値を持つことを確認します:

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

assertSee

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

  1. $browser->assertSee($text);

assertDontSee

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

  1. $browser->assertDontSee($text);

assertSeeIn

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

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

assertDontSeeIn

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

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

assertSeeAnythingIn

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

  1. $browser->assertSeeAnythingIn($selector);

assertSeeNothingIn

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

  1. $browser->assertSeeNothingIn($selector);

assertScript

指定されたJavaScript式が指定された値に評価されることを確認します:

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

assertSourceHas

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

  1. $browser->assertSourceHas($code);

assertSourceMissing

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

  1. $browser->assertSourceMissing($code);

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

  1. $browser->assertSeeLink($linkText);

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

  1. $browser->assertDontSeeLink($linkText);

assertInputValue

指定された入力フィールドが指定された値を持つことを確認します:

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

assertInputValueIsNot

指定された入力フィールドが指定された値を持たないことを確認します:

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

assertChecked

指定されたチェックボックスがチェックされていることを確認します:

  1. $browser->assertChecked($field);

assertNotChecked

指定されたチェックボックスがチェックされていないことを確認します:

  1. $browser->assertNotChecked($field);

assertIndeterminate

指定されたチェックボックスが不確定状態であることを確認します:

  1. $browser->assertIndeterminate($field);

assertRadioSelected

指定されたラジオフィールドが選択されていることを確認します:

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

assertRadioNotSelected

指定されたラジオフィールドが選択されていないことを確認します:

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

assertSelected

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

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

assertNotSelected

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

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

assertSelectHasOptions

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

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

assertSelectMissingOptions

指定された値の配列が選択できないことを確認します:

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

assertSelectHasOption

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

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

assertSelectMissingOption

指定された値が選択できないことを確認します:

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

assertValue

指定されたセレクタに一致する要素が指定された値を持つことを確認します:

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

assertValueIsNot

指定されたセレクタに一致する要素が指定された値を持たないことを確認します:

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

assertAttribute

指定されたセレクタに一致する要素が指定された属性に指定された値を持つことを確認します:

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

assertAttributeContains

指定されたセレクタに一致する要素が指定された属性に指定された値を含むことを確認します:

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

assertAttributeDoesntContain

指定されたセレクタに一致する要素が指定された属性に指定された値を含まないことを確認します:

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

assertAriaAttribute

指定されたセレクタに一致する要素が指定されたaria属性に指定された値を持つことを確認します:

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

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

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

assertDataAttribute

指定されたセレクタに一致する要素が指定されたデータ属性に指定された値を持つことを確認します:

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

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

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

assertVisible

指定されたセレクタに一致する要素が表示されていることを確認します:

  1. $browser->assertVisible($selector);

assertPresent

指定されたセレクタに一致する要素がソースに存在することを確認します:

  1. $browser->assertPresent($selector);

assertNotPresent

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

  1. $browser->assertNotPresent($selector);

assertMissing

指定されたセレクタに一致する要素が表示されていないことを確認します:

  1. $browser->assertMissing($selector);

assertInputPresent

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

  1. $browser->assertInputPresent($name);

assertInputMissing

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

  1. $browser->assertInputMissing($name);

assertDialogOpened

指定されたメッセージのJavaScriptダイアログが開かれていることを確認します:

  1. $browser->assertDialogOpened($message);

assertEnabled

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

  1. $browser->assertEnabled($field);

assertDisabled

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

  1. $browser->assertDisabled($field);

assertButtonEnabled

指定されたボタンが有効であることを確認します:

  1. $browser->assertButtonEnabled($button);

assertButtonDisabled

指定されたボタンが無効であることを確認します:

  1. $browser->assertButtonDisabled($button);

assertFocused

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

  1. $browser->assertFocused($field);

assertNotFocused

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

  1. $browser->assertNotFocused($field);

assertAuthenticated

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

  1. $browser->assertAuthenticated();

assertGuest

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

  1. $browser->assertGuest();

assertAuthenticatedAs

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

  1. $browser->assertAuthenticatedAs($user);

assertVue

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

  1. // HTML...
  2. <profile dusk="profile-component"></profile>
  3. // Component Definition...
  4. Vue.component('profile', {
  5. template: '<div>{{ user.name }}</div>',
  6. data: function () {
  7. return {
  8. user: {
  9. name: 'Taylor'
  10. }
  11. };
  12. }
  13. });

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

  1. test('vue', function () {
  2. $this->browse(function (Browser $browser) {
  3. $browser->visit('/')
  4. ->assertVue('user.name', 'Taylor', '@profile-component');
  5. });
  6. });
  1. /**
  2. * A basic Vue test example.
  3. */
  4. public function test_vue(): void
  5. {
  6. $this->browse(function (Browser $browser) {
  7. $browser->visit('/')
  8. ->assertVue('user.name', 'Taylor', '@profile-component');
  9. });
  10. }

assertVueIsNot

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

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

assertVueContains

指定されたVueコンポーネントデータプロパティが配列であり、指定された値を含むことを確認します:

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

assertVueDoesntContain

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

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

ページ

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

ページの生成

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

  1. php artisan dusk:page Login

ページの設定

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

url メソッド

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

  1. /**
  2. * Get the URL for the page.
  3. */
  4. public function url(): string
  5. {
  6. return '/login';
  7. }

assert メソッド

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

  1. /**
  2. * Assert that the browser is on the page.
  3. */
  4. public function assert(Browser $browser): void
  5. {
  6. $browser->assertPathIs($this->url());
  7. }

ページへの移動

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

  1. use Tests\Browser\Pages\Login;
  2. $browser->visit(new Login);

時には、すでに特定のページにいて、そのページのセレクタとメソッドを現在のテストコンテキストに「ロード」する必要があることがあります。これは、ボタンを押して特定のページにリダイレクトされるときによくあります。この場合、on メソッドを使用してページをロードできます:

  1. use Tests\Browser\Pages\CreatePlaylist;
  2. $browser->visit('/dashboard')
  3. ->clickLink('Create Playlist')
  4. ->on(new CreatePlaylist)
  5. ->assertSee('@create');

ショートハンドセレクタ

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

  1. /**
  2. * Get the element shortcuts for the page.
  3. *
  4. * @return array<string, string>
  5. */
  6. public function elements(): array
  7. {
  8. return [
  9. '@email' => 'input[name=email]',
  10. ];
  11. }

ショートカットが定義されると、通常のCSSセレクタを使用する場所でショートハンドセレクタを使用できます:

  1. $browser->type('@email', '');

グローバルショートハンドセレクタ

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

  1. /**
  2. * Get the global element shortcuts for the site.
  3. *
  4. * @return array<string, string>
  5. */
  6. public static function siteElements(): array
  7. {
  8. return [
  9. '@element' => '#selector',
  10. ];
  11. }

ページメソッド

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

  1. <?php
  2. namespace Tests\Browser\Pages;
  3. use Laravel\Dusk\Browser;
  4. use Laravel\Dusk\Page;
  5. class Dashboard extends Page
  6. {
  7. // Other page methods...
  8. /**
  9. * Create a new playlist.
  10. */
  11. public function createPlaylist(Browser $browser, string $name): void
  12. {
  13. $browser->type('name', $name)
  14. ->check('share')
  15. ->press('Create Playlist');
  16. }
  17. }

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

  1. use Tests\Browser\Pages\Dashboard;
  2. $browser->visit(new Dashboard)
  3. ->createPlaylist('My Playlist')
  4. ->assertSee('My Playlist');

コンポーネント

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

コンポーネントの生成

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

  1. php artisan dusk:component DatePicker

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

  1. <?php
  2. namespace Tests\Browser\Components;
  3. use Laravel\Dusk\Browser;
  4. use Laravel\Dusk\Component as BaseComponent;
  5. class DatePicker extends BaseComponent
  6. {
  7. /**
  8. * Get the root selector for the component.
  9. */
  10. public function selector(): string
  11. {
  12. return '.date-picker';
  13. }
  14. /**
  15. * Assert that the browser page contains the component.
  16. */
  17. public function assert(Browser $browser): void
  18. {
  19. $browser->assertVisible($this->selector());
  20. }
  21. /**
  22. * Get the element shortcuts for the component.
  23. *
  24. * @return array<string, string>
  25. */
  26. public function elements(): array
  27. {
  28. return [
  29. '@date-field' => 'input.datepicker-input',
  30. '@year-list' => 'div > div.datepicker-years',
  31. '@month-list' => 'div > div.datepicker-months',
  32. '@day-list' => 'div > div.datepicker-days',
  33. ];
  34. }
  35. /**
  36. * Select the given date.
  37. */
  38. public function selectDate(Browser $browser, int $year, int $month, int $day): void
  39. {
  40. $browser->click('@date-field')
  41. ->within('@year-list', function (Browser $browser) use ($year) {
  42. $browser->click($year);
  43. })
  44. ->within('@month-list', function (Browser $browser) use ($month) {
  45. $browser->click($month);
  46. })
  47. ->within('@day-list', function (Browser $browser) use ($day) {
  48. $browser->click($day);
  49. });
  50. }
  51. }

コンポーネントの使用

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

  1. <?php
  2. use Illuminate\Foundation\Testing\DatabaseMigrations;
  3. use Laravel\Dusk\Browser;
  4. use Tests\Browser\Components\DatePicker;
  5. uses(DatabaseMigrations::class);
  6. test('basic example', function () {
  7. $this->browse(function (Browser $browser) {
  8. $browser->visit('/')
  9. ->within(new DatePicker, function (Browser $browser) {
  10. $browser->selectDate(2019, 1, 30);
  11. })
  12. ->assertSee('January');
  13. });
  14. });
  1. <?php
  2. namespace Tests\Browser;
  3. use Illuminate\Foundation\Testing\DatabaseMigrations;
  4. use Laravel\Dusk\Browser;
  5. use Tests\Browser\Components\DatePicker;
  6. use Tests\DuskTestCase;
  7. class ExampleTest extends DuskTestCase
  8. {
  9. /**
  10. * A basic component test example.
  11. */
  12. public function test_basic_example(): void
  13. {
  14. $this->browse(function (Browser $browser) {
  15. $browser->visit('/')
  16. ->within(new DatePicker, function (Browser $browser) {
  17. $browser->selectDate(2019, 1, 30);
  18. })
  19. ->assertSee('January');
  20. });
  21. }
  22. }

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

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

Heroku CI

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

  1. {
  2. "environments": {
  3. "test": {
  4. "buildpacks": [
  5. { "url": "heroku/php" },
  6. { "url": "https://github.com/heroku/heroku-buildpack-chrome-for-testing" }
  7. ],
  8. "scripts": {
  9. "test-setup": "cp .env.testing .env",
  10. "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"
  11. }
  12. }
  13. }
  14. }

Travis CI

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

  1. language: php
  2. php:
  3. - 8.2
  4. addons:
  5. chrome: stable
  6. install:
  7. - cp .env.testing .env
  8. - travis_retry composer install --no-interaction --prefer-dist
  9. - php artisan key:generate
  10. - php artisan dusk:chrome-driver
  11. before_script:
  12. - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
  13. - php artisan serve --no-reload &
  14. script:
  15. - php artisan dusk

GitHub Actions

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

  1. name: CI
  2. on: [push]
  3. jobs:
  4. dusk-php:
  5. runs-on: ubuntu-latest
  6. env:
  7. APP_URL: "http://127.0.0.1:8000"
  8. DB_USERNAME: root
  9. DB_PASSWORD: root
  10. MAIL_MAILER: log
  11. steps:
  12. - uses: actions/checkout@v4
  13. - name: Prepare The Environment
  14. run: cp .env.example .env
  15. - name: Create Database
  16. run: |
  17. sudo systemctl start mysql
  18. mysql --user="root" --password="root" -e "CREATE DATABASE \`my-database\` character set UTF8mb4 collate utf8mb4_bin;"
  19. - name: Install Composer Dependencies
  20. run: composer install --no-progress --prefer-dist --optimize-autoloader
  21. - name: Generate Application Key
  22. run: php artisan key:generate
  23. - name: Upgrade Chrome Driver
  24. run: php artisan dusk:chrome-driver --detect
  25. - name: Start Chrome Driver
  26. run: ./vendor/laravel/dusk/bin/chromedriver-linux --port=9515 &
  27. - name: Run Laravel Server
  28. run: php artisan serve --no-reload &
  29. - name: Run Dusk Tests
  30. run: php artisan dusk
  31. - name: Upload Screenshots
  32. if: failure()
  33. uses: actions/upload-artifact@v4
  34. with:
  35. name: screenshots
  36. path: tests/Browser/screenshots
  37. - name: Upload Console Logs
  38. if: failure()
  39. uses: actions/upload-artifact@v4
  40. with:
  41. name: console
  42. path: tests/Browser/console

Chipper CI

Chipper CI を使用してDuskテストを実行する場合、次の構成ファイルを出発点として使用できます。Laravelを実行するためにPHPの組み込みサーバーを使用し、リクエストをリッスンします:

  1. # file .chipperci.yml
  2. version: 1
  3. environment:
  4. php: 8.2
  5. node: 16
  6. # ビルド環境にChromeを含める
  7. services:
  8. - dusk
  9. # すべてのコミットをビルド
  10. on:
  11. push:
  12. branches: .*
  13. pipeline:
  14. - name: Setup
  15. cmd: |
  16. cp -v .env.example .env
  17. composer install --no-interaction --prefer-dist --optimize-autoloader
  18. php artisan key:generate
  19. # Dusk envファイルを作成し、APP_URLがBUILD_HOSTを使用することを確認します
  20. cp -v .env .env.dusk.ci
  21. sed -i "s@APP_URL=.*@APP_URL=http://$BUILD_HOST:8000@g" .env.dusk.ci
  22. - name: Compile Assets
  23. cmd: |
  24. npm ci --no-audit
  25. npm run build
  26. - name: Browser Tests
  27. cmd: |
  28. php -S [::0]:8000 -t public 2>server.log \u0026
  29. sleep 2
  30. php artisan dusk:chrome-driver $CHROME_DRIVER
  31. php artisan dusk --env=ci

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