Laravel Dusk
はじめに
Laravel Duskは、表現力豊かで使いやすいブラウザ自動化およびテストAPIを提供します。デフォルトでは、DuskはローカルコンピューターにJDKまたはSeleniumをインストールする必要はありません。代わりに、DuskはスタンドアロンのChromeDriverインストールを使用します。ただし、必要に応じて他のSelenium互換ドライバーを自由に使用できます。
インストール
開始するには、Google Chromeをインストールし、laravel/dusk
Composer依存関係をプロジェクトに追加する必要があります。
composer require laravel/dusk --dev
Duskのサービスプロバイダを手動で登録している場合、本番環境で登録することは絶対にしないでください。そうすると、任意のユーザーがアプリケーションで認証できるようになる可能性があります。
Duskパッケージをインストールしたら、dusk:install
Artisanコマンドを実行します。dusk:install
コマンドは、tests/Browser
ディレクトリ、Duskのサンプルテストを作成し、お使いのオペレーティングシステム用のChrome Driverバイナリをインストールします。
php artisan dusk:install
次に、アプリケーションの.env
ファイルにAPP_URL
環境変数を設定します。この値は、ブラウザでアプリケーションにアクセスするために使用するURLと一致する必要があります。
Laravel Sailを使用してローカル開発環境を管理している場合は、Duskテストの設定と実行に関するSailのドキュメントも参照してください。
ChromeDriverのインストール管理
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
Duskには、chromedriver
バイナリが実行可能である必要があります。Duskの実行に問題がある場合は、次のコマンドを使用してバイナリが実行可能であることを確認する必要があります。chmod -R 0755 vendor/laravel/dusk/bin/
。
他のブラウザの使用
デフォルトでは、DuskはGoogle ChromeとスタンドアロンのChromeDriverインストールを使用してブラウザテストを実行します。ただし、独自のSeleniumサーバーを起動して、任意のブラウザに対してテストを実行することもできます。
開始するには、アプリケーションのベースDuskテストケースであるtests/DuskTestCase.php
ファイルを開きます。このファイル内で、startChromeDriver
メソッドの呼び出しを削除できます。これにより、DuskがChromeDriverを自動的に起動しなくなります。
/** * Prepare for Dusk test execution. * * @beforeClass */public static function prepare(): void{ // static::startChromeDriver();}
次に、driver
メソッドを変更して、選択したURLとポートに接続できます。さらに、WebDriverに渡す必要のある「desired capabilities」を変更することもできます。
use Facebook\WebDriver\Remote\RemoteWebDriver; /** * Create the RemoteWebDriver instance. */protected function driver(): RemoteWebDriver{ return RemoteWebDriver::create( 'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs() );}
はじめに
テストの生成
Duskテストを生成するには、dusk:make
Artisanコマンドを使用します。生成されたテストは、tests/Browser
ディレクトリに配置されます。
php artisan dusk:make LoginTest
各テスト後のデータベースのリセット
記述するテストのほとんどは、アプリケーションのデータベースからデータを取得するページとやり取りします。ただし、Duskテストは、RefreshDatabase
トレイトを絶対に使用しないでください。RefreshDatabase
トレイトは、HTTPリクエスト全体で適用できない、または利用できないデータベーストランザクションを利用します。代わりに、DatabaseMigrations
トレイトとDatabaseTruncation
トレイトの2つのオプションがあります。
データベースマイグレーションの使用
DatabaseMigrations
トレイトは、各テストの前にデータベースマイグレーションを実行します。ただし、各テストでデータベーステーブルを削除して再作成するよりも、テーブルを切り捨てる方が通常は高速です。
<?php use Illuminate\Foundation\Testing\DatabaseMigrations;use Laravel\Dusk\Browser; uses(DatabaseMigrations::class); //
<?php namespace Tests\Browser; use Illuminate\Foundation\Testing\DatabaseMigrations;use Laravel\Dusk\Browser;use Tests\DuskTestCase; class ExampleTest extends DuskTestCase{ use DatabaseMigrations; //}
Duskテストの実行時には、SQLiteインメモリデータベースを使用できません。ブラウザは独自のプロセス内で実行されるため、他のプロセスのインメモリデータベースにアクセスできなくなります。
データベース切り捨ての使用
DatabaseTruncation
トレイトは、データベーステーブルが適切に作成されていることを確認するために、最初のテストでデータベースを移行します。ただし、後続のテストでは、データベースのテーブルは単に切り捨てられるだけです。これにより、すべてのデータベースマイグレーションを再実行するよりも高速化されます。
<?php use Illuminate\Foundation\Testing\DatabaseTruncation;use Laravel\Dusk\Browser; uses(DatabaseTruncation::class); //
<?php namespace Tests\Browser; use App\Models\User;use Illuminate\Foundation\Testing\DatabaseTruncation;use Laravel\Dusk\Browser;use Tests\DuskTestCase; class ExampleTest extends DuskTestCase{ use DatabaseTruncation; //}
デフォルトでは、このトレイトはmigrations
テーブルを除くすべてのテーブルを切り捨てます。切り捨てるテーブルをカスタマイズする場合は、テストクラスで$tablesToTruncate
プロパティを定義できます。
Pestを使用している場合は、ベースDuskTestCase
クラス、またはテストファイルが拡張する任意のクラスでプロパティまたはメソッドを定義する必要があります。
/** * Indicates which tables should be truncated. * * @var array */protected $tablesToTruncate = ['users'];
または、テストクラスで$exceptTables
プロパティを定義して、切り捨てから除外するテーブルを指定することもできます。
/** * Indicates which tables should be excluded from truncation. * * @var array */protected $exceptTables = ['users'];
テーブルを切り捨てるデータベース接続を指定するには、テストクラスで$connectionsToTruncate
プロパティを定義できます。
/** * Indicates which connections should have their tables truncated. * * @var array */protected $connectionsToTruncate = ['mysql'];
データベースの切り捨てが実行される前または後にコードを実行する場合は、テストクラスでbeforeTruncatingDatabase
またはafterTruncatingDatabase
メソッドを定義できます。
/** * Perform any work that should take place before the database has started truncating. */protected function beforeTruncatingDatabase(): void{ //} /** * Perform any work that should take place after the database has finished truncating. */protected function afterTruncatingDatabase(): void{ //}
テストの実行
ブラウザテストを実行するには、dusk
Artisanコマンドを実行します。
php artisan dusk
前回dusk
コマンドを実行したときにテストに失敗した場合は、dusk:fails
コマンドを使用して、最初に失敗したテストを再実行することで時間を節約できます。
php artisan dusk:fails
dusk
コマンドは、Pest / PHPUnitテストランナーで通常受け入れられる任意の引数を受け入れます。これにより、特定のグループのテストのみを実行できます。
php artisan dusk --group=foo
Laravel Sailを使用してローカル開発環境を管理している場合は、Duskテストの設定と実行に関するSailのドキュメントを参照してください。
ChromeDriverの手動起動
デフォルトでは、Duskは自動的にChromeDriverの起動を試みます。もし、特定のシステムでこれがうまくいかない場合は、dusk
コマンドを実行する前に手動でChromeDriverを起動することができます。手動でChromeDriverを起動する場合、tests/DuskTestCase.php
ファイルの以下の行をコメントアウトする必要があります。
/** * Prepare for Dusk test execution. * * @beforeClass */public static function prepare(): void{ // static::startChromeDriver();}
さらに、ChromeDriverを9515以外のポートで起動する場合は、同じクラスのdriver
メソッドを修正して、正しいポートを反映させる必要があります。
use Facebook\WebDriver\Remote\RemoteWebDriver; /** * Create the RemoteWebDriver instance. */protected function driver(): RemoteWebDriver{ return RemoteWebDriver::create( 'http://localhost:9515', DesiredCapabilities::chrome() );}
環境の処理
テスト実行時にDuskに独自環境ファイルを使用させるには、プロジェクトのルートに.env.dusk.{environment}
ファイルを作成します。たとえば、local
環境からdusk
コマンドを開始する場合は、.env.dusk.local
ファイルを作成する必要があります。
テストを実行すると、Duskは.env
ファイルのバックアップを取り、Dusk環境を.env
にリネームします。テストが完了すると、.env
ファイルは復元されます。
ブラウザの基本
ブラウザの作成
まず、アプリケーションにログインできることを検証するテストを書いてみましょう。テストを生成した後、ログインページに移動し、いくつかの資格情報を入力して、「ログイン」ボタンをクリックするように変更できます。ブラウザインスタンスを作成するには、Duskテスト内からbrowse
メソッドを呼び出すことができます。
<?php use App\Models\User;use Illuminate\Foundation\Testing\DatabaseMigrations;use Laravel\Dusk\Browser; uses(DatabaseMigrations::class); test('basic example', function () { $user = User::factory()->create([ ]); $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([ ]); $this->browse(function (Browser $browser) use ($user) { $browser->visit('/login') ->type('email', $user->email) ->type('password', 'password') ->press('Login') ->assertPathIs('/home'); }); }}
上記の例でわかるように、browse
メソッドはクロージャを受け入れます。ブラウザインスタンスはDuskによってこのクロージャに自動的に渡され、アプリケーションとの対話やアサーションを行うための主要なオブジェクトとなります。
複数のブラウザを作成する
テストを適切に実行するために、複数のブラウザが必要になる場合があります。たとえば、Websocketと対話するチャット画面をテストするには、複数のブラウザが必要になる場合があります。複数のブラウザを作成するには、browse
メソッドに渡されるクロージャのシグネチャに、さらにブラウザ引数を追加するだけです。
$this->browse(function (Browser $first, Browser $second) { $first->loginAs(User::find(1)) ->visit('/home') ->waitForText('Message'); $second->loginAs(User::find(2)) ->visit('/home') ->waitForText('Message') ->type('message', 'Hey Taylor') ->press('Send'); $first->waitForText('Hey Taylor') ->assertSee('Jeffrey Way');});
ナビゲーション
visit
メソッドを使用して、アプリケーション内の指定されたURIに移動できます。
$browser->visit('/login');
visitRoute
メソッドを使用して、名前付きルートに移動できます。
$browser->visitRoute($routeName, $parameters);
back
およびforward
メソッドを使用して、「戻る」および「進む」ナビゲーションができます。
$browser->back(); $browser->forward();
refresh
メソッドを使用して、ページをリフレッシュできます。
$browser->refresh();
ブラウザウィンドウのサイズ変更
resize
メソッドを使用して、ブラウザウィンドウのサイズを調整できます。
$browser->resize(1920, 1080);
maximize
メソッドを使用して、ブラウザウィンドウを最大化できます。
$browser->maximize();
fitContent
メソッドは、ブラウザウィンドウをコンテンツのサイズに合わせてリサイズします。
$browser->fitContent();
テストが失敗すると、Duskは自動的にブラウザをコンテンツに合わせてリサイズしてからスクリーンショットを撮ります。この機能を無効にするには、テスト内でdisableFitOnFailure
メソッドを呼び出すことができます。
$browser->disableFitOnFailure();
move
メソッドを使用して、ブラウザウィンドウを画面上の別の位置に移動できます。
$browser->move($x = 100, $y = 100);
ブラウザマクロ
テストで再利用できるカスタムブラウザメソッドを定義したい場合は、Browser
クラスでmacro
メソッドを使用できます。通常、このメソッドはサービスプロバイダのboot
メソッドから呼び出す必要があります。
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider;use Laravel\Dusk\Browser; class DuskServiceProvider extends ServiceProvider{ /** * Register Dusk's browser macros. */ public function boot(): void { Browser::macro('scrollToElement', function (string $element = null) { $this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);"); return $this; }); }}
macro
関数は、最初の引数として名前、2番目の引数としてクロージャを受け入れます。マクロのクロージャは、Browser
インスタンスでメソッドとしてマクロを呼び出すときに実行されます。
$this->browse(function (Browser $browser) use ($user) { $browser->visit('/pay') ->scrollToElement('#credit-card-details') ->assertSee('Enter Credit Card Details');});
認証
多くの場合、認証を必要とするページをテストします。DuskのloginAs
メソッドを使用すると、すべてのテストでアプリケーションのログイン画面を操作する必要がなくなります。loginAs
メソッドは、認証可能なモデルに関連付けられた主キーまたは認証可能なモデルインスタンスを受け入れます。
use App\Models\User;use Laravel\Dusk\Browser; $this->browse(function (Browser $browser) { $browser->loginAs(User::find(1)) ->visit('/home');});
loginAs
メソッドを使用すると、ファイル内のすべてのテストでユーザーセッションが維持されます。
Cookie
cookie
メソッドを使用して、暗号化されたクッキーの値を取得または設定できます。デフォルトでは、Laravelによって作成されたすべてのクッキーは暗号化されています。
$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
メソッドでカスタマイズできます。通常、このメソッドはアプリケーションのAppServiceProvider
のboot
メソッドから呼び出す必要があります。
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には、フォームと入力要素を操作するためのさまざまなメソッドが用意されています。まず、入力フィールドにテキストを入力する例を見てみましょう。
メソッドは必要に応じて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');
attach関数には、サーバーにインストールおよび有効になっているZip
PHP拡張機能が必要です。
ボタンを押す
press
メソッドを使用して、ページ上のボタン要素をクリックできます。press
メソッドに渡される引数は、ボタンの表示テキストまたはCSS / Duskセレクターのいずれかになります。
$browser->press('Login');
フォームを送信する場合、多くのアプリケーションでは、フォームが押された後にフォームの送信ボタンを無効にし、フォーム送信のHTTPリクエストが完了するとボタンを再度有効にします。ボタンを押して、ボタンが再度有効になるのを待つには、pressAndWaitFor
メソッドを使用できます。
// Press the button and wait a maximum of 5 seconds for it to be enabled...$browser->pressAndWaitFor('Save'); // Press the button and wait a maximum of 1 second for it to be enabled...$browser->pressAndWaitFor('Save', 1);
リンクをクリックする
リンクをクリックするには、ブラウザインスタンスでclickLink
メソッドを使用できます。clickLink
メソッドは、指定された表示テキストを持つリンクをクリックします。
$browser->clickLink($linkText);
seeLink
メソッドを使用して、指定された表示テキストを持つリンクがページに表示されているかどうかを確認できます。
if ($browser->seeLink($linkText)) { // ...}
これらのメソッドはjQueryと対話します。ページでjQueryが利用できない場合、Duskはテスト期間中に利用できるように、自動的にページにjQueryを挿入します。
キーボードの使用
keys
メソッドを使用すると、通常type
メソッドで許可されているよりも複雑な入力シーケンスを、指定された要素に提供できます。たとえば、値を入力中に修飾キーを押したままにするようにDuskに指示できます。この例では、指定されたセレクターに一致する要素にtaylor
が入力されている間、shift
キーが押されたままになります。taylor
が入力された後、修飾キーなしでswift
が入力されます。
$browser->keys('selector', ['{shift}', 'taylor'], 'swift');
keys
メソッドのもう1つの貴重なユースケースは、アプリケーションのプライマリCSSセレクターに「キーボードショートカット」の組み合わせを送信することです。
$browser->keys('.app', ['{command}', 'j']);
{command}
などのすべての修飾キーは{}
文字で囲まれ、Facebook\WebDriver\WebDriverKeys
クラスで定義された定数と一致します。これは、GitHubで確認できます。
Fluentキーボード操作
Duskは、Laravel\Dusk\Keyboard
クラスを介して複雑なキーボード操作を流暢に実行できるwithKeyboard
メソッドも提供します。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
クラスが提供する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 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
指定された暗号化されたCookieが存在することをアサートします。
$browser->assertHasCookie($name);
assertHasPlainCookie
指定された暗号化されていないCookieが存在することをアサートします。
$browser->assertHasPlainCookie($name);
assertCookieMissing
指定された暗号化されたCookieが存在しないことをアサートします。
$browser->assertCookieMissing($name);
assertPlainCookieMissing
指定された暗号化されていないCookieが存在しないことをアサートします。
$browser->assertPlainCookieMissing($name);
assertCookieValue
暗号化されたCookieが指定された値を持っていることをアサートします。
$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 ページを使用すると、1 つのメソッドで特定のページで実行できる表現力豊かなアクションを定義できます。また、ページを使用すると、アプリケーションまたは単一のページに対する一般的なセレクターへのショートカットを定義できます。
ページの生成
ページオブジェクトを生成するには、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 セレクターに対する簡単で覚えやすいショートカットを定義できます。例えば、アプリケーションのログインページの「email」入力フィールドのショートカットを定義してみましょう。
/** * Get the element shortcuts for the page. * * @return array<string, string> */public function elements(): array{ return [ '@email' => 'input[name=email]', ];}
ショートカットが定義されたら、通常は完全な CSS セレクターを使用する場所であればどこでも、ショートカットセレクターを使用できます。
グローバルショートカットセレクター
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 継続的インテグレーション構成では、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: CIon: [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.ymlversion: 1 environment: php: 8.2 node: 16 # Include Chrome in the build environmentservices: - dusk # Build all commitson: 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 ドキュメントを参照してください。