Browser testing Dusk


Browser Tests (Laravel Dusk)

Introduction

Laravel Dusk provides expressive , simple and easy-to-use browser automation and testing API. By default, Dusk does not require JDK or Selenium to be installed on your machine. Instead, you need to use a separate

ChromeDriver for installation. Of course, you are also free to use other Selenium-compatible drivers.

Installation

You should first add laravel/dusk dependency to your Composer:

composer require --dev laravel/dusk

{note} If you register the Dusk service manually Otherwise, you must not register it in your production environment, as this may result in some unruly users having permission to control your application.

After installing the Dusk package, run the dusk:install command:

php artisan dusk:install

Browser The directory will be in tests The directory is created and contains a test case. Next, set the APP_URL variable in your .env file. This value should match the URL that opens the app in your browser.

To run tests, use the dusk command. The dusk command can use the same parameters as the phpunit command:

php artisan dusk

If the test failed the last time the dusk command was run, you can use dusk:fails Command to rerun failed tests to save time:

php artisan dusk:fails

{Note} Dusk requires that the ChromeDriver binary is executable. If you encounter problems when Dusk is running, you can use the following command to ensure that the binary is executable: chmod -R 0755 vendor/laravel/dusk/bin.

Use another browser

By default, Dusk uses the Google Chrome browser and a separate Install the ChromeDriver to run your browser tests. Of course, you can run your own Selenium service and test it using any browser you want.

If you want to do this, open the tests/DuskTestCase.php file. This is the base class for application test cases. In this file, you can remove the call to the startChromeDriver method. This way Dusk will not automatically start ChromeDriver.

/**
 * 准备执行 Dusk 测试。
 *
 * @beforeClass
 * @return void
 */
 public static function prepare(){ 
    // static::startChromeDriver();
   }

You can then modify the driver method to connect to the URL and port of your choice. In addition, you can modify the "desired capabilities" (desired capabilities), which will be passed to WebDriver:

/**
 * 创建 RemoteWebDriver 实例。
 *
 * @return \Facebook\WebDriver\Remote\RemoteWebDriver
 */
 protected function driver(){
     return RemoteWebDriver::create(   
          'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()    
       );
    }

Get started

Creating a test

To create a Dusk test, use the dusk:make command. The created tests will be placed in the tests/Browser directory:

php artisan dusk:make LoginTest

Run the test

Use the dusk command to run your browser test:

php artisan dusk

If the test failed the last time you ran the dusk command , you can save time by rerunning failed tests using the dusk:fails command:

php artisan dusk:fails

dusk The command accepts any parameters that allow PHPUnit to run properly. For example, allowing you to run tests in a specified group:

php artisan dusk --group=foo

Run ChromeDriver manually

By default, Dusk will try to run ChromeDriver automatically . If it doesn't work on your particular system, you can manually run ChromeDriver before running the dusk command. If you choose to run ChromeDriver manually, you need to comment out the following line in your tests/DuskTestCase.php file:

/**
 * 为 Dusk 测试做准备。
 *
 * @beforeClass
 * @return void
 */
 public static function prepare(){ 
    // static::startChromeDriver();
 }

Additionally, if your ChromeDriver is running on a port other than 9515, You need to modify the driver method in the same class:

/**
 * 创建 RemoteWebDriver 实例。
 *
 * @return \Facebook\WebDriver\Remote\RemoteWebDriver
 */
 protected function driver(){ 
    return RemoteWebDriver::create( 
           'http://localhost:9515', DesiredCapabilities::chrome()   
       );
   }

##Environment processing

In order for Dusk to use its own environment file to run tests, you need to create a

.env.dusk.{environment} file in the project root directory. Simply put, if you want to use the local environment to run the dusk command, you need to create a .env.dusk.local file.

When running tests, Dusk will back up your

.env file and rename your Dusk environment file to .env. When the test is finished, it will restore your .env file.

Create browser

Let us first write a test case. This example can verify whether we can log in. system. After generating the test example, we can modify it and make it jump to the login interface. After entering the login information, click the "Login" button. We create a browser instance through the

browse method:

<?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;    
      /**
     * 一个基本的浏览器测试例子。
     *
     * @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');      
                    });   
           }
       }

In the above example, the

browse method receives a callback parameter. Dusk will automatically inject this browser instance into the callback process, and this browser instance can interact and assert with your application.

{tip} This test example can be used to test the login interface generated by the

make:auth command.

Create multiple browsers

Sometimes you may need multiple browsers to test correctly. For example, use multiple browsers to test an online chat page that communicates over websockets. If you want to create multiple browsers, you need to use names to distinguish browser instances in the callback of the

browse method, and then pass it to the callback to "apply" for multiple browser instances:

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

Change the browser window size

You can use the resize method to adjust the browser window size:

$browser->resize(1920, 1080);

maximize method can Maximize the browser window:

$browser->maximize();

Browser macro

If you want to define one you can use it in various tests For custom browser methods that are reused in the Browser class, you can use the macro method. Normally, you should call it from the service provider's boot method:

<?php
    namespace App\Providers;
    use Laravel\Dusk\Browser;
    use Illuminate\Support\ServiceProvider;
    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 The method receives a name as the first parameter, and the second parameter is a closure. When the browser macro is called as a method of an implementation of Browser, the browser macro's closure will be executed:

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

Authentication

You may often test some pages that require authentication. You can use Dusk's loginAs method to avoid having to log in to the login page once for each test. loginAs You can use user ID or user model instance:

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

{note} After using the loginAs method, the user's session will be persisted for Used by other test cases.

Database Migration

Just like the above authentication example, when your test cases need to be migrated , you should not use the RefreshDatabase trait. RefreshDatabase trait uses a database transaction that is not applicable to HTTP requests. Instead, we are going to use the 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;
    }

Interacting with elements

Dusk Selectors

Choosing a good CSS selector for element interaction is one of the most difficult parts of writing Dush tests. Over time, changes to the front end can cause CSS selectors like the following to break tests:

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

Dusk selectors let you focus on writing effective tests instead of memorizing CSS selectors. To define a selector, simply add a dusk attribute to your HTML element. Then, add @ in front of the selector to operate additional elements in the Dusk test:

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

Click the link

To click a link, you can use the clickLink method on the browser instance. The clickLink method will click the link that specifies the displayed text:

$browser->clickLink($linkText);

{Note} This method can interact with jQuery. If there is no jQuery on the page, Dusk will automatically inject it into the page to ensure that it is available during the test.

Text, Values ​​& Properties

Retrieving and setting values

Dusk provides several methods for interacting with the currently displayed text, values, and properties. For example, to get the "value" of an element that matches the specified selector, use the value method:

// 检索值...
$value = $browser->value('selector');
// 设置值...
$browser->value('selector', 'value');

Retrieve text

text This method can be used to match the displayed text of the element in the specified selector:

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

Retrieve attributes

Finally, attribute This method can be used to match the attributes of elements in the specified selector:

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

Usage of form

Input values

Dusk provides various methods for interacting with form and input elements. First let's look at an example of entering text in an input box:

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

Note that although the type method can pass a CSS selector as a parameter, this is not required. If no CSS selector is provided, Dusk searches for an input with the same name attribute. If it is still not found, Dusk will try to find a textarea with the same value as the name attribute passed in.

To append text to a field without clearing its contents, you can use the append method:

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

You can use clear Method to clear input value:

$browser->clear('email');

Drop-down menu

You need to select a value in the drop-down menu, you can use the select method. Similar to the type method, the select method does not necessarily require passing in a CSS selector. When using the select method, you should pass the option's actual value rather than its display text:

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

You can also randomly select an option by omitting the second argument:

$browser->select('size');

Checkbox

When using the "check" checkbox, you can use the check method. Like many other input-related methods, it is not necessary to pass in a CSS selector. If the exact selector cannot be found, Dusk will search for a checkbox that matches the name attribute:

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

Radio Button

When using the radio button option in "select", you can use the radio method. Like many other input-related methods, it does not require passing a CSS selector. If the exact selector cannot be found, Dusk will search for a radio button that matches the name attribute or the value attribute:

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

Attachment

attach method can attach a file to the file input element. Like many other input-related methods, it does not require passing a CSS selector. If the exact selector is not found, Dusk will search for a file input box that matches the name attribute:

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

{Note} The attach method requires PHP Zip extension, your server must have this extension installed.

Using the keyboard

keys method allows you to specify elements Enter a more complex input sequence than the type method. For example, you can press a key while entering a value. In this example, when typing taylor, the shift key is also pressed. When taylor is finished typing, otwell will be typed without pressing any keys:

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

You can even select an element in your app Press the "Shortcut Key":

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

{Tips} All keyboard keys packaged in {} are correspondingly defined in Facebook\WebDriver\WebDriverKeys class, which you can find in GitHub.

Use the mouse

Click on the element

# The ##click method can be used to "click" an element that matches the given selector:

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

Mouseover

mouseover Methods can be used for mouseover actions for elements that match the given selector:

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

Drag and drop

drag Methods are used for dragging with Drag elements matching the specified selector to other elements:

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

Alternatively, you can drag elements in a single direction:

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

JavaScript Dialog

Dusk provides several ways to interact with JavaScript dialog boxes:

// 等待对话框显示:
$browser->waitForDialog($seconds = null);
// 断言对话框已经显示,并且其消息与给定值匹配:
$browser->assertDialogOpened('value');
// 在打开的 JavaScript 提示对话框中输入给定值:
$browser->typeInDialog('Hello World');

Close an open JavaScript dialog box by clicking the OK button:

$browser->acceptDialog();

Close the open JavaScript dialog by clicking the Cancel button (only valid for confirmation dialogs):

$browser->dismissDialog();

Selector Scope

Sometimes you may want to perform multiple operations within a given selector range. For example, you might want to assert that certain text exists in a table and then click a button in the table. This requirement can be achieved using the

with method. All operations performed within the callback function are limited to the original selector:

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

Waiting for elements

When testing applications that use JavaScript extensively, it is often necessary to "wait" for the specified element or data to be available before testing. Dusk makes it easier. Using a series of methods, you can wait until a page element is available, or even until a given JavaScript expression evaluates to true.

Wait

If you need to test pause for the specified number of milliseconds, you can use the pause method:

$browser->pause(1000);

Wait for Selector

waitFor method can be used to pause test execution until an element on the page that matches the given CSS selector is displayed. By default, an exception will be thrown after a pause longer than 5 seconds. If necessary, you can pass a custom timeout as its second parameter:

// 等待选择器 5 秒时间...
$browser->waitFor('.selector');
// 等待选择器 1 秒时间...
$browser->waitFor('.selector', 1);

You can also wait for the specified selector to disappear from the page:

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

The selector is available Timed Scoping

Occasionally you may want to wait for a selector and then interact with it. For example, you might want to wait for a modal window to become available and then click the modal window's OK button. The whenAvailable method can be used in this situation. All element operations to be performed within the given callback will be restricted to the starting selector:

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

wait for text

waitForText The method can be used to wait for the given text on the page to be displayed:

// 等待指定文本 5 秒时间...
$browser->waitForText('Hello World');
// 等待指定文本 1 秒时间...
$browser->waitForText('Hello World', 1);

Waiting for the link

waitForLink The method is used to wait for the given link text to be displayed. The page displays:

// 等待指定链接 5 秒时间...
$browser->waitForLink('Create');
// 等待给定链接 2 秒时间...
$browser->waitForLink('Create', 1);

Waiting for the page to jump

After giving a path similar to $browser->assertPathIs('/home') When asserting, if window.location.pathname is updated asynchronously, the assertion will fail. You can use the waitForLocation method to wait for the page to jump to a given path:

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

You can also wait for the named route to jump:

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

Wait Page reload

If you want to assert after the page reloads, you can use the waitForReload method:

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

Wait for JavaScript expression

Sometimes you want to pause test execution until a given JavaScript expression evaluates to true. This can be easily accomplished using the waitUntil method. Pass an expression to this method without including the return keyword or the closing semicolon:

//等待表达式为 true 5 秒时间...
$browser->waitUntil('App.dataLoaded');
$browser->waitUntil('App.data.servers.length > 0');
// 等待表达式为 true 1 秒时间...
$browser->waitUntil('App.data.servers.length > 0', 1);

Wait for the Vue expression

below Method can be used to wait for a given Vue component property to contain or not contain a given value:

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

Waiting for callbacks

Many of Dusk's "wait" methods rely on the underlying waitUsing method. This method can be used directly to wait for a given callback to return true. waitUsing The method accepts the maximum number of seconds to wait, the interval between closure executions, the closure being executed, and a reliable failure message:

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

Making Vue Assertions

Dusk also allows you to make assertions about the state of Vue component data. For example, suppose your application contains the following Vue component:

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

You can make the following assertion on the state of the Vue component:

/**
 * 一个简单的 Vue 测试例子。
 *
 * @return void
 */
 public function testVue(){ 
    $this->browse(function (Browser $browser) {    
        $browser->visit('/')            
            ->assertVue('user.name', 'Taylor', '@profile-component');  
        });
    }

Available assertions

Dusk provides a series of available assertion methods. All assertions are as follows:

##assertTitle

Assert that the page title matches the specified text:

$browser->assertTitle($title);

##assertTitleContains

Assert that the page title contains the specified text:

$browser->assertTitleContains($title);

assertUrlIs

Assert that the current URL (without query string) matches the specified string:

$browser->assertUrlIs($url);

assertSchemeIs

Assert that the current URL matches the given string:

$browser->assertSchemeIs($scheme);

assertSchemeIsNot

Assert that the current URL match does not match the given string:

$browser->assertSchemeIsNot($scheme);

assertHostIs

Assert that the host of the current URL matches the given value:

$browser->assertHostIs($host);

##assertHostIsNot
Assert that the host of the current URL does not match the given value:

$browser->assertHostIsNot($host);

##assertPortIs

Assert the current URL The port value matches the given value:
$browser->assertPortIs($port);

assertPortIsNot

Asserts that the port value of the current URL matches the given value The specified value does not match:
$browser->assertPortIsNot($port);

assertPathBeginsWith

Assert that the current URL starts with the specified path:
$browser->assertPathBeginsWith($path);

##assertPathIs

Assert that the current path matches the specified path:
$browser->assertPathIs('/home');

assertPathIsNot

Assert that the current path does not match the specified path:
$browser->assertPathIsNot('/home');

assertRouteIs

Assert that the current URL matches the URL of the specified named route:
$browser->assertRouteIs($name, $parameters);

##assertQueryStringHas Assert that the specified query string parameter exists:

$browser->assertQueryStringHas($name);
Assert that the specified query string parameter exists and the value of the parameter is the specified value:
$browser->assertQueryStringHas($name, $value);

assertQueryStringMissingAssert that the specified query string parameter does not exist:

$browser->assertQueryStringMissing($name);

assertFragmentIs

Assert that the current fragment conforms to the specified fragment:

$browser->assertFragmentIs('anchor');

##assertFragmentBeginsWith

Assert that the current fragment starts with the specified fragment:

$browser->assertFragmentBeginsWith('anchor');

##assertFragmentIsNot

Assert that the current fragment Sharding does not match the specified sharding:

$browser->assertFragmentIsNot('anchor');

##assertHasCookie
Assert that the specified cookie exists:

$browser->assertHasCookie($name);

##assertCookieMissing

Assert that the specified cookie does not exist:
$browser->assertCookieMissing($name);

assertCookieValue

Assert that the cookie exists with the specified value:
$browser->assertCookieValue($name, $value);

assertPlainCookieValue

Assert that an unencrypted cookie exists with the specified value:
$browser->assertPlainCookieValue($name, $value);

assertSee

Assert The specified text exists on the current page:
$browser->assertSee($text);

assertDontSee

Assert that the specified text does not exist on the current page:
$browser->assertDontSee($text);

##assertSeeIn

Assert that the specified text exists within the selector range:
$browser->assertSeeIn($selector, $text);

assertDontSeeIn

Assert that the specified text does not exist within the selector range:
$browser->assertDontSeeIn($selector, $text);

assertSourceHas

Assert that the specified source code exists on the current page:
$browser->assertSourceHas($code);

##assertSourceMissingAssert that the specified source code does not exist on the current page:

$browser->assertSourceMissing($code);

assertSeeLinkAssert that the current page exists Specified link:

$browser->assertSeeLink($linkText);

##assertDontSeeLink

Assert that the specified link does not exist on the current page:

$browser->assertDontSeeLink($linkText);

assertInputValue

Assert that the specified value exists in the input box:

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

assertInputValueIsNot

Assert that the specified value does not exist in the input box:

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

assertChecked

Assert that the specified checkbox is checked:

$browser->assertChecked($field);

assertNotChecked

Assert that the specified checkbox is not checked:

$browser->assertNotChecked($field);

##assertRadioSelected

Assert that the specified radio button is selected:

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

##assertRadioNotSelected

Assert that the specified radio button is not Selection:

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

##assertSelected
Assert that the drop-down box is selected with the specified value:

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

assertNotSelected
Assert that the drop-down box does not select the specified value:

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

assertSelectHasOptions
Assert optional to the value in the specified array:

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

assertSelectMissingOptions
Assert that the selected value is not a value in the specified array:

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

##assertSelectHasOption

Assert that the specified value is optional:
$browser->assertSelectHasOption($field, $value);

assertValue

Assert that the specified element exists within the selector range Value:
$browser->assertValue($selector, $value);

##assertVisible

Assert that elements within the selector range are visible:
$browser->assertVisible($selector);

assertPresent

Assert that the elements within the selector range exist:
$browser->assertPresent($selector);

assertMissing

Assert that the element within the selector range does not exist:
$browser->assertMissing($selector);


assertDialogOpened

Assert that the JavaScript dialog box containing the specified message has been opened:
$browser->assertDialogOpened($message);

assertEnabled

Assert that the specified field is enabled:
$browser->assertEnabled($field);

##assertDisabledAssert that the specified field Field is disabled:

$browser->assertDisabled($field);

assertFocusedAssert focus is on the specified field:

$browser->assertFocused($field);

##assertNotFocused

Assert that the focus is not on the specified field:

$browser->assertNotFocused($field);

assertVue

Assert that the properties of the Vue component data match the specified value:

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

assertVueIsNot

Assert that the properties of the Vue component data do not match the specified value:

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

##assertVueContains

Assert that the property of the Vue component data is an array and that the array contains the specified value:

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

assertVueDoesNotContain

Assert that the property of the Vue component data is an array, and the array does not contain the specified value:

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

Page

Sometimes, a complex series of actions needs to be tested, which can make the test code difficult to read and understand. Semantic actions can be defined through the page, and then a single method can be used in the specified page. Pages can also define shortcuts to selectors that are common to applications or individual pages.

Generate page

dusk:page The Artisan command can generate page objects. All page objects are located in the tests/Browser/Pages directory:

php artisan dusk:page Login

##Configuration Page

The page has 3 methods by default:

url

, assert and elements. Here we first detail the url and assert methods, the elements method will be detailed in Selector abbreviation.

url

Methods

url

The method should return the path representing the URL of the page. Dusk will use this URL in the browser to navigate to the specific page:

/**
 * 获得页面 URL 路径。
 *
 * @return string
 */
 public function url(){   
  return '/login';
 }

##assert
Method

assert

Methods can make any assertions to verify that the browser is on the specified page. This method is not required. You can make these assertions based on your own needs. These assertions will be executed automatically when you navigate to this page:

/**
 * 断言浏览器当前处于指定页面。
 *
 * @return void
 */
 public function assert(Browser $browser){ 
    $browser->assertPathIs($this->url());
   }

Navigate to page
Once the page After configuring, you can use the

visit

method to navigate to the page:

use Tests\Browser\Pages\Login;$browser->visit(new Login);
Sometimes, you may already be on the specified page, and all you need is to "load" the selector of the current page and method to the current test. Common examples are: when you press a button, you will be redirected to the specified page instead of navigating directly to the specified page. In this case, you need to use the on

method to load the page:

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

Selector Shorthand

elements method allows you to define a simple and easy-to-remember shorthand for any CSS selector in the page. For example, let's define an abbreviation for the email input field on the app's login page:

/**
 * 获取页面的元素简写。
 *
 * @return array
 */
 public function elements(){ 
    return [  
          '@email' => 'input[name=email]',   
         ];
       }

Now you can use this abbreviation instead of the full CSS selector you used previously in the page:

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

Global selector abbreviation

After installing Dusk, the Page base class is stored in your tests/Browser/Pages Table of contents. This class contains a siteElements method, which can be used to define global selector abbreviations, so that each page in your application can use these global selector abbreviations:

/**
 * 获取站点全局的选择器简写。
 *
 * @return array
 */
 public static function siteElements(){
     return [    
         '@element' => '#selector',   
          ];
        }

Page methods

In addition to the default methods already defined in the page, you can also define the methods that will be used throughout the testing process. other methods. For example, suppose we are developing a music management application. In the application, we may need a public method to create a list. Instead of rewriting the logic of creating a playlist in every page and every test class, at this time you You can define a createPlaylist method in your page class: After the

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

method is defined, you can use this method in any test that uses the page. The browser instance will automatically pass the page method:

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

##Component

Component is similar to Dusk's "Page Object" ”, but it is more of a UI and functional fragment that is frequently reused throughout the entire application, such as a navigation bar or information notification pop-up window. Therefore, the component is not bound to an explicit URL.

Generation of components

To generate a component, use the Artisan command

dusk:component The component can be generated. The newly generated component is located in the test/Browser/Components directory:

php artisan dusk:component DatePicker

As shown above, this is an example of generating a "date picker" component. This component may Will be used throughout many pages of your application. Manually writing browser automation logic for date selection across a large number of test pages across a test suite would be cumbersome. A more convenient alternative is to define a Dusk component that represents a date picker, and then encapsulate the automation logic in the component:

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

Using the component

Once the component definition is complete, it is easy to select a date in the date picker on any test page. And, if you need to modify the logic of the selected date, just modify this component:

<?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{  
      /**
     * 基本的组件测试示例
     *
     * @return void
     */   
      public function testBasicExample() 
         {    
             $this->browse(function (Browser $browser) {       
                  $browser->visit('/')                
                      ->within(new DatePicker, function ($browser) {                   
                           $browser->selectDate(1, 2018);               
                               })                   
                      ->assertSee('January');     
                       });   
            }
      }

Continuous Integration

CircleCI

If you are using CircleCI to run Dusk tests, you can refer to this configuration file as a starting point. As with TravisCI, we will start PHP's built-in web server using the php artisan serve command:

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

To run Dusk tests in Codeship, you need to add the following commands to your Codeship project. Of course, these commands are just examples, feel free to add additional commands as needed:

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

When running Dusk tests in

Heroku CI, add the following Google Chrome buildpack and script to your Heroku app.json file:

{  "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

When running Dusk tests in

Travis CI, you can refer to .travis.yml Configuration. Since Travis CI is not a graphical environment, we need to take a few extra steps to launch the Chrome browser. Additionally, we will start PHP's built-in web server using php artisan serve:

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

In the

.env.testing file, adjust APP_URL Value:

APP_URL=http://127.0.0.1:8000

This article was first published on the
LearnKu.com website.