I previously shared about my project called go-dom, a headless browser based on Go, which incorporates JavaScript functionality through a V8 engine. Now, I’ve achieved a significant development milestone:
Basic interactive HTMX functionality!
Though still under construction and not fully user-friendly yet, I’m refining the API following a major code revamp.
The core application features a simple web page with a counter that increments upon clicks. This required integrating several components for HTMX functionality, such as XmlHttpRequest
, FormData
, a basic event loop, as well as CSS and XPath selectors, among others.
I’ve also focused on code generation, leveraging IDL specifications from W3C sources to automate parts of the implementation, moving away from older manual coding practices.
Project Objective
The aim is to establish a library facilitating the testing of complex web applications in Go, specifically targeting HTMX/Go integration, which is becoming increasingly popular. The library is structured to support a Test-Driven Development (TDD) method to hasten feedback and productivity, allowing customization for testing individual features efficiently.
Unique to this project is the ability to interact directly with an http.Handler
, skipping the TCP layer and significantly reducing execution time to sub-millisecond levels. Prioritizing usability over complete spec adherence, it will not support quirks mode, given the modern application focus.
Addressing Alternative Libraries
In response to past inquiries regarding other libraries, many are headless versions of real browsers, bringing with them various overheads. This library aims to provide rapid feedback without the complexities involved with traditional headless browser implementations.
Use Case Example: GPS Tracking
Consider a scenario where an application utilizes a location API. With this modular library, a custom plugin could simulate GPS data from a GPX file for efficient testing, with features like time acceleration planned.
Upcoming Developments
Next, I plan to implement form interaction handling and manage browser history effectively to enhance user experience.
Code Showcase
Below is an example demonstrating basic browser interaction:
server := http.NewServeMux()
server.Handle(
"GET /home.html",
http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.Write([]byte(`<body>
<div id='display'></div>
<script>
const display = document.getElementById('display');
display.textContent = "42"
</script>
</body>`))
}),
)
browser := InitNewBrowser(server)
DeferCleanup(func() { browser.Shutdown() })
page, err := browser.Visit("/home.html")
Expect(err).ToNot(HaveOccurred())
display := page.Document().QuerySelector("#display")
Expect(display).To(HaveTextContent(Equal("42")))
HTMX Interaction Example
This snippet illustrates the HTMX interaction:
<html>
<head>
<script src="/assets/htmx.js"></script>
</head>
<body>
<div hx-trigger="click" hx-post="/update" id="counter">Count: 1</div>
</body>
</html>
The accompanying Go server for handling requests would look like this:
func SetupServer() http.Handler {
mux := http.NewServeMux()
total := 1
mux.Handle("GET /", http.FileServer(http.FS(content.FS)))
mux.HandleFunc("POST /update", func(res http.ResponseWriter, req *http.Request) {
total++
res.Write([]byte(fmt.Sprintf("Count: %d", total)))
})
return mux
}
And the test would verify the increment action:
var _ = Describe("Server Load Test", func() {
It("Should load HTMX without issue", func() {
browser := InitNewBrowser(SetupServer())
DeferCleanup(func() {
browser.Shutdown()
})
page, err := browser.Visit("/home.html")
Expect(err).ToNot(HaveOccurred())
counter := page.Document().QuerySelector("#counter")
Expect(counter).To(HaveInnerText(Equal("Count: 1")))
counter.Click()
counter = page.Document().QuerySelector("#counter")
Expect(counter).To(HaveInnerText(Equal("Count: 2")))
})
})