Laravel Dusk 控制檯是一款 Laravel 擴充套件包,能夠為你的 Dusk 測試套件提供漂亮的可視皮膚。通過它,你可以視覺化執行 Dusk 測試時涉及的各個步驟,以及檢視每個步驟的 DOM 快照。這對於除錯瀏覽器測試、並搞清楚後臺做了什麼十分有用。同時,你還可以使用瀏覽器的除錯工具來檢查 DOM 快照。
除了可視皮膚,此擴充套件包還提供了 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
複製程式碼
類似這樣的介面便會展示在你的面前:
開始測試
只需按下「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 開發者社群 laravel-china.org/topics/2119…