Browser testing Dusk
Browser Tests (Laravel Dusk)
- Introduction
- Installation
- #Start using
- Interacting with elements
- Available assertions
- Page
- Component
- Continuous integration
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.
.env file and rename your Dusk environment file to
.env. When the test is finished, it will restore your
.env file.
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 theCreate multiple browsersSometimes 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 themake:auth
command.
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 inFacebook\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 DialogDusk 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 ScopeSometimes 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
assertTitleContains
assertUrlIs
assertSchemeIs
assertSchemeIsNot
assertHostIs
assertHostIsNot
assertPortIs
assertPortIsNot
assertPathBeginsWith
assertPathIs
assertPathIsNot
assertRouteIs
assertQueryStringHas
assertQueryStringMissing
assertFragmentIs
assertFragmentBeginsWith
assertFragmentIsNot
assertHasCookie
assertCookieMissing
assertCookieValue
assertPlainCookieValue
assertSee
assertDontSee
assertSeeIn
assertDontSeeIn
assertSourceHas
assertSourceMissing
assertSeeLink
assertDontSeeLink
assertInputValue
assertInputValueIsNot
assertChecked
assertNotChecked
assertRadioSelected
assertRadioNotSelected
assertSelected
assertNotSelected
assertSelectHasOptions
assertSelectMissingOptions
assertSelectHasOption
assertValue
assertVisible
assertPresent
assertMissing
assertDialogOpened
assertEnabled
assertDisabled
assertFocused
assertNotFocused
assertVue
assertVueIsNot
assertVueContains
assertVueDoesNotContain
$browser->assertTitle($title);
Assert that the page title contains the specified text:
$browser->assertTitleContains($title);
Assert that the current URL (without query string) matches the specified string:
$browser->assertUrlIs($url);
Assert that the current URL matches the given string:
$browser->assertSchemeIs($scheme);
Assert that the current URL match does not match the given string:
$browser->assertSchemeIsNot($scheme);
Assert that the host of the current URL matches the given value:
$browser->assertHostIs($host);##assertHostIsNotAssert that the host of the current URL does not match the given value:
$browser->assertHostIsNot($host);
$browser->assertPortIs($port);
$browser->assertPortIsNot($port);
$browser->assertPathBeginsWith($path);Assert that the current path matches the specified path:
$browser->assertPathIs('/home');
$browser->assertPathIsNot('/home');
$browser->assertRouteIs($name, $parameters);
##assertQueryStringHas Assert that the specified query string parameter exists:
$browser->assertQueryStringHas($name);
$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');
Assert that the current fragment Sharding does not match the specified sharding:
$browser->assertFragmentIsNot('anchor');##assertHasCookieAssert that the specified cookie exists:
$browser->assertHasCookie($name);
$browser->assertCookieMissing($name);
$browser->assertCookieValue($name, $value);
$browser->assertPlainCookieValue($name, $value);
$browser->assertSee($text);
$browser->assertDontSee($text);Assert that the specified text exists within the selector range:
$browser->assertSeeIn($selector, $text);
Assert that the specified text does not exist within the selector range:
$browser->assertDontSeeIn($selector, $text);
$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);##assertRadioSelectedAssert that the specified radio button is selected:
$browser->assertRadioSelected($field, $value);
Assert that the specified radio button is not Selection:
$browser->assertRadioNotSelected($field, $value);##assertSelectedAssert that the drop-down box is selected with the specified value:
$browser->assertSelected($field, $value);
assertNotSelectedAssert that the drop-down box does not select the specified value: $browser->assertNotSelected($field, $value);
assertSelectHasOptionsAssert optional to the value in the specified array: $browser->assertSelectHasOptions($field, $values);
assertSelectMissingOptionsAssert that the selected value is not a value in the specified array: $browser->assertSelectMissingOptions($field, $values);
$browser->assertSelectHasOption($field, $value);
$browser->assertValue($selector, $value);Assert that elements within the selector range are visible:
$browser->assertVisible($selector);
$browser->assertPresent($selector);
$browser->assertMissing($selector);
Assert that the JavaScript dialog box containing the specified message has been opened:
$browser->assertDialogOpened($message);
$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);##assertVueContainsAssert 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);assertVueDoesNotContainAssert 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);PageSometimes, 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
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
.
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
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 pageOnce 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');##ComponentComponent 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 componentsTo 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 DatePickerAs 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 componentOnce 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 CIWhen 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 CIWhen 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 duskIn the
.env.testing file, adjust
APP_URL Value:
APP_URL=http://127.0.0.1:8000This article was first published on the