做的事情太少有時會導致一個瘋狂的想法,而這一次;目的是透過嵌入v8 引擎,用Go 編寫一個無頭瀏覽器,具有完整的DOM 實現和JavaScript 支援。
這一切都是從編寫 HTMX 應用程式開始的,測試它的需求讓我很好奇是否有無頭瀏覽器的純 Go 實作。
搜尋「go headless browser」只會導致搜尋結果談論自動化無頭瀏覽器,即在無頭模式下使用真正的瀏覽器,例如 Firefox 的 Chrome。
但是在純 Go 中什麼都沒有。
所以我開始建造一個。
這可能看起來很愚蠢,因為編寫無頭瀏覽器永遠不會像真正的瀏覽器一樣工作;因此並不能真正驗證您的應用程式是否在您決定支援的所有瀏覽器中正常工作。這也不允許您在停止工作時獲得良好的功能,例如應用程式的螢幕截圖。
那為什麼呢?
為了在有效的 TDD 循環中工作,測試必須很快。緩慢的測試執行會阻礙 TDD,您會失去快速回饋循環提供的效率優勢。
使用瀏覽器自動化進行此類驗證會產生嚴重的開銷,而此類測試通常是在程式碼編寫後編寫;因此,它們不再有助於編寫正確的實作;但事後卻減少了維護負擔;只是偶爾會在您的付費客戶之前檢測到錯誤。
目標是建立一個支援 TDD 流程的工具。為了可用,它需要在進程內運行。
需要用Go編寫。
讓 DOM 處於進程內可以在 DOM 之上編寫更好的包裝器;這可以幫助為您的測試提供一個不太不穩定的介面,就像測試庫為 JavaScript 所做的那樣。
您不用依賴 CSS 類別名稱、元素 ID 或 DOM 結構,而是使用以使用者為中心的語言編寫測試,如下所示。
在有「電子郵件」標籤的文字方塊中輸入「me@example.com」
或用假設的程式碼。
testing.GetElement(Query{ role: "textbox", // The accessibility "name" of a textbox _is_ the label name: "Email", }).type("me@example.com")
此測試不關心標籤是否實作為
這將行為驗證與 UI 更改解耦;但它確實強製文字「電子郵件」以可存取的方式與輸入欄位關聯。這將測試與用戶如何與頁面互動結合;包括那些依賴螢幕閱讀器使用您的頁面的人。
這實現了TDD最重要的方面;編寫與具體行為相結合的測試。 1
儘管在技術上可能可以為進程外瀏覽器編寫相同的測試;原生程式碼的好處對於這些類型的助手最可能需要的 DOM 隨機存取類型至關重要。
為了舉例說明測試類型,我將使用 JavaScript 中的類似範例;也是使用 HTMX 的應用程式。此測試驗證請求需要身份驗證的頁面的一般登入流程。
有點長,因為我在這裡將所有設定和幫助程式碼合併到一個測試函數中。
testing.GetElement(Query{ role: "textbox", // The accessibility "name" of a textbox _is_ the label name: "Email", }).type("me@example.com")
簡單來說,測驗執行以下操作:
測試在內部啟動 HTTP 伺服器。因為 this 在測試過程中運行,所以可以對業務邏輯進行模擬和存根。測試使用jsdom與HTTP伺服器通訊;它既將 HTML 回應解析為 DOM,又在已初始化的沙箱中執行客戶端腳本,例如以 window 作為全域範圍。 3
這使得能夠編寫 HTTP 層的測試,其中驗證回應的內容是不夠的。在這種情況下; HTMX 按預期處理回應。
但除了等待一些 HTMX 事件,以免過早(或太晚)進行之外,測試實際上並不關心 HTMX。事實上,如果我從表單中刪除 HTMX,採用經典重定向,測試仍然可以通過。
(如果我完全刪除 HTMX <script> 標籤,測試將超時等待 HTMX 事件)</script>
雖然之前的測試比預期慢了一點;它相當快,通常在 150-180 毫秒內完成。對於大多數測試套件來說這太慢了,但它足夠快,可以在處理該特定功能時充當反饋循環。
此測試不是正常 TDD 運作的一部分。當我處理該功能時,它們就會運行;或在提交之前;確保沒有任何損壞。這是處理“慢測試”的完全正常的方式。
JavaScript 範例使用在隨機連接埠上啟動的真實 HTTP 伺服器。伺服器在測試運行器的進程中運行,這就是為什麼我們可以存根和模擬業務邏輯。
在 Go 中,HTTP 請求由 http.Handler 處理,因此無需實際啟動 HTTP 伺服器即可輕鬆使用 HTTP 處理邏輯。
這是 go-dom 程式碼 現在 處理的事情,目前測試套件的運行時間為零毫秒,四捨五入到最接近的毫秒。 4
運行並行測試的能力僅取決於您的程式碼並行運行的能力。由於這可以消耗 http.Handler,因此每個測試都可以創建自己的處理程序;每個都有不同的依賴項,替換為測試雙倍,以適合單獨的測試。
這可讓您測試整個 HTTP 層;使用存根業務邏輯。
幾乎沒有任何實施;目前的狀態是大約一天半工作的結果。我有一個基本的流標記產生器,可以使用 http 響應流,該流被傳遞到傳回 Node 的解析器。
程式碼目前可以處理字串 (還不允許有空格)到 HTMLHtmlElement 中。
接下來的步驟是
這很可能會死:(
我甚至沒有在 Go 專案上工作,這將是有價值的(我當時在 Node.js 專案上工作)。很高興看到 jsdom 如何幫助充當身份驗證流程的反饋循環,從而激發了一個有趣的愚蠢想法。作為一個患有多動症的人,這對我來說是一個典型的模式。我開始做一些有趣的事情,並努力去做;直到有其他東西引起我的注意並引起我的興趣。
除非...
其他開發人員認為這是一個好主意,並希望幫助建構它。
我相信這樣的工具對於任何將伺服器端渲染與客戶端腳本結合的 Go 專案都非常有幫助,包括基於 HTMX 的應用程式。
專案可以在這裡找到:https://github.com/stroiman/go-dom
TDD 的目標是而不是編寫單元測試。這是一個極為常見的現象;但完全不正確的誤解。 ↩
重要的不是我們被重定向;而是我們被重定向了。但瀏覽器歷史記錄具有正確的條目,提供瀏覽器後退/前進功能的合理行為。測試應該確實驗證了歷史的內容,甚至可能主動使用導航API來來回。像這樣;該測試可以在描述從用戶的角度來看預期的行為方面得到改進。 ↩
用 JavaScript 寫無頭瀏覽器有不公平的優點;因為你的模擬 DOM 已經是有效的 JavaScript 物件。在 Go 中,需要額外的工作來允許客戶端腳本改變 DOM,並讓結果可以在測試程式碼中存取。 ↩
據 Ginkgo 報道。這不包括建置和啟動的開銷,這有一個明顯但非常短的延遲。 ↩
以上是Go-DOM - 用 Go 寫的無頭瀏覽器。的詳細內容。更多資訊請關注PHP中文網其他相關文章!