- Introduction
- Installation
- Getting Started
- Browser Basics
- Interacting With Elements
- 利用可能なアサーション
- 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
- ページ
- コンポーネント
- 継続的インテグレーション
Introduction
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
コマンドは、tests/Browser
ディレクトリ、例のDuskテスト、およびオペレーティングシステム用のChrome Driverバイナリを作成します:
php artisan dusk:install
次に、アプリケーションの.env
ファイルにAPP_URL
環境変数を設定します。この値は、ブラウザでアプリケーションにアクセスするために使用するURLと一致する必要があります。
Laravel Sailを使用してローカル開発環境を管理している場合は、Duskテストの設定と実行に関するSailのドキュメントも参照してください。
Managing ChromeDriver Installations
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/
。
Using Other Browsers
デフォルトでは、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に渡すべき「希望の機能」を変更できます:
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
Generating Tests
Duskテストを生成するには、dusk:make
Artisanコマンドを使用します。生成されたテストはtests/Browser
ディレクトリに配置されます:
php artisan dusk:make LoginTest
Resetting the Database After Each Test
ほとんどのテストは、アプリケーションのデータベースからデータを取得するページと対話します。ただし、DuskテストではRefreshDatabase
トレイトを使用してはいけません。RefreshDatabase
トレイトはデータベーストランザクションを利用しますが、これはHTTPリクエスト間で適用されないか、利用できません。代わりに、DatabaseMigrations
トレイトとDatabaseTruncation
トレイトの2つのオプションがあります。
Using Database Migrations
``````php
<?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;
//
}
SQLiteのインメモリデータベースは、Duskテストを実行する際に使用できません。ブラウザは独自のプロセス内で実行されるため、他のプロセスのインメモリデータベースにアクセスできません。
Using Database Truncation
DatabaseTruncation
トレイトは、最初のテストでデータベースをマイグレーションして、データベーステーブルが正しく作成されていることを確認します。ただし、以降のテストでは、データベースのテーブルは単にトランケートされます - すべてのデータベースマイグレーションを再実行するよりも速度が向上します:
<?php
use Illuminate\Foundation\Testing\DatabaseTruncation;
use Laravel\Dusk\Browser;
uses(DatabaseTruncation::class);
//
<?php
namespace Tests\Browser;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTruncation;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseTruncation;
//
}
デフォルトでは、このトレイトはmigrations
テーブルを除いてすべてのテーブルをトランケートします。トランケートするテーブルをカスタマイズしたい場合は、テストクラスに$tablesToTruncate
プロパティを定義できます:
Pestを使用している場合は、ベースDuskTestCase
クラスまたはテストファイルが拡張する任意のクラスにプロパティまたはメソッドを定義する必要があります。
/**
* Indicates which tables should be truncated.
*
* @var array
*/
protected $tablesToTruncate = ['users'];
または、テストクラスに$exceptTables
プロパティを定義して、トランケートから除外するテーブルを指定できます:
/**
* Indicates which tables should be excluded from truncation.
*
* @var array
*/
protected $exceptTables = ['users'];
トランケートするテーブルのデータベース接続を指定するには、テストクラスに$connectionsToTruncate
プロパティを定義できます:
/**
* Indicates which connections should have their tables truncated.
*
* @var array
*/
protected $connectionsToTruncate = ['mysql'];
データベーストランケーションが実行される前後にコードを実行したい場合は、テストクラスにbeforeTruncatingDatabase
またはafterTruncatingDatabase
メソッドを定義できます:
/**
* Perform any work that should take place before the database has started truncating.
*/
protected function beforeTruncatingDatabase(): void
{
//
}
/**
* Perform any work that should take place after the database has finished truncating.
*/
protected function afterTruncatingDatabase(): void
{
//
}
Running Tests
ブラウザテストを実行するには、dusk
Artisanコマンドを実行します:
php artisan dusk
前回dusk
コマンドを実行したときにテストが失敗した場合、dusk:fails
コマンドを使用して失敗したテストを最初に再実行することで時間を節約できます:
php artisan dusk:fails
dusk
コマンドは、通常Pest / PHPUnitテストランナーによって受け入れられる任意の引数を受け入れます。たとえば、特定のgroupのテストのみを実行することができます:
php artisan dusk --group=foo
Laravel Sailを使用してローカル開発環境を管理している場合は、Duskテストの設定と実行に関するSailのドキュメントを参照してください。
Manually Starting 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()
);
}
Environment Handling
Duskがテストを実行する際に独自の環境ファイルを使用するよう強制するには、プロジェクトのルートに.env.dusk.{environment}
ファイルを作成します。たとえば、dusk
コマンドをlocal
環境から開始する場合は、.env.dusk.local
ファイルを作成する必要があります。
テストを実行すると、Duskは.env
ファイルをバックアップし、Dusk環境を.env
にリネームします。テストが完了すると、.env
ファイルが復元されます。
Browser Basics
Creating Browsers
始めるには、アプリケーションにログインできることを確認するテストを書きましょう。テストを生成した後、ログインページに移動し、いくつかの資格情報を入力し、「ログイン」ボタンをクリックするように変更できます。ブラウザインスタンスを作成するには、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' => '',
]);
$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' => '',
]);
$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/login')
->type('email', $user->email)
->type('password', 'password')
->press('Login')
->assertPathIs('/home');
});
}
}
上記の例に示すように、browse
メソッドはクロージャを受け入れます。ブラウザインスタンスはDuskによって自動的にこのクロージャに渡され、アプリケーションと対話し、アサーションを行うために使用される主要なオブジェクトです。
Creating Multiple Browsers
テストを適切に実行するために、複数のブラウザが必要な場合があります。たとえば、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');
});
Navigation
``````php
$browser->visit('/login');
`
``````php
$browser->visitRoute($routeName, $parameters);
`
``````php
$browser->back();
$browser->forward();
`
``````php
$browser->refresh();
`
Resizing Browser Windows
``````php
$browser->resize(1920, 1080);
`
``````php
$browser->maximize();
`
``````php
$browser->fitContent();
`
テストが失敗した場合、Duskは自動的にブラウザをコンテンツに合わせてリサイズし、スクリーンショットを撮る前に行います。この機能を無効にするには、テスト内でdisableFitOnFailure
メソッドを呼び出します:
$browser->disableFitOnFailure();
``````php
$browser->move($x = 100, $y = 100);
`
Browser Macros
さまざまなテストで再利用できるカスタムブラウザメソッドを定義したい場合は、macro
メソッドをBrowser
クラスで使用できます。通常、このメソッドはサービスプロバイダの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;
});
}
}
``````php
$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/pay')
->scrollToElement('#credit-card-details')
->assertSee('Enter Credit Card Details');
});
`
Authentication
多くの場合、認証が必要なページをテストします。DuskのloginAs
メソッドを使用して、すべてのテスト中にアプリケーションのログイン画面と対話しないようにできます。loginAs
メソッドは、認証可能なモデルに関連付けられた主キーまたは認証可能なモデルインスタンスを受け取ります:
use App\Models\User;
use Laravel\Dusk\Browser;
$this->browse(function (Browser $browser) {
$browser->loginAs(User::find(1))
->visit('/home');
});
<a name="cookies"></a>
### Cookies
`````cookie`````メソッドを使用して、暗号化されたクッキーの値を取得または設定できます。デフォルトでは、Laravelによって作成されたすべてのクッキーは暗号化されています:
``````php
$browser->cookie('name');
$browser->cookie('name', 'Taylor');
`
``````php
$browser->plainCookie('name');
$browser->plainCookie('name', 'Taylor');
`
``````php
$browser->deleteCookie('name');
`
Executing JavaScript
``````php
$browser->script('document.documentElement.scrollTop = 0');
$browser->script([
'document.body.scrollTop = 0',
'document.documentElement.scrollTop = 0',
]);
$output = $browser->script('return window.location.pathname');
`
Taking a Screenshot
``````php
$browser->screenshot('filename');
`
``````php
$browser->responsiveScreenshots('filename');
`
``````php
$browser->screenshotElement('#selector', 'filename');
`
Storing Console Output to Disk
``````php
$browser->storeConsoleLog('filename');
`
Storing Page Source to Disk
``````php
$browser->storeSource('filename');
`
Interacting With Elements
Dusk Selectors
要素と対話するための良い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
メソッドを介してカスタマイズできます。通常、このメソッドはアプリケーションのAppServiceProvider
のboot
メソッドから呼び出すべきです:
use Laravel\Dusk\Dusk;
Dusk::selectorHtmlAttribute('data-dusk');
Text, Values, and Attributes
Retrieving and Setting Values
Duskは、ページ上の要素の現在の値、表示テキスト、および属性と対話するためのいくつかのメソッドを提供します。たとえば、指定されたCSSまたはDuskセレクタに一致する要素の「値」を取得するには、value
メソッドを使用します:
// Retrieve the value...
$value = $browser->value('selector');
// Set the value...
$browser->value('selector', 'value');
``````php
$value = $browser->inputValue('field');
`
Retrieving Text
``````php
$text = $browser->text('selector');
`
Retrieving Attributes
最後に、attribute
メソッドを使用して、指定されたセレクタに一致する要素の属性の値を取得できます:
$attribute = $browser->attribute('selector', 'value');
Interacting With Forms
Typing Values
Duskは、フォームや入力要素と対話するためのさまざまなメソッドを提供します。まず、入力フィールドにテキストを入力する例を見てみましょう:
$browser->type('email', '');
メソッドは必要に応じて1つを受け入れますが、type
メソッドにCSSセレクタを渡す必要はありません。CSSセレクタが提供されていない場合、Duskは指定されたname
属性を持つinput
またはtextarea
フィールドを検索します。
フィールドの内容をクリアせずにテキストを追加するには、append
メソッドを使用します:
$browser->type('tags', 'foo')
->append('tags', ', bar, baz');
``````php
$browser->clear('email');
`
Duskに遅く入力するよう指示するには、typeSlowly
メソッドを使用します。デフォルトでは、Duskはキー入力の間に100ミリ秒の間隔を置きます。キー入力の間の時間をカスタマイズするには、メソッドの第3引数として適切なミリ秒数を渡します:
$browser->typeSlowly('mobile', '+1 (202) 555-5555');
$browser->typeSlowly('mobile', '+1 (202) 555-5555', 300);
``````php
$browser->type('tags', 'foo')
->appendSlowly('tags', ', bar, baz');
`
Dropdowns
``````php
$browser->select('size', 'Large');
`
2番目の引数を省略することで、ランダムなオプションを選択できます:
$browser->select('size');
``````php
$browser->select('categories', ['Art', 'Music']);
`
Checkboxes
``````php
$browser->check('terms');
`
``````php
$browser->uncheck('terms');
`
Radio Buttons
``````php
$browser->radio('size', 'large');
`
Attaching Files
``````php
$browser->attach('photo', __DIR__.'/photos/mountains.png');
`
添付機能を使用するには、サーバーにZip
PHP拡張がインストールされ、有効になっている必要があります。
Pressing Buttons
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);
Clicking Links
リンクをクリックするには、ブラウザインスタンスでclickLink
メソッドを使用します。clickLink
メソッドは、指定された表示テキストを持つリンクをクリックします:
$browser->clickLink($linkText);
指定された表示テキストを持つリンクがページ上に表示されているかどうかを確認するには、seeLink
メソッドを使用します:
if ($browser->seeLink($linkText)) {
// ...
}
これらのメソッドはjQueryと対話します。ページにjQueryがない場合、Duskは自動的にページにjQueryを注入し、テストの期間中に利用できるようにします。
Using the Keyboard
``````php
$browser->keys('selector', ['{shift}', 'taylor'], 'swift');
`
``````php
$browser->keys('.app', ['{command}', 'j']);
`
すべての修飾キーは{}
文字でラップされ、Facebook\WebDriver\WebDriverKeys
クラスで定義された定数に一致します。これはGitHubで見つけることができます。
Fluent Keyboard Interactions
DuskはwithKeyboard
メソッドも提供しており、Laravel\Dusk\Keyboard
クラスを介して複雑なキーボード操作を流暢に実行できます。Keyboard
クラスは、press
、release
、type
、およびpause
メソッドを提供します:
use Laravel\Dusk\Keyboard;
$browser->withKeyboard(function (Keyboard $keyboard) {
$keyboard->press('c')
->pause(1000)
->release('c')
->type(['c', 'e', 'o']);
});
Keyboard Macros
テストスイート全体で簡単に再利用できるカスタムキーボード操作を定義したい場合は、macro
メソッドをKeyboard
クラスで使用できます。通常、このメソッドはサービスプロバイダの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;
});
}
}
``````php
$browser->click('@textarea')
->withKeyboard(fn (Keyboard $keyboard) => $keyboard->copy())
->click('@another-textarea')
->withKeyboard(fn (Keyboard $keyboard) => $keyboard->paste());
`
Using the Mouse
Clicking on Elements
``````php
$browser->click('.selector');
`
``````php
$browser->clickAtXPath('//div[@class = "selector"]');
`
``````php
$browser->clickAtPoint($x = 0, $y = 0);
`
``````php
$browser->doubleClick();
$browser->doubleClick('.selector');
`
``````php
$browser->rightClick();
$browser->rightClick('.selector');
`
``````php
$browser->clickAndHold('.selector');
$browser->clickAndHold()
->pause(1000)
->releaseMouse();
`
``````php
$browser->controlClick();
$browser->controlClick('.selector');
`
Mouseover
``````php
$browser->mouseover('.selector');
`
Drag and Drop
``````php
$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 Dialogs
DuskはJavaScriptダイアログと対話するためのさまざまなメソッドを提供します。たとえば、waitForDialog
メソッドを使用して、JavaScriptダイアログが表示されるのを待つことができます。このメソッドは、ダイアログが表示されるまでの待機時間を秒数で指定するオプションの引数を受け取ります:
$browser->waitForDialog($seconds = null);
``````php
$browser->assertDialogOpened('Dialog message');
`
JavaScriptダイアログにプロンプトが含まれている場合、typeInDialog
メソッドを使用してプロンプトに値を入力できます:
$browser->typeInDialog('Hello World');
「OK」ボタンをクリックして開いているJavaScriptダイアログを閉じるには、acceptDialog
メソッドを呼び出します:
$browser->acceptDialog();
「キャンセル」ボタンをクリックして開いているJavaScriptダイアログを閉じるには、dismissDialog
メソッドを呼び出します:
$browser->dismissDialog();
Interacting With Inline Frames
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');
});
Scoping Selectors
時には、特定のセレクタ内でのすべての操作をスコープする必要がある場合があります。たとえば、テーブル内にのみテキストが存在することを確認し、そのテーブル内のボタンをクリックしたい場合があります。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');
});
});
Waiting for Elements
JavaScriptを広範に使用するアプリケーションをテストする際には、特定の要素やデータが利用可能になるまで「待つ」必要があることがよくあります。Duskはこれを簡単にします。さまざまなメソッドを使用して、要素がページに表示されるのを待ったり、特定のJavaScript式がtrue
に評価されるまで待ったりできます。
Waiting
指定されたミリ秒数だけテストを一時停止する必要がある場合は、pause
メソッドを使用します:
$browser->pause(1000);
指定された条件がtrue
の場合にのみテストを一時停止する必要がある場合は、pauseIf
メソッドを使用します:
$browser->pauseIf(App::environment('production'), 1000);
同様に、指定された条件がtrue
でない限りテストを一時停止する必要がある場合は、pauseUnless
メソッドを使用します:
$browser->pauseUnless(App::environment('testing'), 1000);
Waiting for Selectors
``````php
// 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);
Scoping Selectors When Available
時には、指定されたセレクタに一致する要素が表示されるのを待ってから、その要素と対話したい場合があります。たとえば、モーダルウィンドウが利用可能になるまで待ってから、モーダル内の「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');
利用可能なアサーション
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
ページタイトルが指定されたテキストと一致することを確認します:
$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');
assertHasCookie
指定された暗号化されたクッキーが存在することを確認します:
$browser->assertHasCookie($name);
assertHasPlainCookie
指定された暗号化されていないクッキーが存在することを確認します:
$browser->assertHasPlainCookie($name);
assertCookieMissing
指定された暗号化されたクッキーが存在しないことを確認します:
$browser->assertCookieMissing($name);
assertPlainCookieMissing
指定された暗号化されていないクッキーが存在しないことを確認します:
$browser->assertPlainCookieMissing($name);
assertCookieValue
暗号化されたクッキーが指定された値を持つことを確認します:
$browser->assertCookieValue($name, $value);
assertPlainCookieValue
暗号化されていないクッキーが指定された値を持つことを確認します:
$browser->assertPlainCookieValue($name, $value);
assertSee
指定されたテキストがページに存在することを確認します:
$browser->assertSee($text);
assertDontSee
指定されたテキストがページに存在しないことを確認します:
$browser->assertDontSee($text);
assertSeeIn
指定されたテキストがセレクタ内に存在することを確認します:
$browser->assertSeeIn($selector, $text);
assertDontSeeIn
指定されたテキストがセレクタ内に存在しないことを確認します:
$browser->assertDontSeeIn($selector, $text);
assertSeeAnythingIn
任意のテキストがセレクタ内に存在することを確認します:
$browser->assertSeeAnythingIn($selector);
assertSeeNothingIn
セレクタ内にテキストが存在しないことを確認します:
$browser->assertSeeNothingIn($selector);
assertScript
指定されたJavaScript式が指定された値に評価されることを確認します:
$browser->assertScript('window.isLoaded')
->assertScript('document.readyState', 'complete');
assertSourceHas
指定されたソースコードがページに存在することを確認します:
$browser->assertSourceHas($code);
assertSourceMissing
指定されたソースコードがページに存在しないことを確認します:
$browser->assertSourceMissing($code);
assertSeeLink
指定されたリンクがページに存在することを確認します:
$browser->assertSeeLink($linkText);
assertDontSeeLink
指定されたリンクがページに存在しないことを確認します:
$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 ページを使用すると、特定のページで実行できる表現力豊かなアクションを定義できます。ページは、アプリケーションや単一のページの一般的なセレクタへのショートカットを定義することもできます。
ページの生成
ページオブジェクトを生成するには、dusk:page
Artisan コマンドを実行します。すべてのページオブジェクトは、アプリケーションの tests/Browser/Pages
ディレクトリに配置されます:
php artisan dusk:page Login
ページの設定
デフォルトでは、ページには url
、assert
、および 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', '');
グローバルショートハンドセレクタ
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');
});
}
}
継続的インテグレーション
ほとんどのDusk継続的インテグレーション構成は、ポート8000で組み込みのPHP開発サーバーを使用してLaravelアプリケーションが提供されることを期待しています。したがって、続行する前に、継続的インテグレーション環境に 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
# ビルド環境にChromeを含める
services:
- dusk
# すべてのコミットをビルド
on:
push:
branches: .*
pipeline:
- name: Setup
cmd: |
cp -v .env.example .env
composer install --no-interaction --prefer-dist --optimize-autoloader
php artisan key:generate
# Dusk envファイルを作成し、APP_URLが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 \u0026
sleep 2
php artisan dusk:chrome-driver $CHROME_DRIVER
php artisan dusk --env=ci
DuskテストをChipper CIで実行する方法、データベースの使用方法については、公式Chipper CIドキュメントを参照してください。