| name | hlive-testing |
| description | Write browser tests for HLive pages using the hlivetest package (github.com/SamHennessy/hlive/hlivetest) and Playwright. Use when testing HLive UI behavior end-to-end — spinning up a test server, driving a real browser (Click/ClickAndWait, TextContent, GetAttribute), and asserting with hlivetest.Diff. Use when an HLive task mentions tests, Playwright, or verifying interactive behavior. |
HLive Testing
HLive's behavior lives in the browser round-trip, so it's tested by driving a
real browser with Playwright via the hlivetest package. Tests boot an HLive
server, open a browser page against it, interact, and assert on the resulting
DOM.
Setup
Tests need Playwright browsers installed:
make install-test
# or: go run github.com/playwright-community/playwright-go/cmd/playwright install --with-deps
Because these are heavy browser tests, guard them so go test -short skips them
(the harness below does this).
The harness pattern
HLive's own suite (hlivetest/pages/) uses a small per-package harness. Copy it
into your test package:
package pages_test
import (
"testing"
l "github.com/SamHennessy/hlive"
"github.com/SamHennessy/hlive/hlivetest"
"github.com/playwright-community/playwright-go"
)
type harness struct {
server *hlivetest.Server
pwpage playwright.Page
teardown func()
}
func setup(t *testing.T, pageFn func() *l.Page) harness {
t.Helper()
if testing.Short() {
t.Skip("skipping test in short mode.")
}
h := harness{
server: hlivetest.NewServer(pageFn),
pwpage: hlivetest.NewBrowserPage(),
}
h.teardown = func() {
if err := h.pwpage.Close(); err != nil {
t.Error(err)
}
}
if _, err := h.pwpage.Goto(h.server.HTTPServer.URL); err != nil {
t.Fatal("goto page:", err)
}
return h
}
NewServer takes a page factory (func() *l.Page) — the same kind of
function you hand to l.NewPageServer. In a structured app (see the
hlive-project skill) that's an exported factory from your page package, so
a test imports it and passes it straight in: setup(t, page.Home).
Give the elements you select stable ids. With hhtml use the Id(...) attribute:
import (
l "github.com/SamHennessy/hlive"
. "github.com/SamHennessy/hlive/hhtml"
)
func Counter() *l.Page {
count := l.Box(0)
page := l.NewPage()
page.DOM().Body().Add(
Button(Id("btn"), l.On("click", func(_ context.Context, _ l.Event) {
count.Lock(func(v int) int { return v + 1 })
}), "+"),
Div(Id("count"), count),
)
return page
}
Writing a test
func TestClick_OneClick(t *testing.T) {
t.Parallel()
h := setup(t, pages.Click())
defer h.teardown()
hlivetest.Diff(t, "0", hlivetest.TextContent(t, h.pwpage, "#count"))
hlivetest.ClickAndWait(t, h.pwpage, "#btn")
hlivetest.Diff(t, "1", hlivetest.TextContent(t, h.pwpage, "#count"))
}
Use ClickAndWait before an assertion (it waits for HLive's diff to apply). Use
plain Click for intermediate clicks where you'll assert only at the end:
for i := 0; i < 9; i++ {
hlivetest.Click(t, h.pwpage, "#btn")
}
hlivetest.ClickAndWait(t, h.pwpage, "#btn")
hlivetest.Diff(t, "10", hlivetest.TextContent(t, h.pwpage, "#count"))
hlivetest helpers
All take (t, pwpage, ...) unless noted:
Click(selector) — click without waiting for the diff.
ClickAndWait(selector) — click, then block until the diff is applied.
TextContent(selector) string — element text.
GetAttribute(selector, attribute) string — an attribute value.
GetID(selector) string — the element's HLive id.
Title(pwpage) string — page title.
Diff(want, got any) — assert equal, reporting a diff on failure (t.Error).
DiffFatal(want, got any) — same but t.Fatal.
FatalOnErr(err) — fail fast on an error.
NewServer(pageFn) *Server / NewBrowserPage() playwright.Page — fixtures.
For interactions hlivetest doesn't wrap (typing, hover, selects), use the
playwright.Page directly (h.pwpage.Fill(...), .Hover(...)), then assert with
hlivetest.Diff.
Running
go test ./... # full run (needs browsers)
go test -short ./... # skips the browser tests
Reference
hlivetest/hlivetest.go, hlivetest/server.go, hlivetest/browser.go, and the
examples hlivetest/pages/harness_test.go, hlivetest/pages/click_test.go,
hlivetest/pages/click.go. Larger suites live under systemtests/.