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