Laravel 8.x Laravel Dusk

イントロダクション

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

インストール

使い始めるには、Google Chromeをインストールして、プロジェクトにLaravel/Dusk Composer依存パッケージを追加する必要があります。

composer require --dev laravel/dusk

Note: 本番環境にDuskをインストールしてはいけません。インストールすると、アプリケーションに対する未認証でのアクセスを許すようになります。

Duskパッケージをインストールし終えたら、dusk:install Artisanコマンドを実行します。dusk:installコマンドは、tests/BrowserディレクトリとサンプルのDuskテストを作成します。

php artisan dusk:install

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

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

ChromeDriverインストールの管理

Laravel Duskにデフォルトで含まれるChromeDriverとは別のバージョンをインストールしたい場合は、dusk:chrome-driverコマンドが使用できます。

# OSに合う、最新バージョンのChromeDriverのインストール
php artisan dusk:chrome-driver

# OSに合う、指定バージョンのChromeDriverのインストール
php artisan dusk:chrome-driver 86

# 全OSをサポートしている、指定バージョンのChromeDriverのインストール
php artisan dusk:chrome-driver --all

# OSに合わせ検出したChrome/Chromiumのバージョンと一致するバージョンのChromeDriverをインストール
php artisan dusk:chrome-driver --detect

Note: Dusk実行には、実行可能なchromedriverバイナリが必要です。Dusk実行時に問題がある場合は、このバイナリを実行可能に確実にするために、chmod -R 0755 vendor/laravel/dusk/binコマンドを実行してみてください。

他ブラウザの使用

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

開始するには、アプリケーションのベースDuskテストケースである、tests/DuskTestCase.phpファイルを開きます。このファイルの中の、startChromeDriverメソッド呼び出しを削除してください。これにより、ChromeDriverの自動起動を停止します。

/**
 * Duskテスト実行準備
 *
 * @beforeClass
 * @return void
 */
public static function prepare()
{
    // static::startChromeDriver();
}

次に、皆さんが選んだURLとポートへ接続するために、driverメソッドを変更します。WebDriverに渡すべき、"desired capabilities"を更新することもできます。

/**
 * RemoteWebDriverインスタンスの生成
 *
 * @return \Facebook\WebDriver\Remote\RemoteWebDriver
 */
protected function driver()
{
    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トレイトを使用してください。これにより、テストごとにデータベースが再マイグレーションされます。

<?php

namespace Tests\Browser;

use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;

class ExampleTest extends DuskTestCase
{
    use DatabaseMigrations;
}

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

テストの実行

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

php artisan dusk

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

php artisan dusk:fails

duskコマンドは、特定のグループのテストのみを実行できるようにするなど、PHPUnitテストランナーが通常受け付ける引数を全て受け入れます。

php artisan dusk --group=foo

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

ChromeDriverの手動起動

デフォルトのDuskは、ChromeDriverを自動的に起動しようとします。特定のシステムで自動起動しない場合は、duskコマンドを実行する前に手動でChromeDriverを起動することもできます。ChromeDriverを手動起動する場合は、tests/DuskTestCase.phpファイルの以下の行をコメントアウトしてください。

/**
 * Duskテスト実行準備
 *
 * @beforeClass
 * @return void
 */
public static function prepare()
{
    // static::startChromeDriver();
}

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

/**
 * RemoteWebDriverインスタンスの生成
 *
 * @return \Facebook\WebDriver\Remote\RemoteWebDriver
 */
protected function driver()
{
    return RemoteWebDriver::create(
        'http://localhost:9515', DesiredCapabilities::chrome()
    );
}

環境の処理

テスト実行時に独自の環境ファイルを強制的に使用させるには、プロジェクトのルートに.env.dusk.{environment}ファイルを作成します。たとえば、local環境からduskコマンドを起動する場合は、.env.dusk.localファイルを作成します。

テストを実行すると、Duskは.envファイルをバックアップし、皆さんのDusk環境を.envへリネームします。テストが完了したら、.envファイルをリストアします。

ブラウザの基本

ブラウザの生成

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

<?php

namespace Tests\Browser;

use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;

class ExampleTest extends DuskTestCase
{
    use DatabaseMigrations;

    /**
     * 基本的なブラウザテスト例
     *
     * @return void
     */
    public function test_basic_example()
    {
        $user = User::factory()->create([
            'email' => 'taylor@laravel.com',
        ]);

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

上記の例のように、browseメソッドはクロージャを引数に取ります。ブラウザインスタンスは、Duskによってこのクロージャに自動的に渡され、アプリケーションを操作し、アサーションを作成するために使用するメインオブジェクトです。

複数のブラウザの作成

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

$this->browse(function ($first, $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('login');

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
{
    /**
     * Duskのブラウザマクロを登録
     *
     * @return void
     */
    public function boot()
    {
        Browser::macro('scrollToElement', function ($element = null) {
            $this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);");

            return $this;
        });
    }
}

macro関数は、最初の引数に名前を取り、2番目にクロージャを取ります。マクロのクロージャは、Browserインスタンスのメソッドとしてマクロを呼び出したときに実行します。

$this->browse(function ($browser) use ($user) {
    $browser->visit('/pay')
            ->scrollToElement('#credit-card-details')
            ->assertSee('Enter Credit Card Details');
});

認証

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

use App\Models\User;

$this->browse(function ($browser) {
    $browser->loginAs(User::find(1))
          ->visit('/home');
});

Note: loginAsメソッドを使用した後、ファイル内のすべてのテストでユーザーセッションを維持します。

クッキー

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

$browser->cookie('name');

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

暗号化していないクッキーの値を取得/セットするには、plainCookieメソッドを使います。

$browser->plainCookie('name');

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

指定クッキーを削除するには、deleteCookieメソッドを使います。

$browser->deleteCookie('name');

JavaScriptの実行

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

$output = $browser->script('document.documentElement.scrollTop = 0');

$output = $browser->script([
    'document.body.scrollTop = 0',
    'document.documentElement.scrollTop = 0',
]);

スクリーンショットの取得

スクリーンショットを取るには、screenshotメソッドを使います。指定したファイル名で保存されます。スクリーンショットはすべて、tests/Browser/screenshotsディレクトリへ保存します。

$browser->screenshot('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は、ページ上の要素の現在の値、表示テキスト、属性を操作するための方法をいくつか提供します。たとえば、特定のCSSまたはDuskセレクタに一致する要素の「値」を取得するには、valueメソッドを使用します。

// 値の取得
$value = $browser->value('selector');

// 値の設定
$browser->value('selector', 'value');

指定したフィールド名を持つインプット要素の「値」を取得するには、inputValueメソッドを使ってください。

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

テキストの取得

textメソッドは、指定したセレクタに一致する要素の表示テキストを取得します。

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

属性の取得

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

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

フォーム操作

値のタイプ

Duskはフォームと入力要素を操作する、さまざまなメソッドを提供しています。最初に、入力フィールドへテキストをタイプする例を見てみましょう。

$browser->type('email', 'taylor@laravel.com');

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

コンテンツをクリアせずに、フィールドへテキストを追加するには、appendメソッドを使用します。

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

入力値をクリアするには、clearメソッドを使用します。

$browser->clear('email');

typeSlowlyメソッドによりDuskへゆっくりとタイプするように指示できます。Duskはデフォルトでキー押下間に100ミリ秒の間隔を開けます。このキー押下間の時間をカスタマイズするには、メソッドの第3引数へ適切なミリ秒数を渡してください。

$browser->typeSlowly('mobile', '+1 (202) 555-5555');

$browser->typeSlowly('mobile', '+1 (202) 555-5555', 300);

テキストをゆっくりと追加するため、appendSlowlyメソッドが使用できます。

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

ドロップダウン

select要素で使用可能な値を選択するには、selectメソッドを使用できます。typeメソッドと同様に、selectメソッドは完全なCSSセレクタを必要としません。selectメソッドに値を渡すときは、表示テキストの代わりに基になるオプション値を渡す必要があります。

$browser->select('size', 'Large');

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

$browser->select('size');

selectメソッドの第2引数に配列を指定することで、複数の選択肢を選択するように指定できます。

$browser->select('categories', ['Art', 'Music']);

チェックボックス

チェックボックス入力を「チェック」するには、checkメソッドを使用します。他の多くの入力関連メソッドと同様に、完全なCSSセレクタは必要ありません。CSSセレクタの一致が見つからない場合、Duskは一致するname属性を持つチェックボックスを検索します。

$browser->check('terms');

uncheckメソッドは、チェックボックス入力を「チェック解除」するために使用します。

$browser->uncheck('terms');

ラジオボタン

radio入力オプションを「選択」するには、radioメソッドを使用します。他の多くの入力関連メソッドと同様に、完全なCSSセレクタは必要ありません。CSSセレクタの一致が見つからない場合、Duskは「name」属性と「value」属性が一致する「radio」入力を検索します。

$browser->radio('size', 'large');

ファイルの添付

attachメソッドは、ファイルをfile入力要素に添付するために使用します。他の多くの入力関連メソッドと同様に、完全なCSSセレクタは必要ありません。CSSセレクタの一致が見つからない場合、Duskは一致するname属性を持つfile入力を検索します。

$browser->attach('photo', __DIR__.'/photos/mountains.png');

Note: 添付機能を使用するには、サーバへZip PHP拡張機能をインストールし、有効にする必要があります。

ボタンの押下

pressメソッドを使用して、ページ上のボタン要素をクリックできます。pressメソッドに与えられる最初の引数は、ボタンの表示テキストまたはCSS/Duskセレクタのどちらかです。

$browser->press('Login');

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

// ボタンを押して、有効になるまで最大5秒待つ
$browser->pressAndWaitFor('Save');

// ボタンを押して、有効になるまで最大1秒待つ
$browser->pressAndWaitFor('Save', 1);

リンクのクリック

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

$browser->clickLink($linkText);

seeLinkメソッドを使用して、指定する表示テキストのリンクがページに表示されているかどうかを確認できます。

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

Note: これらのメソッドはjQueryを操作します。jQueryがページで利用できない場合、Duskは自動的にそれをページに挿入して、テストの期間中利用できるようにします。

キーボードの使用

keysメソッドを使用すると、typeメソッドで通常できるより複雑な入力シーケンスを特定の要素に提供できます。たとえば、値を入力するときに修飾キーを押したままにするようにDuskに指示できます。以下の例では、指定したセレクタに一致する要素へtaylorを入力している間、shiftキーが押されます。taylorの入力後、swiftが修飾キーなしで入力されます。

$browser->keys('selector', ['{shift}', 'taylor'], 'swift');

keysメソッドのもう1つの有益な使用例は、アプリケーションのプライマリCSSセレクタに「キーボードショートカット」の組み合わせを送信することです。

$browser->keys('.app', ['{command}', 'j']);

Tip!! {command}など、すべての修飾キーは{}文字でラップし、GitHubで見つかるFacebook\WebDriver\WebDriverKeysクラスで定義された定数です。

マウスの使用

要素のクリック

clickメソッドを使用して、指定したCSSまたはDuskセレクタに一致する要素をクリックできます。

$browser->click('.selector');

clickAtXPathメソッドを使用して、指定したXPath式に一致する要素をクリックできます。

$browser->clickAtXPath('//div[@class = "selector"]');

clickAtPointメソッドを使用して、ブラウザの表示可能領域を基準にした特定の座標ペアで最上位の要素をクリックできます。

$browser->clickAtPoint($x = 0, $y = 0);

doubleClickメソッドを使用して、マウスのダブルクリックをシミュレートできます。

$browser->doubleClick();

rightClickメソッドを使用して、マウスの右クリックをシミュレートできます。

$browser->rightClick();

$browser->rightClick('.selector');

clickAndHoldメソッドを使用して、マウスボタンがクリックされたままにしている状況をシミュレートできます。その後のreleaseMouseメソッドの呼び出しは、この動作を元に戻し、マウスボタンを離します。

$browser->clickAndHold()
        ->pause(1000)
        ->releaseMouse();

マウスオーバ

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

セレクタの範囲指定

特定のセレクタ内のすべての操作をスコープしながら、いくつかの操作を実行したい場合があります。たとえば、一部のテキストがテーブル内にのみ存在することを宣言してから、そのテーブル内のボタンをクリックしたい場合があります。これを実現するには、withメソッドを使用できます。withメソッドに与えられたクロージャ内で実行されるすべての操作は、元のセレクタにスコープされます。

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

現在のスコープ外でアサートを実行する必要がある場合があります。これを実現するには、elsewhereメソッドを使用できます。

 $browser->with('.table', function ($table) {
    // 現在のスコープは`body .table`

    $browser->elsewhere('.page-title', function ($title) {
        // 現在のスコープは`body .page-title`
        $title->assertSee('Hello World');
    });

    $browser->elsewhereWhenAvailable('.page-title', function ($title) {
        // 現在のスコープは`body. page-title`
        $title->assertSee('Hello World');
    });
 });

要素の待機

広範囲に渡りJavaScriptを使用しているアプリケーションのテストでは、テストを進める前に特定の要素やデータが利用可能になるまで、「待つ(wait)」必要がしばしば起きます。Duskではこれも簡単に行えます。数多くのメソッドを使い、ページで要素が見えるようになるまで、もしくはJavaScriptの評価がtrueになるまで待機できます。

待機

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

$browser->pause(1000);

セレクタの待機

waitForメソッドを使用して、指定するCSSまたはDuskセレクタに一致する要素がページに表示されるまでテストの実行を一時停止できます。デフォルトでは、これは例外をスローする前に最大5秒間テストを一時停止します。必要に応じて、メソッドの2番目の引数にカスタムタイムアウトしきい値を渡せます。

// セレクタを最長5秒間待つ
$browser->waitFor('.selector');

// セレクタを最長1秒待つ
$browser->waitFor('.selector', 1);

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

// セレクタが指定テキストを持つまで、最長5秒待つ
$browser->waitForTextIn('.selector', 'Hello World');

// セレクタが指定テキストを持つまで、最長5秒待つ
$browser->waitForTextIn('.selector', 'Hello World', 1);

指定するセレクタに一致する要素がページから無くなるまで待つこともできます。

// セレクタが消えるまで、最長5秒待つ
$browser->waitUntilMissing('.selector');

// セレクタが消えるまで、最長1秒待つ
$browser->waitUntilMissing('.selector', 1);

あるいは、与えられたセレクタにマッチする要素が有効または無効になるまで待つこともできます。

// セレクタが有効になるまで最大5秒待つ
$browser->waitUntilEnabled('.selector');

// セレクタが有効になるまで最大1秒待つ
$browser->waitUntilEnabled('.selector', 1);

// セレクタが無効になるまで最大5秒待つ
$browser->waitUntilDisabled('.selector');

// セレクタが無効になるまで最大1秒待つ
$browser->waitUntilDisabled('.selector', 1);

利用可能時限定のセレクタ

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

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

テキストの待機

指定したテキストがページに表示されるまで待ちたい場合は、waitForTextメソッドを使います。

// テキストを最大5秒間待つ
$browser->waitForText('Hello World');

// テキストを最大1秒待つ
$browser->waitForText('Hello World', 1);

ページに表示されている指定したテキストが削除されるまで待ちたい場合は、waitUntilMissingTextメソッドを使います。

// テキストが削除されるまで最大5秒間待つ
$browser->waitUntilMissingText('Hello World');

// テキストが削除されるまで最大1秒間待つ
$browser->waitUntilMissingText('Hello World', 1);

リンクの待機

ページに指定したリンクテキストが表示されるまで待つ場合は、waitForLinkメソッドを使います。

// リンクを最大5秒間待つ
$browser->waitForLink('Create');

// リンクを最大1秒間待つ
$browser->waitForLink('Create', 1);

ページロケーションの待機

$browser->assertPathIs('/home')のようなパスをアサートするときに、window.location.pathnameが非同期更新中の場合、アサートは失敗するでしょう。指定値のロケーションを待機するために、waitForLocationメソッドを使ってください。

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

waitForLocationメソッドは、現在のウィンドウの場所が完全修飾URLになるまで待機するためにも使用できます。

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

名前付きルートのロケーションを待機することも可能です。

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

ページリロードの待機

ページのリロード後にアサートする必要がある場合は、waitForReloadメソッドを使ってください。

$browser->click('.some-action')
        ->waitForReload()
        ->assertSee('something');

JavaScriptの評価の待機

指定したJavaScript式の評価がtrueになるまで、テストの実行を中断したい場合もときどきあります。waitUntilメソッドで簡単に行えます。このメソッドに式を渡す時に、returnキーワードや最後のセミコロンを含める必要はありません。

// 式がtrueになるまで最大5秒間待つ
$browser->waitUntil('App.data.servers.length > 0');

// 式がtrueになるまで最大1秒間待つ
$browser->waitUntil('App.data.servers.length > 0', 1);

Vue式の待機

waitUntilVueメソッドとwaitUntilVueIsNotメソッドを使用して、Vueコンポーネント属性が指定した値になるまで待機できます。

// コンポーネント属性に指定した値が含まれるまで待つ
$browser->waitUntilVue('user.name', 'Taylor', '@user');

// コンポーネント属性に指定した値が含まれなくなるまで待つ
$browser->waitUntilVueIsNot('user.name', null, '@user');

コールバックによる待機

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

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

要素をスクロールしてビューに表示

要素がブラウザの表示可能領域の外にあるために、要素をクリックできない場合があります。scrollIntoViewメソッドは、指定したセレクタの要素がビュー内に入るまでブラウザウィンドウをスクロールします。

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

使用可能なアサート

Duskはアプリケーションに対する数多くのアサートを提供しています。使用できるアサートを以下のリストにまとめます。

assertTitle

ページタイトルが指定した文字列と一致することを宣言します。

$browser->assertTitle($title);

assertTitleContains

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

$browser->assertTitleContains($title);

assertUrlIs

クエリ文字列を除いた、現在のURLが指定した文字列と一致するのを宣言します。

$browser->assertUrlIs($url);

assertSchemeIs

現在のURLスキームが、指定したスキームと一致することを宣言します。

$browser->assertSchemeIs($scheme);

assertSchemeIsNot

現在のURLスキームが、指定したスキームと一致しないことを宣言します。

$browser->assertSchemeIsNot($scheme);

assertHostIs

現在のURLのホストが、指定したホストと一致することを宣言します。

$browser->assertHostIs($host);

assertHostIsNot

現在のURLのホストが、指定したホストと一致しないことを宣言します。

$browser->assertHostIsNot($host);

assertPortIs

現在のURLポートが、指定したポートと一致することを宣言します。

$browser->assertPortIs($port);

assertPortIsNot

現在のURLポートが、指定したポートと一致しないことを宣言します。

$browser->assertPortIsNot($port);

assertPathBeginsWith

現在のURLパスが指定したパスで始まることを宣言します。

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

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

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

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

指定フィールドが、enabledであることを宣言します。

$browser->assertEnabled($field);

assertDisabled

指定フィールドが、disabledであることを宣言します。

$browser->assertDisabled($field);

assertButtonEnabled

指定したボタンが、enabledであることを宣言します。

$browser->assertButtonEnabled($button);

assertButtonDisabled

指定したボタンが、disabledであることを宣言します。

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

// コンポーネント定義…

Vue.component('profile', {
    template: '<div>{{ user.name }}</div>',

    data: function () {
        return {
            user: {
                name: 'Taylor'
            }
        };
    }
});

次のように、Vueコンポーネントの状態を宣言できます。

/**
 * 基本的なVueテストの例
 *
 * @return void
 */
public function testVue()
{
    $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);

assertVueDoesNotContain

指定したVueコンポーネントのデータプロパティが配列で、指定値を含まないことを宣言します。

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

ページ

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

ページの生成

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

php artisan dusk:page Login

ページの設定

デフォルトでページには、urlassertelementsの3メソッドが用意されています。urlassertメソッドは、この後説明します。elementsメソッドについては、のちほど詳細を紹介します。

urlメソッド

urlメソッドでは、そのページを表すURLのパスを返します。Duskはブラウザでこのページへ移動するとき、このURLを使用します。

/**
 * このページのURL取得
 *
 * @return string
 */
public function url()
{
    return '/login';
}

assertメソッド

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

/**
 * ブラウザがページ上にあることを宣言
 *
 * @return void
 */
public function assert(Browser $browser)
{
    $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"入力フィールドのショートカットを定義しましょう。

/**
 * ページ要素の短縮形を取得
 *
 * @return array
 */
public function elements()
{
    return [
        '@email' => 'input[name=email]',
    ];
}

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

$browser->type('@email', 'taylor@laravel.com');

グローバルなセレクタ簡略記述

Duskをインストールすると、ベースPageクラスがtests/Browser/Pagesディレクトリへ設置されます。このクラスは、アプリケーション全部のどのページからでも利用可能な、グローバル短縮セレクタを定義するsiteElementsメソッドを含んでいます。

/**
 * サイトのグローバル要素短縮形の取得
 *
 * @return array
 */
public static function siteElements()
{
    return [
        '@element' => '#selector',
    ];
}

ページメソッド

ページに対し定義済みのデフォルトメソッドに加え、テスト全体で使用できる追加メソッドも定義できます。たとえば、音楽管理アプリケーションを構築中だと想像してみましょう。アプリケーションのあるページでプレイリストを作成するのは、よくあるアクションです。各テストごとにプレイリスト作成のロジックを書き直す代わりに、ページクラスにcreatePlaylistメソッドを定義できます。

<?php

namespace Tests\Browser\Pages;

use Laravel\Dusk\Browser;

class Dashboard extends Page
{
    // 他のページメソッドの定義…

    /**
     * 新しいプレイリストの作成
     *
     * @param  \Laravel\Dusk\Browser  $browser
     * @param  string  $name
     * @return void
     */
    public function createPlaylist(Browser $browser, $name)
    {
        $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
{
    /**
     * コンポーネントのルートセレクタ取得
     *
     * @return string
     */
    public function selector()
    {
        return '.date-picker';
    }

    /**
     * ブラウザページにそのコンポーネントが含まれていることを宣言
     *
     * @param  Browser  $browser
     * @return void
     */
    public function assert(Browser $browser)
    {
        $browser->assertVisible($this->selector());
    }

    /**
     * コンポーネントの要素のショートカットを取得
     *
     * @return array
     */
    public function elements()
    public function selectDate(Browser $browser, $year, $month, $day)
        return [
            '@date-field' => 'input.datepicker-input',
            '@year-list' => 'div > div.datepicker-years',
            '@month-list' => 'div > div.datepicker-months',
            '@day-list' => 'div > div.datepicker-days',
        ];
    }

    /**
     * 指定日付のセレクト
     *
     * @param  \Laravel\Dusk\Browser  $browser
     * @param  int  $year
     * @param  int  $month
     * @param  int  $day
     * @return void
     */
    public function selectDate(Browser $browser, $year, $month, $day)
    {
        $browser->click('@date-field')
                ->within('@year-list', function ($browser) use ($year) {
                    $browser->click($year);
                })
                ->within('@month-list', function ($browser) use ($month) {
                    $browser->click($month);
                })
                ->within('@day-list', function ($browser) use ($day) {
                    $browser->click($day);
                });
    }
}

コンポーネントの使用

コンポーネントを定義したら、全テスト中からデートピッカーの中の指定日付を簡単にセレクトできます。日付選択で必要なロジックに変更が起きたら、このコンポーネントを更新するだけです。

<?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
{
    /**
     * 基本的なコンポーネントテスト例
     *
     * @return void
     */
    public function testBasicExample()
    {
        $this->browse(function (Browser $browser) {
            $browser->visit('/')
                    ->within(new DatePicker, function ($browser) {
                        $browser->selectDate(2019, 1, 30);
                    })
                    ->assertSee('January');
        });
    }
}

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

Note: ほとんどのDusk継続的インテグレーション設定では、Laravelアプリケーションがポート8000​​の組み込みPHP開発サーバを使用して提供されることを想定しています。したがって、続行する前に、継続的インテグレーション環境のAPP_URL環境変数値を確実にhttp://127.0.0.1:8000に指定してください。

Heroku CI

DuskテストをHeroku CI上で実行するには、Herokuのapp.jsonファイルへ、以下のGoogle Chromeビルドパックとスクリプトを追加してください。

{
  "environments": {
    "test": {
      "buildpacks": [
        { "url": "heroku/php" },
        { "url": "https://github.com/heroku/heroku-buildpack-google-chrome" }
      ],
      "scripts": {
        "test-setup": "cp .env.testing .env",
        "test": "nohup bash -c './vendor/laravel/dusk/bin/chromedriver-linux > /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の組み込みWebサーバを起動するために、php artisan serveを使用する必要もあるでしょう。

language: php

php:
  - 7.3

addons:
  chrome: stable

install:
  - cp .env.testing .env
  - travis_retry composer install --no-interaction --prefer-dist
  - php artisan key:generate
  - php artisan dusk:chrome-driver

before_script:
  - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
  - php artisan serve --no-reload &

script:
  - php artisan dusk

GitHubアクション

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

name: CI
on: [push]
jobs:

  dusk-php:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - 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 `/opt/google/chrome/chrome --version | cut -d " " -f3 | cut -d "." -f1`
      - name: Start Chrome Driver
        run: ./vendor/laravel/dusk/bin/chromedriver-linux &
      - name: Run Laravel Server
        run: php artisan serve --no-reload &
      - name: Run Dusk Tests
        env:
          APP_URL: "http://127.0.0.1:8000"
        run: php artisan dusk
      - name: Upload Screenshots
        if: failure()
        uses: actions/upload-artifact@v2
        with:
          name: screenshots
          path: tests/Browser/screenshots
      - name: Upload Console Logs
        if: failure()
        uses: actions/upload-artifact@v2
        with:
          name: console
          path: tests/Browser/console

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる