Laravel Dusk 控制台是一款 Laravel 扩展包,能够为你的 Dusk 测试套件提供漂亮的可视面板。通过它,你可以可视化运行 Dusk 测试时涉及的各个步骤,以及查看每个步骤的 DOM 快照。这对于调试浏览器测试、并搞清楚后台做了什么十分有用。同时,你还可以使用浏览器的调试工具来检查 DOM 快照。<img src=“https://user-gold-cdn.xitu.io…;h=728&f=png&s=505665” class=“rm-style”>除了可视面板,此扩展包还提供了 Laravel Dusk 测试监视器。在你对 Dusk 测试进行修改后,便会自动执行测试过程。该扩展包受到 Javascript 前端测试框架 —— Cypress 的强烈启发。查看本扩展包,请移步 GitHub 。什么是 Laravel Dusk?Laravel Dusk 提供了富有表现力的、易于使用的浏览器自动化和测试 API。使用 Laravel Dusk编写测试用例,像在真正的浏览器上一样。比如,当你想在网站上测试拖放功能时,想要测试Vue组件或其他与 Javascript 相关功能,那么你无法使用 Laravels HTTP 测试 API 本身进行测试。我认为 Laravel Dusk 是一个非常棒的软件包并且可以简化浏览器测试。以下是一个用户注册的示例测试,以便你可以了解 Laravel Dusk 的功能:public function test_can_register(){ $faker = Factory::create(); $this->browse(function($browser) use ($faker) { $password = $faker->password(9); $browser->visit(’/register’) ->assertSee(‘Register’) ->type(’name’, $faker->name) ->type(’email’, $faker->safeEmail) ->type(‘password’, $password) ->type(‘password_confirmation’, $password) ->press(‘Register’) ->assertPathIs(’/home’); });}要了解更多关于 Laravel Dusk 以及如何开始使用自己的浏览器测试的更多信息,请查看 官方文档。使用 Laravel Dusk 控制台在介绍 Laravel Dusk 控制台内部如何运行之前,让我们先瞄一眼如何在 Laravel 应用内安装并使用这个扩展包。如下步骤假定你已经按照 官方文档 成功地安装了 Laravel Dusk;或者甚至你已经写好了一些 Dusk 测试。首先,使用 Composer 安装本扩展包。composer require –dev beyondcode/dusk-dashboard接下来,打开 Laravel Dusk 生成的 DuskTestCase.php。你可以在 tests 目录里找到这个文件。请务必使用本扩展包的测试用例(Test case)作为基类,而不是 Laravel Dusk 的测试用例。稍后我再告诉你内部原理。找到此行:use Laravel\Dusk\TestCase as BaseTestCase;使用如下内容替换:use BeyondCode\DuskDashboard\Testing\TestCase as BaseTestCase;搞定。现在你可以使用如下命令启动 Laravel Dusk 控制台,并执行你的测试了。php artisan dusk:dashboard类似这样的界面便会展示在你的面前:<img src=“https://user-gold-cdn.xitu.io…;h=728&f=png&s=287914” class=“rm-style”>开始测试只需按下「Start Tests」按钮,即可运行 Laravel Dusk 测试,并观察到你的应用被测试时的输出,以及所发生的行为。随后,你便会看到 Dusk 测试产生的各种事件出现在你的控制台上。还有一种启动 Dusk 测试的方法是,只要编辑任意一个测试文件然后保存即可。Laravel Dusk 控制台内置了文件监视器。调试测试步骤你可以通过点击展示在列表中的测试行为,来调试和检查它们。点击后,你将会看到 DOM 快照,表示当此行为被记录时的 HTML 页面状态。若此行为以某种方式操作过 DOM,那么你也可以点击 「Before」和「After」按钮在事件发生「之前」或「之后」的 DOM 快照之间进行切换。如下,一个按下「Register」按钮的小例子:检查XHR请求有时候,查看运行测试时发生的有关 XHR 请求的其他信息可能会很有用。例如:你网站上又一个按钮,它将对某个服务端执行 GET 请求。Dusk Dashboard 允许您记录 XHR 事件,并显示响应状态和响应路径。默认情况下 XHR 请求检查不会启用,因为它需要你修改浏览器功能。要启用 XHR 的请求记录,打开你的  DuskTestCase.php ,在文件里,有个 driver 方法,用于设置不同测试操作的 WebDriver。由于此程序包需要对此驱动程序的功能进行一些调整,因此需要使用 $this->enableNetworkLogging 方法调用来封装  DesiredCapabilities 对象。protected function driver(){ $options = (new ChromeOptions)->addArguments([ ‘–disable-gpu’, ‘–headless’, ‘–window-size=1920,1080’, ]); return RemoteWebDriver::create( ‘http://localhost:9515’, $this->enableNetworkLogging( DesiredCapabilities::chrome()->setCapability( ChromeOptions::CAPABILITY, $options ) ) );}通过添加此功能,该程序包将启用记录 XHR 请求和响应信息所需的功能。工作原理基本思路十分简单:运行一个 WebSocket 服务,控制台用户连接到这个 WebSocket 服务,接着 PHPUnit 便会将浏览器事件和失败信息发送至所有 WebSocket 连接。以下是具体的实现方式:在内部,此扩展包向你的 Laravel 应用内添加了一个名为 StartDashboardCommand 的命令。当此命令被执行时,就会 启动 一个由 Ratchet 开发的 WebSocket 服务。最初我考虑基于我同 Freek 一起开发的 Laravel Websockets 实现此功能,然而随后就毙了这个想法。原因很简单,此扩展包仅能用作开发依赖项,并且我不需要 Pusher 或 Laravel 广播功能,因为广播是通过 PHPUnit 内部实现的。译者注:Freek 意指 Freek Van der Herten。另,截至目前,此扩展包也已经发布 v1.0.x 稳定版本。接下来,我添加两条路由到 WebSocket 服务。$dashboardRoute = new Route(’/dashboard’, [’_controller’ => new DashboardController()], [], [], null, [], [‘GET’]);$this->app->routes->add(‘dashboard’, $dashboardRoute);$eventRoute = new Route(’/events’, [’_controller’ => new EventController()], [], [], null, [], [‘POST’]);$this->app->routes->add(’events’, $eventRoute);$dashboardRoute 是一条普通 HTTP 控制器路由,用于输出 Laravel Dusk 控制台的 HTML 视图。就是这么简单,它只做一件事——返回 HTML 视图:class DashboardController extends Controller{ public function onOpen(ConnectionInterface $connection, RequestInterface $request = null) { $connection->send( str(new Response( 200, [‘Content-Type’ => ’text/html’], file_get_contents(DIR.’/../../../resources/views/index.html’) )) ); $connection->close(); }}$eventRoute 同样是一个 HTTP 路由,但只允许 POST 请求。它被用来在 PHPUnit 和 WebSocket 客户端之间通讯。同样十分简单,也只做一件事——接收 POST 数据,并广播给所有已连接的 WebSocket 客户端:class EventController extends Controller{ public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { try { /* * 如下即为从 PHPUnit 测试发来的 POST 数据, * 发送到已连接的客户端。 / foreach (Socket::$connections as $connection) { $connection->send($request->getBody()); } $conn->send(str(new Response(200))); } catch (Exception $e) { $conn->send(str(new Response(500, [], $e->getMessage()))); } $conn->close(); }}收集浏览器行为这是整个扩展包最乏味的部分。因为若想收集所有 Laravel Dusk 方法,并将它们广播到 WebSocket 连接,那么必须代理所有的消息再收集它们。在本扩展包自定义的 TestCase 类里,我们能够重写(override)浏览器实例被创建的过程。那么,此处就是我注入自定义的浏览器(Browser)类的地方。它负责代理现有方法并收集所有行为,同时转发给 WebSocket 连接。protected function newBrowser($driver){ return new Browser($driver);}没什么高端操作。接下来,我原本想直接创建一个新类,传给它 Laravel Dusk 的浏览器类,随后使用 __call 魔术方法代理所有的方法。这能够省下一大堆代码,但也会引出两个问题:用户无法使用 IDE 自动完成、方法提示功能。对我来说有点忍不了,我认为这是个非常重要的特性 —— 尤其是对于测试工具来说。开发者并不了解 API 的输入和输出,因此需要 IDE 的提示。另一个问题是,我不仅仅想在浏览器行为发生后记录 DOM 快照,在某些特定的行为发生前,同样想记录快照。所以这就是我为何不得不像下面这样,代理所有 Laravel Dusk 方法:/* @inheritdoc */public function assertTitle($title){ $this->actionCollector->collect(FUNCTION, func_get_args(), $this); return parent::assertTitle($title);}好了,这样我便能收集并记录各个行为,且依然维持着 IDE 自动完成功能。棒棒哒!现在你能看到这里的 actionCollector 是 PHPUnit 和 WebSocket 客户端之间的桥梁。它收集获得的信息,并用例如测试名称和 WebSocket POST 推送的端点数据来丰富它:protected function pushAction(string $name, array $payload){ try { $this->client->post(‘http://127.0.0.1:’.StartDashboardCommand::PORT.’/events’, [ RequestOptions::JSON => [ ‘channel’ => ‘dusk-dashboard’, ’name’ => $name, ‘data’ => $payload, ], ]); } catch (\Exception $e) { // Dusk-Dashboard 服务器可能是关闭的。不必惊慌。 }}它由 try-catch 包裹来保证即使在 Dusk Dashboard 服务器关闭时 Laravel Dusk 也能正常运行。UI 界面最后,值得注意的是,此扩展包在它的面板界面里也有很多说道。它由 TailwindCSS 和 Vue 驱动来展示到来的事件以及过滤它们等等。你可以在这 这 查看起始页面的代码。差不多就这些了。更多翻译文章请见 PHP / Laravel 开发者社区 https://laravel-china.org/top