首頁  >  文章  >  後端開發  >  Go-DOM - 重大里程碑

Go-DOM - 重大里程碑

Mary-Kate Olsen
Mary-Kate Olsen原創
2024-11-22 02:44:17172瀏覽

Go-DOM -  major milestone

工作了不到兩週;我終於達到了 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 之後執行。

處理 HTTP 請求

能夠使用內嵌腳本處理 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 應用程式時構思的,因此合理的下一個目標是支持這種情況。一個簡單的 HTMX 應用程序,帶有一個按鈕和一個計數器,按下按鈕時計數器會增加。

  • AnXMLHttpRequest 實作需要就位。為此,工作正在進行中。
  • XPathEvaluator。我相信一開始就可以填充。
  • 事件傳播。現在僅發出 DOMContentLoaded 和 load 事件。元素需要支援更多的事件;例如點擊;以及觸發它們的方法。
    • 這可能還需要正確的事件捕捉和冒泡。

進而 ...

接下來是更進階的使用者互動;正確的表單處理,例如,輸入手線(例如,在 欄位中按enter 提交表單。這通常也涉及某種URL 重定向;這驅動了對歷史物件等的需求.

整合外部站點

具有控制傳輸層的能力;我們可以提供具有獨特能力的測試;我們可以模擬系統在運行時依賴的外部站點。例如,對於給定的主機名,測試可以提供另一個模擬行為的 Go HTTP 處理程序。

最明顯的例子是使用外部身分提供者。此測試可以模擬登入流程的行為;不必強迫您在外部系統中建立虛擬帳戶,由於外部系統中斷而導致測試失敗,或者由於身分提供者引入的 2FA 或驗證碼而根本無法自動化該流程。

另一個用例是使用 API 密集型庫,例如地圖庫,這會產生使用成本。模擬外部站點,以免因執行測試套件而收到額外費用。

可用性勝於相容性

創建 100% 符合 Whatwg 標準的實現是一項艱鉅的任務;直到我真正開始閱讀 Whatwg 規範的部分內容之前,我並沒有完全理解其範圍。目標是創建一個工具幫助為 Web 應用程式編寫測試。完全相容是長期目標;但在專案達到某種程度的可用性之前,我會開始填補漏洞。

因此;在實際應用中更可能使用的功能更有可能被優先考慮。指向給出錯誤結果的實際測試的功能請求可能會被優先考慮。 實施特定標準的功能請求可能會被拒絕。

傳播這個詞

我相信這對許多開發人員來說都是一個非常有用的工具,所以如果您閱讀了本文,請讓您的同事知道它的存在。到目前為止,這只是一個業餘時間項目,目前我有很多空閒時間;但情況不會永遠如此。

如果你想現場觀看,請傳出去......

也許您甚至會贊助這個?您有一家使用 Go 建立 Web 應用程式的大公司嗎?歡迎聯絡我。

在這裡找到項目:https://github.com/stroiman/go-dom


  1. 如果您成功地聽到了對 BBC 流行廣播劇的致敬,那就太好了。 ↩

  2. 這是基於個人經驗。由於快速的回饋週期,正確執行 TDD 會加快你的速度。真實瀏覽器的開銷往往會讓您在生產程式碼之後編寫測試;失去了快速測試套件為您提供的回饋循環的好處。 ↩

  3. v8go 專案已經奠定了基礎。然而;並非 v8 的所有功能都暴露給 Go 程式碼;包括嵌入本機物件的必要功能。我能夠將它們添加到單獨的叉子中;這仍然是 WIP。 ↩

以上是Go-DOM - 重大里程碑的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn