Laravel Dusk 控制檯是一款 Laravel 擴展包,可以爲你的 Dusk 測試套件提供漂亮的可視面板。經過它,你能夠可視化運行 Dusk 測試時涉及的各個步驟,以及查看每一個步驟的 DOM 快照。這對於調試瀏覽器測試、並搞清楚後臺作了什麼十分有用。同時,你還可使用瀏覽器的調試工具來檢查 DOM 快照。php
除了可視面板,此擴展包還提供了 Laravel Dusk 測試監視器。在你對 Dusk 測試進行修改後,便會自動執行測試過程。html
該擴展包受到 Javascript 前端測試框架 —— Cypress 的強烈啓發。前端
Laravel Dusk 提供了富有表現力的、易於使用的瀏覽器自動化和測試 API。使用 Laravel Dusk編寫測試用例,像在真正的瀏覽器上同樣。好比,當你想在網站上測試拖放功能時,想要測試Vue組件或其餘與 Javascript 相關功能,那麼你沒法使用 Laravels HTTP 測試 API 自己進行測試。laravel
我認爲 Laravel Dusk 是一個很是棒的軟件包而且能夠簡化瀏覽器測試。 如下是一個用戶註冊的示例測試,以便你能夠了解 Laravel Dusk 的功能:git
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 以及如何開始使用本身的瀏覽器測試的更多信息,請查看 官方文檔。github
在介紹 Laravel Dusk 控制檯內部如何運行以前,讓咱們先瞄一眼如何在 Laravel 應用內安裝並使用這個擴展包。web
以下步驟假定你已經按照 官方文檔 成功地安裝了 Laravel Dusk;或者甚至你已經寫好了一些 Dusk 測試。chrome
首先,使用 Composer 安裝本擴展包。瀏覽器
composer require --dev beyondcode/dusk-dashboard
複製代碼
接下來,打開 Laravel Dusk 生成的 DuskTestCase.php
。你能夠在 tests
目錄裏找到這個文件。bash
請務必使用本擴展包的測試用例(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 請求的其餘信息可能會頗有用。例如:你網站上又一個按鈕,它將對某個服務端執行 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 也能正常運行。
最後,值得注意的是,此擴展包在它的面板界面裏也有不少說道。它由 TailwindCSS 和 Vue 驅動來展現到來的事件以及過濾它們等等。你能夠在這 這 查看起始頁面的代碼。
差很少就這些了。
更多翻譯文章請見 PHP / Laravel 開發者社區 laravel-china.org/topics/2119…