国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

瀏覽器測(cè)試 Dusk

瀏覽器測(cè)試 Dusk


Browser Tests (Laravel Dusk)

介紹

Laravel Dusk 提供了富有表現(xiàn)力、簡單易用的瀏覽器自動(dòng)化及測(cè)試 API 。默認(rèn)情況下,Dusk 不需要在你的機(jī)器上安裝 JDK 或者 Selenium 。而是需要使用單獨(dú)的 ChromeDriver 進(jìn)行安裝。當(dāng)然,你也可以自由使用其他的兼容 Selenium 的驅(qū)動(dòng)程序。

安裝

你應(yīng)該先向你的 Composer 添加 laravel/dusk 依賴 :

composer require --dev laravel/dusk

{note} 如果你是手動(dòng)注冊(cè) Dusk 服務(wù)提供者,一定 不能 在你的生產(chǎn)環(huán)境中注冊(cè),這樣可能會(huì)導(dǎo)致一些不守規(guī)矩的用戶擁有控制你應(yīng)用的權(quán)限。

安裝好 Dusk 包后,運(yùn)行 dusk:install 命令:

php artisan dusk:install

Browser 目錄將會(huì)在 tests 目錄下被創(chuàng)建,并且包含一個(gè)測(cè)試用例。接下來,在你的 .env 文件中設(shè)置 APP_URL 變量。這個(gè)值應(yīng)該與你在瀏覽器中打開本應(yīng)用的 URL 匹配。

要運(yùn)行測(cè)試,使用 dusk 命令。 dusk 命令可以使用與 phpunit 命令同樣的參數(shù):

php artisan dusk

如果上次運(yùn)行  dusk 命令時(shí)測(cè)試失敗,則可以通過使用 dusk:fails 命令重新運(yùn)行失敗的測(cè)試來節(jié)省時(shí)間:

php artisan dusk:fails

{注意} Dusk 要求  ChromeDriver 二進(jìn)制文件是可執(zhí)行的。如果在 Dusk 運(yùn)行時(shí)遇到問題,可以使用以下命令確保二進(jìn)制文件是可執(zhí)行的:chmod -R 0755 vendor/laravel/dusk/bin。

使用其他瀏覽器

默認(rèn)情況下, Dusk 使用 Google Chrome 瀏覽器和一個(gè)單獨(dú)的 ChromeDriver 的安裝來運(yùn)行你的瀏覽器測(cè)試。當(dāng)然,你可以運(yùn)行你自己的 Selenium 服務(wù),用任何你想用的瀏覽器來進(jìn)行測(cè)試。

如果要這么做,打開 tests/DuskTestCase.php 文件,這個(gè)是應(yīng)用測(cè)試用例的基類。在這個(gè)文件中,你可以移除對(duì) startChromeDriver 方法的調(diào)用。這樣 Dusk 就不會(huì)自動(dòng)啟動(dòng) ChromeDriver 了。

/**
 * 準(zhǔn)備執(zhí)行 Dusk 測(cè)試。
 *
 * @beforeClass
 * @return void
 */
 public static function prepare(){ 
    // static::startChromeDriver();
   }

然后,你可以修改 driver 方法來連接到你選定的 URL 和端口。此外,你可以修改 「desired capabilities」(期望能力),它將會(huì)被傳遞給 WebDriver:

/**
 * 創(chuàng)建 RemoteWebDriver 實(shí)例。
 *
 * @return \Facebook\WebDriver\Remote\RemoteWebDriver
 */
 protected function driver(){
     return RemoteWebDriver::create(   
          'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()    
       );
    }

開始使用

創(chuàng)建測(cè)試

要?jiǎng)?chuàng)建一個(gè) Dusk 測(cè)試,使用 dusk:make 命令。創(chuàng)建的測(cè)試將會(huì)被放在 tests/Browser 目錄:

php artisan dusk:make LoginTest

運(yùn)行測(cè)試

使用 dusk 命令來運(yùn)行你的瀏覽器測(cè)試:

php artisan dusk

如果上次運(yùn)行  dusk 命令時(shí)測(cè)試失敗,則可以通過使用 dusk:fails 命令重新運(yùn)行失敗的測(cè)試來節(jié)省時(shí)間:

php artisan dusk:fails

dusk 命令接受任何能讓 PHPUnit 正常運(yùn)行的參數(shù)。例如,讓你可以在指定 group 中運(yùn)行測(cè)試:

php artisan dusk --group=foo

手動(dòng)運(yùn)行 ChromeDriver

默認(rèn)情況下,Dusk 會(huì)嘗試自動(dòng)運(yùn)行 ChromeDriver。如果你在特定的系統(tǒng)中不能運(yùn)行,可以在運(yùn)行 dusk 命令前通過手動(dòng)的方式來運(yùn)行 ChromeDriver。 如果你選擇手動(dòng)運(yùn)行 ChromeDriver,你需要在你的 tests/DuskTestCase.php 文件中注釋掉下面這一行:

/**
 * 為 Dusk 測(cè)試做準(zhǔn)備。
 *
 * @beforeClass
 * @return void
 */
 public static function prepare(){ 
    // static::startChromeDriver();
 }

另外,如果你的 ChromeDriver 運(yùn)行在非 9515 端口 ,你需要修改同一個(gè)類中的 driver 方法:

/**
 * 創(chuàng)建 RemoteWebDriver 實(shí)例。
 *
 * @return \Facebook\WebDriver\Remote\RemoteWebDriver
 */
 protected function driver(){ 
    return RemoteWebDriver::create( 
           'http://localhost:9515', DesiredCapabilities::chrome()   
       );
   }

環(huán)境處理

為了讓 Dusk 使用自己的環(huán)境文件來運(yùn)行測(cè)試,你需要在項(xiàng)目根目錄創(chuàng)建一個(gè) .env.dusk.{environment} 文件。簡單的說,如果你想用 local 環(huán)境來運(yùn)行 dusk 命令,你需要?jiǎng)?chuàng)建一個(gè) .env.dusk.local 文件。

運(yùn)行測(cè)試的時(shí)候,Dusk 會(huì)備份你的 .env 文件并且重命名你的 Dusk 環(huán)境文件為 .env。當(dāng)測(cè)試結(jié)束后,它會(huì)恢復(fù)你的 .env 文件。

創(chuàng)建瀏覽器

讓我們先來寫一個(gè)測(cè)試用例,這個(gè)例子可以驗(yàn)證我們是否能夠登錄系統(tǒng)。生成測(cè)試?yán)又?,我們可以修改它并讓它可以跳轉(zhuǎn)到登錄界面,輸入登錄信息之后,點(diǎn)擊「登錄」按鈕。我們通過 browse 方法來創(chuàng)建一個(gè)瀏覽器實(shí)例:

<?php
    namespace Tests\Browser;
    use App\User;use Tests\DuskTestCase;
    use Laravel\Dusk\Chrome;
    use Illuminate\Foundation\Testing\DatabaseMigrations;
    class ExampleTest extends DuskTestCase{ 
       use DatabaseMigrations;    
      /**
     * 一個(gè)基本的瀏覽器測(cè)試?yán)印?     *
     * @return void
     */   
      public function testBasicExample()  
        {     
           $user = factory(User::class)->create([          
             'email' => 'taylor@laravel.com',      
           ]);        
           $this->browse(function ($browser) use ($user) {      
                 $browser->visit('/login')               
                      ->type('email', $user->email)                    
                      ->type('password', 'secret')                    
                      ->press('Login')                    
                      ->assertPathIs('/home');      
                    });   
           }
       }

在上面的例子中,browse 方法接收了一個(gè)回調(diào)參數(shù)。Dusk 會(huì)自動(dòng)將這個(gè)瀏覽器實(shí)例注入到回調(diào)過程中,而且這個(gè)瀏覽器實(shí)例可以和你的應(yīng)用進(jìn)行交互和斷言。

{tip} 這個(gè)測(cè)試?yán)涌梢杂脕頊y(cè)試 make:auth 命令生成的登錄界面。

創(chuàng)建多個(gè)瀏覽器

有時(shí)候你可能需要多個(gè)瀏覽器才能正確的進(jìn)行測(cè)試。例如,使用多個(gè)瀏覽器測(cè)試通過 websockets 進(jìn)行通訊的在線聊天頁面。想要?jiǎng)?chuàng)建多個(gè)瀏覽器,需要在 browse 方法的回調(diào)中,用名字來區(qū)分瀏覽器實(shí)例,然后傳給回調(diào)去「申請(qǐng)」多個(gè)瀏覽器實(shí)例:

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

改變?yōu)g覽器窗口大小

你可以使用 resize 方法去調(diào)整瀏覽器的窗口大?。?/p>

$browser->resize(1920, 1080);

maximize 方法可以將瀏覽器窗口最大化:

$browser->maximize();

瀏覽器宏

如果你想定義一個(gè)可以在各種測(cè)試中重復(fù)使用的自定義瀏覽器方法,可以在 Browser 類中使用 macro 方法。通常,你應(yīng)該從 服務(wù)提供者 的 boot 方法中調(diào)用它:

<?php
    namespace App\Providers;
    use Laravel\Dusk\Browser;
    use Illuminate\Support\ServiceProvider;
    class DuskServiceProvider extends ServiceProvider{  
      /**
     * 注冊(cè)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 方法接收一個(gè)名稱作為第一個(gè)參數(shù),第二個(gè)參數(shù)則是一個(gè)閉包。 當(dāng)調(diào)用瀏覽器宏作為一個(gè) Browser 的實(shí)現(xiàn)的方法時(shí),瀏覽器宏的閉包將會(huì)執(zhí)行:

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

認(rèn)證

你可能經(jīng)常會(huì)測(cè)試一些需要認(rèn)證的頁面。你可以使用 Dusk 的 loginAs 方法來避免每個(gè)測(cè)試都去登陸頁面登陸一次。 loginAs 可以使用用戶 ID 或者用戶模型實(shí)例:

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

{note} 使用 loginAs 方法后,該用戶的 session 將會(huì)持久化的供其他測(cè)試用例使用。

數(shù)據(jù)庫遷移

就像上面的認(rèn)證例子一樣,當(dāng)你的測(cè)試用例需要遷移的時(shí)候,你不應(yīng)該使用 RefreshDatabase trait。 RefreshDatabase trait 使用了不適用于 HTTP 請(qǐng)求的數(shù)據(jù)庫事務(wù)。取而代之,我們要用 DatabaseMigrations trait:

<?php
    namespace Tests\Browser;
    use App\User;
    use Tests\DuskTestCase;
    use Laravel\Dusk\Chrome;
    use Illuminate\Foundation\Testing\DatabaseMigrations;
    class ExampleTest extends DuskTestCase{
        use DatabaseMigrations;
    }

與元素交互

Dusk 選擇器

選擇一個(gè)好的 CSS 選擇器用于元素交互是編寫 Dush 測(cè)試最困難的部分之一。隨著時(shí)間推移,前端的更改可能會(huì)導(dǎo)致類似以下的 CSS 選擇器中斷測(cè)試:

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

Dusk 選擇器讓你專注于編寫有效的測(cè)試,而不是去記憶 CSS 選擇器。要定義一個(gè)選擇器,只需在你的 HTML 元素中添加一個(gè) dusk 屬性。然后,在選擇器前面添加 @ 去操作 Dusk 測(cè)試中的附加元素:

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

點(diǎn)擊鏈接

要點(diǎn)擊鏈接的話,你可以在瀏覽器實(shí)例上使用 clickLink 方法。clickLink 方法將會(huì)點(diǎn)擊指定顯示文本的鏈接:

$browser->clickLink($linkText);

{注意} 這個(gè)方法可以與 jQuery 進(jìn)行交互。如果頁面上沒有 jQuery,Dusk 會(huì)自動(dòng)將其注入頁面,保證在測(cè)試的期間可用。

文本、值 & 屬性

檢索和設(shè)置值

Dusk 提供了幾種與當(dāng)前顯示文本,值和屬性進(jìn)行交互的方法。例如,要獲取與指定選擇器匹配的元素的「值」,請(qǐng)使用 value 方法:

// 檢索值...
$value = $browser->value('selector');
// 設(shè)置值...
$browser->value('selector', 'value');

檢索文本

text 這個(gè)方法可以用來匹配指定選擇器中元素的顯示文本:

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

檢索屬性

最后,attribute 這個(gè)方法 可以用來匹配指定選擇器中元素的屬性:

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

表單的使用

輸入值

Dusk 提供了與表單和 input 元素交互的各種方法。首先讓我們看一個(gè)在 input 框中輸入文本的例子:

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

注意, 雖然 type 方法可以傳遞 CSS 選擇器做為一個(gè)參數(shù),但這并不是強(qiáng)制要求的。如果沒有提供 CSS 選擇器, Dusk 會(huì)搜索與 name 屬性相同的 input 。如果還是沒有找到,Dusk 會(huì)嘗試查找傳入值與  name  屬性相同的 textarea 。

要想將文本附加到一個(gè)字段之后而且不清除其內(nèi)容, 你可以使用 append 方法:

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

你可以使用 clear 方法清除輸入值:

$browser->clear('email');

下拉菜單

需要在下拉菜單中選擇值,你可以使用 select 方法。 類似于  type  方法, select 方法并不是一定要傳入 CSS 選擇器。 當(dāng)使用 select 方法時(shí),你應(yīng)該傳遞選項(xiàng)實(shí)際的值而不是它的顯示文本:

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

你也可以通過省略第二個(gè)參數(shù)來隨機(jī)選擇一個(gè)選項(xiàng):

$browser->select('size');

復(fù)選框

使用「check」 復(fù)選框時(shí),你可以使用 check 方法。 像其他許多與 input 相關(guān)的方法,并不是必須傳入 CSS 選擇器。 如果準(zhǔn)確的選擇器無法找到的時(shí)候,Dusk 會(huì)搜索能夠與 name 屬性匹配的復(fù)選框:

$browser->check('terms');$browser->uncheck('terms');

單選按鈕

使用 「select」中單選按鈕選項(xiàng)時(shí),你可以使用 radio 這個(gè)方法。 像很多其他的與輸入相關(guān)的方法一樣, 它也并不是必須傳入 CSS 選擇器。如果準(zhǔn)確的選擇器無法被找到的時(shí)候, Dusk 會(huì)搜索能夠與 name 屬性或者 value 屬性相匹配的單選按鈕:

$browser->radio('version', 'php7');

附件

attach 方法可以附加一個(gè)文件到  file  input 元素中。 像很多其他的與輸入相關(guān)的方法一樣,他也并不是必須傳入 CSS 選擇器。如果準(zhǔn)確的選擇器沒有被找到的時(shí)候, Dusk 會(huì)搜索與 name 屬性匹配的文件輸入框:

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

{注意} attach 方法需要使用 PHP Zip  擴(kuò)展,你的服務(wù)器必須安裝了此擴(kuò)展。

使用鍵盤

keys 方法讓你可以再指定元素中輸入比 type 方法更加復(fù)雜的輸入序列。例如,你可以在輸入值的同時(shí)按下按鍵。在這個(gè)例子中,輸入 taylor 時(shí), shift 鍵也同時(shí)被按下。當(dāng) taylor 輸入完之后, 將會(huì)輸入 otwell 而不會(huì)按下任何按鍵:

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

你甚至可以在你的應(yīng)用中選中某個(gè)元素之后按下「快捷鍵」:

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

{提示} 所有包在 {} 中的鍵盤按鍵, 都對(duì)應(yīng)定義于 Facebook\WebDriver\WebDriverKeys 類中,你可以在 GitHub 中找到。

使用鼠標(biāo)

點(diǎn)擊元素

click 方法可用于「點(diǎn)擊」與給定選擇器匹配的元素:

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

鼠標(biāo)懸停

mouseover 方法可用于與給定選擇器匹配的元素的鼠標(biāo)懸停動(dòng)作:

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

拖放

drag 方法用于將與指定選擇器匹配的元素拖到其它元素:

$browser->drag('.from-selector', '.to-selector');

或者,可以在單一方向上拖動(dòng)元素:

$browser->dragLeft('.selector', 10);
$browser->dragRight('.selector', 10);
$browser->dragUp('.selector', 10);
$browser->dragDown('.selector', 10);

JavaScript 對(duì)話框

Dusk 提供了幾種與 JavaScript 對(duì)話框交互的方法:

// 等待對(duì)話框顯示:
$browser->waitForDialog($seconds = null);
// 斷言對(duì)話框已經(jīng)顯示,并且其消息與給定值匹配:
$browser->assertDialogOpened('value');
// 在打開的 JavaScript 提示對(duì)話框中輸入給定值:
$browser->typeInDialog('Hello World');

通過點(diǎn)擊確定按鈕關(guān)閉打開的 JavaScript 對(duì)話框:

$browser->acceptDialog();

通過點(diǎn)擊取消按鈕關(guān)閉打開的 JavaScript 對(duì)話框(僅對(duì)確認(rèn)對(duì)話框有效):

$browser->dismissDialog();

選擇器作用范圍

有時(shí)可能希望在給定的選擇器范圍內(nèi)執(zhí)行多個(gè)操作。比如,可能想要斷言表格中存在某些文本,然后點(diǎn)擊表格中的一個(gè)按鈕??梢允褂?with 方法實(shí)現(xiàn)此需求?;卣{(diào)函數(shù)內(nèi)所有被執(zhí)行的操作都被限定在原始的選擇器上:

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

等待元素

在測(cè)試大面積使用 JavaScript 的應(yīng)用時(shí),在進(jìn)行測(cè)試之前,經(jīng)常需要「等待」指定元素或數(shù)據(jù)可用。Dusk 使之更容易。使用一系列方法,可以等到頁面元素可用,甚至給定的 JavaScript 表達(dá)式執(zhí)行結(jié)果為  true。

等待

如果需要測(cè)試暫停指定的毫秒數(shù),可以使用 pause 方法:

$browser->pause(1000);

等待選擇器

waitFor 方法可以用于暫停執(zhí)行測(cè)試,直到頁面上與給定 CSS 選擇器匹配的元素被顯示。默認(rèn)情況下,將在暫停超過 5 秒后拋出異常。如果有必要,可以傳遞自定義超時(shí)時(shí)長作為其第二個(gè)參數(shù):

// 等待選擇器 5 秒時(shí)間...
$browser->waitFor('.selector');
// 等待選擇器 1 秒時(shí)間...
$browser->waitFor('.selector', 1);

還可以等待指定選擇器從頁面消失:

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

選擇器可用時(shí)限定作用域范圍

偶爾可能希望等待選擇器然后與其互動(dòng)。例如,可能希望等待模態(tài)窗口可用,然后點(diǎn)擊模態(tài)窗口的「確定」按鈕。 whenAvailable 方法能夠用于這種情況。給定回調(diào)內(nèi)的所有要執(zhí)行的元素操作都將被限定在起始選擇器上:

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

等待文本

waitForText 方法可以用于等待頁面上給定文字被顯示:

// 等待指定文本 5 秒時(shí)間...
$browser->waitForText('Hello World');
// 等待指定文本 1 秒時(shí)間...
$browser->waitForText('Hello World', 1);

等待鏈接

waitForLink 方法用于等待給定鏈接文字在頁面上顯示:

// 等待指定鏈接 5 秒時(shí)間...
$browser->waitForLink('Create');
// 等待給定鏈接 2 秒時(shí)間...
$browser->waitForLink('Create', 1);

等待頁面跳轉(zhuǎn)

在給出類似  $browser->assertPathIs('/home') 路徑斷言時(shí),如果 window.location.pathname 被異步更新,斷言就會(huì)失敗??梢允褂?waitForLocation 方法等待頁面跳轉(zhuǎn)到給定路徑:

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

還可以等待被命名的路由跳轉(zhuǎn):

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

等待頁面重新加載

如果要在頁面重新加載后斷言,可以使用 waitForReload 方法:

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

等待 JavaScript 表達(dá)式

有時(shí)會(huì)希望暫停執(zhí)行測(cè)試,直到給定的 JavaScript 表達(dá)式執(zhí)行結(jié)果為  true??梢允褂?waitUntil 方法輕易地達(dá)成此目的。傳送一個(gè)表達(dá)式給此方法,不需要包含 return 關(guān)鍵字或者結(jié)束分號(hào):

//等待表達(dá)式為 true 5 秒時(shí)間...
$browser->waitUntil('App.dataLoaded');
$browser->waitUntil('App.data.servers.length > 0');
// 等待表達(dá)式為 true 1 秒時(shí)間...
$browser->waitUntil('App.data.servers.length > 0', 1);

等待 Vue 表達(dá)式

下面的方法可以用于等待給定的 Vue 組件屬性包含或不包含給定值:

// 等待組件屬性包含給定值...
$browser->waitUntilVue('user.name', 'Taylor', '@user');
// 等待組件屬性不包含給定值...
$browser->waitUntilVueIsNot('user.name', null, '@user');

等待回調(diào)

Dusk 的許多「等待」方法都依賴底層的 waitUsing 方法??梢灾苯邮褂么朔椒▉淼却o定的回調(diào)返回 true。 waitUsing 方法接受等待的最大秒數(shù),閉包執(zhí)行的間隔時(shí)長,被執(zhí)行的閉包,還有可靠的失敗消息:

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

做出 Vue 斷言

Dusk 還允許你對(duì) Vue 組件數(shù)據(jù)的狀態(tài)作出斷言。例如,假設(shè)您的應(yīng)用程序包含以下 Vue 組件:

// HTML...
<profile dusk="profile-component"></profile>
// 定義組件...
Vue.component('profile', {
    template: '<div>{{ user.name }}</div>',
    data: function () { 
               return {
                         user: {
                                  name: 'Taylor' 
                                  }        
                           };    
                      }
              });

你可以在 Vue 組件的狀態(tài)上作出如下斷言:

/**
 * 一個(gè)簡單的 Vue 測(cè)試?yán)印? *
 * @return void
 */
 public function testVue(){ 
    $this->browse(function (Browser $browser) {    
        $browser->visit('/')            
            ->assertVue('user.name', 'Taylor', '@profile-component');  
        });
    }

可用的斷言

Dusk 提供了一系列可用的斷言方法。所有斷言如下:

assertTitle

斷言網(wǎng)頁標(biāo)題匹配指定的文本:

$browser->assertTitle($title);

assertTitleContains

斷言網(wǎng)頁標(biāo)題包含指定的文本:

$browser->assertTitleContains($title);

assertUrlIs

斷言當(dāng)前 URL (不帶查詢字符串) 匹配指定的字符串:

$browser->assertUrlIs($url);

assertSchemeIs

斷言當(dāng)前 URL 匹配與給定的字符串匹配:

$browser->assertSchemeIs($scheme);

assertSchemeIsNot

斷言當(dāng)前 URL 匹配與給定的字符串不匹配:

$browser->assertSchemeIsNot($scheme);

assertHostIs

斷言當(dāng)前 URL 的 host 與給定的值匹配:

$browser->assertHostIs($host);

assertHostIsNot

斷言當(dāng)前 URL 的 host 與給定的值不匹配:

$browser->assertHostIsNot($host);

assertPortIs

斷言當(dāng)前 URL 的端口值與給定的值匹配:

$browser->assertPortIs($port);

assertPortIsNot

斷言當(dāng)前 URL 的端口值與給定的值不匹配:

$browser->assertPortIsNot($port);

assertPathBeginsWith

斷言當(dāng)前 URL 開始于指定的路徑:

$browser->assertPathBeginsWith($path);

assertPathIs

斷言當(dāng)前路徑匹配指定的路徑:

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

assertPathIsNot

斷言當(dāng)前路徑不匹配指定的路徑:

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

assertRouteIs

斷言當(dāng)前 URL 匹配指定的命名路由的 URL:

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

assertQueryStringHas

斷言存在指定的查詢字符串參數(shù):

$browser->assertQueryStringHas($name);

斷言指定的查詢字符串參數(shù)存在,并且該參數(shù)的值為指定的值:

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

assertQueryStringMissing

斷言不存在指定的查詢字符串參數(shù):

$browser->assertQueryStringMissing($name);

assertFragmentIs

斷言目前的分片符合指定的分片:

$browser->assertFragmentIs('anchor');

assertFragmentBeginsWith

斷言目前的分片以指定的分片開頭:

$browser->assertFragmentBeginsWith('anchor');

assertFragmentIsNot

斷言目前的分片不符合指定的分片:

$browser->assertFragmentIsNot('anchor');

assertHasCookie

斷言存在指定的 cookie:

$browser->assertHasCookie($name);

assertCookieMissing

斷言不存在指定的 cookie:

$browser->assertCookieMissing($name);

assertCookieValue

斷言 cookie 存在指定的值:

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

assertPlainCookieValue

斷言未加密的 cookie 存在指定的值:

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

assertSee

斷言當(dāng)前頁存在指定的文本:

$browser->assertSee($text);

assertDontSee

斷言當(dāng)前頁不存在指定的文本:

$browser->assertDontSee($text);

assertSeeIn

斷言選擇器范圍內(nèi)存在指定的文本:

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

assertDontSeeIn

斷言選擇器范圍內(nèi)不存在指定的文本:

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

assertSourceHas

斷言當(dāng)前頁存在指定的源碼:

$browser->assertSourceHas($code);

assertSourceMissing

斷言當(dāng)前頁不存在指定的源碼:

$browser->assertSourceMissing($code);

assertSeeLink

斷言當(dāng)前頁存在指定的鏈接:

$browser->assertSeeLink($linkText);

assertDontSeeLink

斷言當(dāng)前頁不存在指定的鏈接:

$browser->assertDontSeeLink($linkText);

assertInputValue

斷言輸入框存在指定的值:

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

assertInputValueIsNot

斷言輸入框不存在指定的值:

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

assertChecked

斷言指定的復(fù)選框被選中:

$browser->assertChecked($field);

assertNotChecked

斷言指定的復(fù)選框未選中:

$browser->assertNotChecked($field);

assertRadioSelected

斷言指定的單選按鈕被選?。?/p>

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

assertRadioNotSelected

斷言指定的單選按鈕未被選?。?/p>

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

assertSelected

斷言下拉框被選取指定的值:

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

assertNotSelected

斷言下拉框未選取指定的值:

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

assertSelectHasOptions

斷言可選到指定數(shù)組中的值:

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

assertSelectMissingOptions

斷言選取的值并非指定數(shù)組中的值:

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

assertSelectHasOption

斷言可選到指定的值:

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

assertValue

斷言選擇器范圍內(nèi)的元素存在指定的值:

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

assertVisible

斷言選擇器范圍內(nèi)的元素可見:

$browser->assertVisible($selector);

assertPresent

斷言選擇器范圍內(nèi)的元素是存在的:

$browser->assertPresent($selector);

assertMissing

斷言選擇器范圍內(nèi)的元素不存在:

$browser->assertMissing($selector);

assertDialogOpened

斷言含有指定消息的 JavaScript 對(duì)話框已經(jīng)打開:

$browser->assertDialogOpened($message);

assertEnabled

斷言指定的字段是啟用的:

$browser->assertEnabled($field);

assertDisabled

斷言指定的字段是停用的:

$browser->assertDisabled($field);

assertFocused

斷言焦點(diǎn)在于指定的字段:

$browser->assertFocused($field);

assertNotFocused

斷言焦點(diǎn)不在指定的字段:

$browser->assertNotFocused($field);

assertVue

斷言 Vue 組件數(shù)據(jù)的屬性匹配指定的值:

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

assertVueIsNot

斷言 Vue 組件數(shù)據(jù)的屬性不匹配指定的值:

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

assertVueContains

斷言 Vue 組件數(shù)據(jù)的屬性是一個(gè)數(shù)組,并且該數(shù)組包含指定的值:

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

assertVueDoesNotContain

斷言 Vue 組件數(shù)據(jù)的屬性是一個(gè)數(shù)組,并且該數(shù)組不包含指定的值:

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

頁面

有時(shí)候,需要測(cè)試一系列復(fù)雜的動(dòng)作,這會(huì)使得測(cè)試代碼難以閱讀和理解。通過頁面可以定義出語義化的動(dòng)作,然后在指定頁面中可以使用單個(gè)方法。頁面還可以定義應(yīng)用或單個(gè)頁面通用選擇器的快捷方式。

生成頁面

dusk:page Artisan 命令可以生成頁面對(duì)象。所有的頁面對(duì)象都位于 tests/Browser/Pages 目錄:

php artisan dusk:page Login

配置頁面

頁面默認(rèn)擁有 3 個(gè)方法: url, assertelements。 在這里我們先詳述 urlassert 方法, elements 方法將會(huì) 選擇器簡寫 中詳述。

url 方法

url 方法應(yīng)該返回表示頁面 URL 的路徑。 Dusk 將會(huì)在瀏覽器中使用這個(gè) URL 來導(dǎo)航到具體頁面:

/**
 * 獲得頁面 URL 路徑。
 *
 * @return string
 */
 public function url(){   
  return '/login';
 }

assert 方法

assert 方法可以作出任何斷言來驗(yàn)證瀏覽器是否在指定頁面上。這個(gè)方法并不是必須的。你可以根據(jù)你自己的需求來做出這些斷言。這些斷言會(huì)在你導(dǎo)航到這個(gè)頁面的時(shí)候自動(dòng)執(zhí)行:

/**
 * 斷言瀏覽器當(dāng)前處于指定頁面。
 *
 * @return void
 */
 public function assert(Browser $browser){ 
    $browser->assertPathIs($this->url());
   }

導(dǎo)航至頁面

一旦頁面配置好之后,你可以使用 visit 方法導(dǎo)航至頁面:

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

有時(shí)候,你可能已經(jīng)在指定頁面了,你需要的只是「加載」當(dāng)前頁面的選擇器和方法到當(dāng)前測(cè)試中來。常見的例子有:當(dāng)你按下一個(gè)按鈕的時(shí)候,你會(huì)被重定向至指定頁面,而不是直接導(dǎo)航至指定頁面。在這種情況下,你需要使用 on 方法來加載頁面:

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

選擇器簡寫

elements 方法允許你為頁面中的任何 CSS 選擇器定義簡單易記的簡寫。例如,讓我們?yōu)閼?yīng)用登錄頁中的 email 輸入框定義一個(gè)簡寫:

/**
 * 獲取頁面的元素簡寫。
 *
 * @return array
 */
 public function elements(){ 
    return [  
          '@email' => 'input[name=email]',   
         ];
       }

現(xiàn)在你可以用這個(gè)簡寫來代替之前在頁面中使用的完整 CSS 選擇器:

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

全局的選擇器簡寫

安裝 Dusk 之后,Page 基類存放在你的 tests/Browser/Pages 目錄。該類中包含一個(gè) siteElements 方法,這個(gè)方法可以用來定義全局的選擇器簡寫,這樣在你應(yīng)用中每個(gè)頁面都可以使用這些全局選擇器簡寫了:

/**
 * 獲取站點(diǎn)全局的選擇器簡寫。
 *
 * @return array
 */
 public static function siteElements(){
     return [    
         '@element' => '#selector',   
          ];
        }

頁面方法

除了頁面中已經(jīng)定義的默認(rèn)方法之外,你還可以定義在整個(gè)測(cè)試過程中會(huì)使用到的其他方法。例如,假設(shè)我們正在開發(fā)一個(gè)音樂管理應(yīng)用,在應(yīng)用中都可能需要一個(gè)公共的方法來創(chuàng)建列表,而不是在每一頁、每一個(gè)測(cè)試類中都重寫一遍創(chuàng)建播放列表的邏輯,這時(shí)候你可以在你的頁面類中定義一個(gè) createPlaylist 方法:

<?php
    namespace Tests\Browser\Pages;
    use Laravel\Dusk\Browser;
    class Dashboard extends Page{  
      // 其他頁面方法...  
      /**
     * 創(chuàng)建一個(gè)新的播放列表。
     *
     * @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');   
           }
       }

方法被定義之后,你可以在任何使用到該頁的測(cè)試中使用這個(gè)方法了。瀏覽器實(shí)例會(huì)自動(dòng)傳遞該頁面方法:

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

組件

組件類似于 Dusk 的 「頁面對(duì)象」,不過它更多的是貫穿整個(gè)應(yīng)用程序中頻繁重用的 UI 和功能片斷,比如說導(dǎo)航條或信息通知彈窗。因此,組件并不會(huì)綁定于某個(gè)明確的 URL。

組件的生成

為了生成一個(gè)組件,使用 Artisan 命令 dusk:component 即可生成組件。新生成的組件位于 test/Browser/Components 目錄中:

php artisan dusk:component DatePicker

如上所示,這是生成一個(gè) “日期選擇器”(date picker) 組件的示例,這個(gè)組件可能會(huì)貫穿使用在你應(yīng)用程序的許多頁面中。在整個(gè)測(cè)試套件的大量測(cè)試頁面中,手動(dòng)編寫日期選擇的瀏覽器自動(dòng)化邏輯會(huì)非常麻煩。 更方便的替代辦法是,定義一個(gè)表示日期選擇器的 Dusk 組件,然后把自動(dòng)化邏輯封裝在該組件內(nèi):

<?php
    namespace Tests\Browser\Components;
    use Laravel\Dusk\Browser;
    use Laravel\Dusk\Component as BaseComponent;
    class DatePicker extends BaseComponent{   
     /**
     * 獲取組件的 root selector
     *
     * @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()   
       {    
           return [        
               '@date-field' => 'input.datepicker-input',       
               '@month-list' => 'div > div.datepicker-months',            
               '@day-list' => 'div > div.datepicker-days',      
         ];   
      }   
     /**
     * 選擇給定日期
     *
     * @param  \Laravel\Dusk\Browser  $browser
     * @param  int  $month
     * @param  int  $day
     * @return void
     */  
      public function selectDate($browser, $month, $day)  
        {    
            $browser->click('@date-field')             
               ->within('@month-list', function ($browser) use ($month) {       
                            $browser->click($month);         
                                })                
                 ->within('@day-list', function ($browser) use ($day) {       
                              $browser->click($day);           
                                   });   
          }
       }

組件的使用

組件定義一旦完成,在任何測(cè)試頁面的日期選擇器中選定一個(gè)日期就很輕松了。并且,如果需要修改選定日期的邏輯,僅修改該組件即可:

<?php
    namespace Tests\Browser;
    use Tests\DuskTestCase;
    use Laravel\Dusk\Browser;
    use Tests\Browser\Components\DatePicker;
    use Illuminate\Foundation\Testing\DatabaseMigrations;
    class ExampleTest extends DuskTestCase{  
      /**
     * 基本的組件測(cè)試示例
     *
     * @return void
     */   
      public function testBasicExample() 
         {    
             $this->browse(function (Browser $browser) {       
                  $browser->visit('/')                
                      ->within(new DatePicker, function ($browser) {                   
                           $browser->selectDate(1, 2018);               
                               })                   
                      ->assertSee('January');     
                       });   
            }
      }

持續(xù)集成

CircleCI

如果使用 CircleCI 運(yùn)行 Dusk 測(cè)試,則可以參考此配置文件作為起點(diǎn)。與 TravisCI 一樣,我們將使用 php artisan serve 命令啟動(dòng) PHP 的內(nèi)置 Web 服務(wù)器:

version: 2jobs:
    build:
        steps:            
            - run: sudo apt-get install -y libsqlite3-dev            
            - run: cp .env.testing .env            
            - run: composer install -n --ignore-platform-reqs            
            - run: npm install            
            - run: npm run production            
            - run: vendor/bin/phpunit            
            - run:
                name: Start Chrome Driver
                command: ./vendor/laravel/dusk/bin/chromedriver-linux
                background: true            
           - run:
                name: Run Laravel Server
                command: php artisan serve
                background: true            
           - run:
                name: Run Laravel Dusk Tests
                command: php artisan dusk

Codeship

Codeship 中運(yùn)行 Dusk 測(cè)試,需要在你的 Codeship 項(xiàng)目中添加以下命令。當(dāng)然,這些命令只是作為范例,你可以根據(jù)需要隨意添加額外的命令:

phpenv local 7.2
cp .env.testing .env
mkdir -p ./bootstrap/cache
composer install --no-interaction --prefer-dist
php artisan key:generate
nohup bash -c "php artisan serve 2>&1 &" && sleep 5
php artisan dusk

Heroku CI

Heroku CI 中運(yùn)行 Dusk 測(cè)試時(shí),請(qǐng)將下列 Google Chrome 構(gòu)建包和腳本添加到你的 Heroku app.json 文件中:

{  "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 > /dev/null 2>&1 &' && php artisan dusk" 
                    }  
                  }  
            }
       }

Travis CI

在  Travis CI 中運(yùn)行 Dusk 測(cè)試時(shí),你可以參考 .travis.yml 的配置。由于 Travis CI 不是圖形環(huán)境,因此我們需要采取一些額外的步驟來啟動(dòng) Chrome 瀏覽器。此外,我們將使用 php artisan serve 啟動(dòng) PHP 的內(nèi)置 Web 服務(wù)器:

language: php
php: 
 - 7.3
addons:
  chrome: stable
install:
  - cp .env.testing .env  
  - travis_retry composer install--no-interaction --prefer-dist --no-suggest  
  - php artisan key:generate
before_script:  
   - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &  
   - php artisan serve &
 script:
   - php artisan dusk

.env.testing 文件中,調(diào)整 APP_URL 的值:

APP_URL=http://127.0.0.1:8000
本文章首發(fā)在 LearnKu.com 網(wǎng)站上。