From f68ff4ee099133b70f24a7547542451de626dcec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 5 Oct 2026 13:15:52 -0400 Subject: [PATCH] Web mirror: handler constructor and e2e tests --- examples/gallery/web.go | 10 ++- examples/gallery/web_test.go | 135 +++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 examples/gallery/web_test.go diff --git a/examples/gallery/web.go b/examples/gallery/web.go index dd58a50..c2e0ea9 100644 --- a/examples/gallery/web.go +++ b/examples/gallery/web.go @@ -35,6 +35,13 @@ type mirror struct { } func serveWeb(addr string, view func(c *ui.Context)) error { + _, h := newMirror(view) + slog.Info("gallery: web mirror listening", "addr", "http://"+addr) + return http.ListenAndServe(addr, h) +} + +// newMirror starts the frame loop of view and returns its HTTP handler. +func newMirror(view func(c *ui.Context)) (*mirror, http.Handler) { m := &mirror{ tt: ui.NewTester(view, 1200, 800), seed: maphash.MakeSeed(), @@ -52,8 +59,7 @@ func serveWeb(addr string, view func(c *ui.Context)) error { mux.HandleFunc("GET /frame.png", m.serveFrame) mux.HandleFunc("GET /events", m.serveEvents) mux.HandleFunc("POST /input", m.serveInput) - slog.Info("gallery: web mirror listening", "addr", "http://"+addr) - return http.ListenAndServe(addr, mux) + return m, mux } // loop draws frames while the picture keeps changing, then sleeps. diff --git a/examples/gallery/web_test.go b/examples/gallery/web_test.go new file mode 100644 index 0000000..d3d61c5 --- /dev/null +++ b/examples/gallery/web_test.go @@ -0,0 +1,135 @@ +package main + +import ( + "bufio" + "bytes" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/egoist/mygo/ui" + + mujica "mujicaui" +) + +// mirrorRig serves a one-field view through the web mirror. +type mirrorRig struct { + t *testing.T + m *mirror + srv *httptest.Server + text string +} + +func newMirrorRig(t *testing.T) *mirrorRig { + r := &mirrorRig{t: t} + var h http.Handler + r.m, h = newMirror(func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + ui.Column(c).Padding(40).Children(func() { + mujica.TextInput(c, &r.text, mujica.TextInputOptions{Label: "Ledger"}) + }) + }) + r.srv = httptest.NewServer(h) + t.Cleanup(r.srv.Close) + return r +} + +func (r *mirrorRig) post(in input) int { + r.t.Helper() + body, err := json.Marshal(in) + if err != nil { + r.t.Fatal(err) + } + res, err := http.Post(r.srv.URL+"/input", "application/json", bytes.NewReader(body)) + if err != nil { + r.t.Fatal(err) + } + res.Body.Close() + return res.StatusCode +} + +func (r *mirrorRig) get(path string) []byte { + r.t.Helper() + res, err := http.Get(r.srv.URL + path) + if err != nil { + r.t.Fatal(err) + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + r.t.Fatalf("GET %s: %d", path, res.StatusCode) + } + b, err := io.ReadAll(res.Body) + if err != nil { + r.t.Fatal(err) + } + return b +} + +func (r *mirrorRig) value() string { + r.m.mu.Lock() + defer r.m.mu.Unlock() + return r.text +} + +func TestMirrorServesPageAndFirstNotice(t *testing.T) { + r := newMirrorRig(t) + if page := r.get("/"); !bytes.Contains(page, []byte("