工作了不到兩週;我終於達到了 Go-DOM 的第一個重要里程碑。
現在,瀏覽器將在建立 DOM 樹時下載並執行遠端 JavaScript
。這個專案最初是一個瘋狂的想法;看到 Go 和 HTMX 是一個越來越受歡迎的堆疊;
Go 已經擁有測試純伺服器端渲染所需的所有工具。但是,當添加像 HTMX 這樣的庫時,應用程式的行為是初始 DOM 之間編排的結果;交互元素的屬性;到達的 HTTP 端點以及這些端點傳送的內容;回應標頭和正文。要從使用者的角度驗證行為,您需要一個瀏覽器;或至少是一個行為...與瀏覽器並不完全不同的測試工具。 1
搜尋「Go 中的無頭瀏覽器」只會導致建議在無頭模式下使用真實瀏覽器的結果。這種組合有巨大的開銷;阻礙快速高效的 TDD 循環。依賴真實的瀏覽器通常會減慢您的速度而不是加快您的速度。 2
於是這個想法就被激發了;用純 Go 編寫一個無頭瀏覽器作為 Web 應用程式的測試工具;
首先要解決的不確定性是 HTML 的解析;以及腳本執行。我很快就做到了; 2天內解決這兩個問題。我有一個非常基本的 HTML 解析器;我還將 v8 整合到程式碼庫中3
並使 Go 物件可以被 JavaScript 程式碼存取。HTML 解析器後來被刪除,因為 go x/net/html 已經實作了 HTML 解析器;處理 HTML 解析的所有怪癖。解析格式良好的文件並不是一個非常難解決的問題。它可以優雅地處理格式錯誤的 HTML,但在這方面卻變得棘手。
過了一段時間,我還設法讓內聯
腳本執行在正確的時刻運行;即當元素實際連接到 DOM 時執行腳本,而不是在解析完整的 HTML 之後執行。能夠使用內嵌腳本處理 HTML 文件之後;下一步是實際從來源下載
腳本。這就需要整合一個HTTP層;以便瀏覽器自行取得內容;而不是被灌輸內容。http.Client 也允許您使用 http.RoundTripper 介面控制實際的傳輸層。通常你會啟動一個伺服器;它將偵聽 TCP 連接埠上的請求。在這種情況下,TCP 充當傳輸層;但本身與 HTTP 請求的處理無關。由於 Go 中標準 HTTP 堆疊的簡單性;整個 HTTP 伺服器由單一函數 func Handle(http.ResponseWriter, *http.Request) 表示。
無頭瀏覽器可以完全繞過 TCP 堆疊的開銷,並使用自訂的 RoundTripper 直接呼叫此函數。
現在瀏覽器可以執行HTTP請求,但瀏覽器程式碼本身不知道HTTP層被繞過的事實。隨之而來的是在 DOM 解析期間下載腳本的能力。
讓我們探索一個簡單的測試,就像它現在在程式碼庫中一樣(程式碼使用 Ginkgo 和 Gomega,恕我直言,這是一個有點被忽視的組合)
首先,測試建立一個簡單的 HTTP 處理程序,該處理程序提供兩個端點:/index.html 和 /js/script.js。
It("Should download and execute script from script tags", func() { // Setup a server with test content server := http.NewServeMux() server.HandleFunc( "GET /index.html", func(res http.ResponseWriter, req *http.Request) { res.Write( []byte( `<html><head><script src="/js/script.js"></script></head><body>Hello, World!</body>`, ), ) }, ) server.HandleFunc( "GET /js/script.js", func(res http.ResponseWriter, req *http.Request) { res.Header().Add("Content-Type", "text/javascript") res.Write([]byte(`var scriptLoaded = true`)) }, ) // ...
此處的目的只是驗證腳本是否已執行。為此,腳本會產生一個可觀察到的副作用:它在全域範圍內設定一個值。
要驗證腳本是否已執行,只需檢查全域範圍,這是透過從測試本身執行臨時 JavaScript 來完成的;驗證表達式的結果。
建立瀏覽器、載入索引檔案並驗證觀察到的副作用的程式碼
browser := ctx.NewBrowserFromHandler(server) Expect(browser.OpenWindow("/index.html")).Error().ToNot(HaveOccurred()) Expect(ctx.RunTestScript("window.scriptLoaded")).To(BeTrue())
測試執行也相當快。測試套件中涉及 JavaScript 執行的部分目前由 32 個測試組成,運行時間為 23 毫秒。
由於該專案最初是在嘗試驗證 HTMX 應用程式時構思的,因此合理的下一個目標是支持這種情況。一個簡單的 HTMX 應用程序,帶有一個按鈕和一個計數器,按下按鈕時計數器會增加。
接下來是更進階的使用者互動;正確的表單處理,例如,輸入手線(例如,在 欄位中按enter 提交表單。這通常也涉及某種URL 重定向;這驅動了對歷史物件等的需求.
具有控制傳輸層的能力;我們可以提供具有獨特能力的測試;我們可以模擬系統在運行時依賴的外部站點。例如,對於給定的主機名,測試可以提供另一個模擬行為的 Go HTTP 處理程序。
最明顯的例子是使用外部身分提供者。此測試可以模擬登入流程的行為;不必強迫您在外部系統中建立虛擬帳戶,由於外部系統中斷而導致測試失敗,或者由於身分提供者引入的 2FA 或驗證碼而根本無法自動化該流程。
另一個用例是使用 API 密集型庫,例如地圖庫,這會產生使用成本。模擬外部站點,以免因執行測試套件而收到額外費用。
創建 100% 符合 Whatwg 標準的實現是一項艱鉅的任務;直到我真正開始閱讀 Whatwg 規範的部分內容之前,我並沒有完全理解其範圍。目標是創建一個工具幫助為 Web 應用程式編寫測試。完全相容是長期目標;但在專案達到某種程度的可用性之前,我會開始填補漏洞。
因此;在實際應用中更可能使用的功能更有可能被優先考慮。指向給出錯誤結果的實際測試的功能請求可能會被優先考慮。 實施特定標準的功能請求可能會被拒絕。
我相信這對許多開發人員來說都是一個非常有用的工具,所以如果您閱讀了本文,請讓您的同事知道它的存在。到目前為止,這只是一個業餘時間項目,目前我有很多空閒時間;但情況不會永遠如此。
如果你想現場觀看,請傳出去......
也許您甚至會贊助這個?您有一家使用 Go 建立 Web 應用程式的大公司嗎?歡迎聯絡我。
在這裡找到項目:https://github.com/stroiman/go-dom
如果您成功地聽到了對 BBC 流行廣播劇的致敬,那就太好了。 ↩
這是基於個人經驗。由於快速的回饋週期,正確執行 TDD 會加快你的速度。真實瀏覽器的開銷往往會讓您在生產程式碼之後編寫測試;失去了快速測試套件為您提供的回饋循環的好處。 ↩
v8go 專案已經奠定了基礎。然而;並非 v8 的所有功能都暴露給 Go 程式碼;包括嵌入本機物件的必要功能。我能夠將它們添加到單獨的叉子中;這仍然是 WIP。 ↩
以上是Go-DOM - 重大里程碑的詳細內容。更多資訊請關注PHP中文網其他相關文章!