Laravel Dusk
简介
Laravel Dusk Laravel Dusk 提供了富有表现力、简单易用的浏览器自动化及测试 API 。默认情况下,Dusk 不需要在你的机器上安装 JDK 或者 Selenium 。而是需要使用单独的 ChromeDriver 进行安装。当然,你也可以自由使用其他的兼容 Selenium 的驱动程序。
安装
首先,您应该安装 Google Chrome并将 laravel/dusk
依赖项添加到你的项目中:
composer require --dev laravel/dusk
注意:如果你是手动注册 Dusk 服务提供者,一定 不能 在你的生产环境中注册,这样可能会导致一些不守规矩的用户拥有控制你应用的权限。
安装好 Dusk 包后,运行 dusk:install
命令。dusk:install
命令会创建一个 tests/Browser
目录和一个测试例子:
php artisan dusk:install
接下来,在你的 .env
文件中设置 APP_URL
变量。这个值应该与你在浏览器中打开本应用的 URL 相匹配。
技巧:如果您使用 Laravel Sail 管理您的本地开发环境,还请查阅 configuring and running Dusk tests 的文档。
管理 ChromeDriver 安装
如果你想安装与 Laravel Dusk 附带版本不同的 ChromeDriver,可以使用 dusk:chrome-driver
命令:
# 为你的操作系统安装最新版本的 ChromeDriver...
php artisan dusk:chrome-driver
# 为你的操作系统安装指定版本的 ChromeDriver...
php artisan dusk:chrome-driver 86
# 为所有支持的操作系统安装指定版本的 ChromeDriver...
php artisan dusk:chrome-driver --all
# 安装与您的操作系统检测到的 Chrome/Chromium 版本匹配的 ChromeDriver 版本...
php artisan dusk:chrome-driver --detect
注意:Dusk 要求 chromedriver
二进制文件是可执行的。如果在 Dusk 运行时遇到问题,可以使用以下命令确保二进制文件是可执行的: chmod -R 0755 vendor/laravel/dusk/bin/
。
使用其他浏览器
默认情况下, Dusk 使用 Google Chrome 浏览器和一个单独安装的 ChromeDriver 来运行你的浏览器测试。当然,你可以运行你自己的 Selenium 服务,用任何你想用的浏览器来进行测试。
如果要这么做,打开你的 tests/DuskTestCase.php
文件,这个是应用测试用例的基类。在这个文件中,你可以移除对 startChromeDriver
方法的调用。这样 Dusk 就不会自动启动 ChromeDriver 了。
/**
* Prepare for Dusk test execution.
*
* @beforeClass
* @return void
*/
public static function prepare()
{
// static::startChromeDriver();
}
然后,你可以按照自己的意愿修改 driver
方法来连接到你选定的 URL 和端口。此外,你可以修改 「desired capabilities」(期望能力),它将会被传递给 WebDriver:
/**
* Create the RemoteWebDriver instance.
*
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
*/
protected function driver()
{
return RemoteWebDriver::create(
'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()
);
}
开始
创建测试
要创建一个 Dusk 测试,可以使用 dusk:make
命令。创建的测试将会被放在 tests/Browser
目录中:
php artisan dusk:make LoginTest
数据库迁移
编写的测试,大多数都是从数据库中查询数据的页面,与这些页面进行交互。但是,你的 Dusk 测试不应使用 RefreshDatabase
Trait。 RefreshDatabase
Trait 利用了数据库事务,该事务在 HTTP 请求中将不适用或不可用。相反,请使用 DatabaseMigrations
Trait,该 Trait 将为每个测试重新迁移数据库:
<?php
namespace Tests\Browser;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
}
注意:执行 Dusk 测试时,可能不会使用 SQLite 内存数据库。由于浏览器在其自己的进程中执行,因此它将无法访问其他进程的内存数据库。
运行时测试
要运行浏览器测试,请执行 Dask
Artisan 命令:
php artisan dusk
如果您上次运行 dush
命令时测试失败,可以先使用 dusk:fails
命令重新运行失败的测试,以节约时间:
php artisan dusk:fails
dusk
命令接受 PHPUnit 测试运行程序通常接受的任何参数,例如只允许您为给定的组:运行测试
php artisan dusk --group=foo
技巧:如果您使用 Laravel Sail 管理您的本地开发环境,还请查阅 配置和运行 Dusk 测试 的文档。
手动启动 ChromeDriver
默认情况下,Dusk 将自动尝试启动 ChromeDriver。如果这不适用于您的特定系统,您可以在运行 dusk
命令之前手动启动 ChromeDriver。如果你选择手动启动 ChromeDriver,你应该注释掉下面的 tests/testcase.php
文件:
/**
* Prepare for Dusk test execution.
*
* @beforeClass
* @return void
*/
public static function prepare()
{
// static::startChromeDriver();
}
此外,如果在9515以外的端口上启动 ChromeDriver,则应修改同类一的 driver
方法,以映射正确的端口:
/**
* 创建RemoteWebDriver实例。
*
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
*/
protected function driver()
{
return RemoteWebDriver::create(
'http://localhost:9515', DesiredCapabilities::chrome()
);
}
环境处理
要强制 Dusk 在运行测试时使用它自己的环境文件,请在项目的根目录中创建一个 .env.dusk.{environment}
文件。 例如,如果您要从 local
环境启动 dusk
命令,则应创建一个 .env.dusk.local
文件。
运行测试时,Dusk 会备份你的 .env
文件并将你的 Dusk 环境重命名为 .env
。 测试完成后,.env
文件将被恢复。
浏览器基础
创建浏览器
首先,让我们编写一个测试来验证我们可以登录到我们的应用程序。生成测试后,我们可以修改它以导航到登录页面,输入一些凭据,然后单击「登录」按钮。要创建浏览器实例,您可以在 Dusk 测试中调用 browse
方法:
<?php
namespace Tests\Browser;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
/**
* 基本的浏览器测试示例。
*
* @return void
*/
public function test_basic_example()
{
$user = User::factory()->create([
'email' => 'taylor@laravel.com',
]);
$this->browse(function ($browser) use ($user) {
$browser->visit('/login')
->type('email', $user->email)
->type('password', 'password')
->press('Login')
->assertPathIs('/home');
});
}
}
正如你在上面的例子中看到的,browse
方法接受一个闭包。 Dusk 会自动将一个浏览器实例传递给这个闭包,用于与您的应用程序交互和对应用程序进行断言的主要对象。
创建多个浏览器
有时您可能需要多个浏览器才能正确执行测试。例如,可能需要多个浏览器来测试与 websocket 交互的聊天页面。要创建多个浏览器,只需将更多浏览器参数添加到 browse
方法的闭 包签名中:
$this->browse(function ($first, $second) {
$first->loginAs(User::find(1))
->visit('/home')
->waitForText('Message');
$second->loginAs(User::find(2))
->visit('/home')
->waitForText('Message')
->type('message', 'Hey Taylor')
->press('Send');
$first->waitForText('Hey Taylor')
->assertSee('Jeffrey Way');
});
导航
可以使用 visit
方法导航到应用程序中的给定 URI:
$browser->visit('/login');
你也可以使用 visitRoute
方法导航到 命名路由:
$browser->visitRoute('login');
可以使用 back
和 forward
方法导航 「后退」和 「前进」:
$browser->back();
$browser->forward();
可以使用 refresh
方法刷新页面:
$browser->refresh();
改变浏览器窗口大小
可以使用 resize
方法去调整浏览器的窗口大小:
$browser->resize(1920, 1080);
该 maximize
方法可以将浏览器窗口最大化:
$browser->maximize();
该 fitContent
方法将自动适配浏览器的窗口大小和页面内容的尺寸:
$browser->fitContent();
测试失败时,Dusk 会自动将浏览器窗口缩放至内容大小并拍下屏幕快照,你可以通过调用 disableFitOnFailure
方法来禁用这一特性:
$browser->disableFitOnFailure();
你可以使用 move
方法将浏览器窗口移动到屏幕上的其他位置:
$browser->move($x = 100, $y = 100);
浏览器宏
如果你想定义一个可以在各种测试中重复使用的自定义浏览器方法,可以在 Browser
类中使用 macro
方法。通常,你应该从 服务提供者 的 boot
方法中调用它:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\Browser;
class DuskServiceProvider extends ServiceProvider
{
/**
* Register Dusk's browser macros.
*
* @return void
*/
public function boot()
{
Browser::macro('scrollToElement', function ($element = null) {
$this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);");
return $this;
});
}
}
该 macro
函数接收方法名作为其第一个参数,并接收闭包作为其第二个参数。 将宏作为 Browser
实现上的方法调用宏时,将执行宏的闭包:
$this->browse(function ($browser) use ($user) {
$browser->visit('/pay')
->scrollToElement('#credit-card-details')
->assertSee('Enter Credit Card Details');
});
用户认证
我们经常会测试需要身份验证的页面,你可以使用 Dusk 的 loginAs
方法来避免在每次测试期间与登录页面进行交互。该 loginAs
方法接收用户 ID 或者用户模型实例:
use App\Models\User;
$this->browse(function ($browser) {
$browser->loginAs(User::find(1))
->visit('/home');
});
注意:使用 loginAs
方法后,用户会话在文件中的所有测试被维护。
Cookies
你可以使用 cookie
方法来获取或者设置加密过的 cookie 的值:
$browser->cookie('name');
$browser->cookie('name', 'Taylor');
使用 plainCookie
则可以获取或者设置未加密过的 cookie 的值:
$browser->plainCookie('name');
$browser->plainCookie('name', 'Taylor');
你可以使用 deleteCookie
方法删除指定的 cookie:
$browser->deleteCookie('name');
运行 JavaScript
可以使用 script
方法在浏览器中执行任意 JavaScript 语句:
$browser->script('document.documentElement.scrollTop = 0');
$browser->script([
'document.body.scrollTop = 0',
'document.documentElement.scrollTop = 0',
]);
$output = $browser->script('return window.location.pathname');
获取截图
你可以使用 screenshot
方法来截图并将其指定文件名存储,所有截图都将存放在 tests/Browser/screenshots
目录下:
$browser->screenshot('filename');
控制台输出结果保存到硬盘
你可以使用 storeConsoleLog
方法将控制台输出指定文件名并写入磁盘,控制台输出默认存放在 tests/Browser/console
目录下:
$browser->storeConsoleLog('filename');
页面源码保存到硬盘
你可以使用 storeSource
方法将页面当前源代码指定文件名并写入磁盘,页面源代码默认会存放到 tests/Browser/source
目录:
$browser->storeSource('filename');
与元素交互
Dusk 选择器
编写 Dusk 测试最困难的部分之一就是选择良好的 CSS 选择器与元素进行交互。 随着时间的推移,前端的更改可能会导致如下所示的 CSS 选择器无法通过测试:
// HTML...
<button>Login</button>
// Test...
$browser->click('.login-page .container div > button');
Dusk 选择器可以让你专注于编写有效的测试,而不必记住 CSS 选择器。要定义一个选择器,你需要添加一个 dusk
属性在 HTML 元素中。然后在选择器前面加上 @
用来在 Dusk 测试中操作元素:
// HTML...
<button dusk="login-button">Login</button>
// Test...
$browser->click('@login-button');