From b8242d4e28559f5b6998abd5d2b8a891b0892307 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:19:52 -0400 Subject: [PATCH] Tests: one snapshot helper (snapshot, snapshotAfter) replaces three copies --- baseline_states_test.go | 16 +++++++------- context_menu_test.go | 2 +- dropdown_menu_test.go | 2 +- hover_card_test.go | 2 +- overlay_snapshot_test.go | 45 ---------------------------------------- snapshot_test.go | 9 ++++++++ tabs_test.go | 42 +++---------------------------------- tooltip_test.go | 2 +- 8 files changed, 24 insertions(+), 96 deletions(-) diff --git a/baseline_states_test.go b/baseline_states_test.go index 3026371..e7dc8da 100644 --- a/baseline_states_test.go +++ b/baseline_states_test.go @@ -23,9 +23,9 @@ func TestBaselineButtonStates(t *testing.T) { Button(c, "Cancel", ButtonOptions{Variant: Secondary}) }) } - overlaySnapshot(t, "button-hover", 300, 90, view, func(tt *ui.Tester) { tt.Move(baselineAt(t, tt, "Save")) }) - overlaySnapshot(t, "button-pressed", 300, 90, view, func(tt *ui.Tester) { tt.Press(baselineAt(t, tt, "Save")) }) - overlaySnapshot(t, "button-focus", 300, 90, view, func(tt *ui.Tester) { tt.Key(0, ui.KeyTab) }) + snapshotAfter(t, "button-hover", 300, 90, view, func(tt *ui.Tester) { tt.Move(baselineAt(t, tt, "Save")) }) + snapshotAfter(t, "button-pressed", 300, 90, view, func(tt *ui.Tester) { tt.Press(baselineAt(t, tt, "Save")) }) + snapshotAfter(t, "button-focus", 300, 90, view, func(tt *ui.Tester) { tt.Key(0, ui.KeyTab) }) } func TestBaselineTextInputStates(t *testing.T) { @@ -36,8 +36,8 @@ func TestBaselineTextInputStates(t *testing.T) { TextInput(c, &date, TextInputOptions{Label: "Date", Error: "No such date"}) }) } - overlaySnapshot(t, "text_input-focus", 400, 170, view, func(tt *ui.Tester) { tt.Key(0, ui.KeyTab) }) - overlaySnapshot(t, "text_input-error-focus", 400, 170, view, func(tt *ui.Tester) { + snapshotAfter(t, "text_input-focus", 400, 170, view, func(tt *ui.Tester) { tt.Key(0, ui.KeyTab) }) + snapshotAfter(t, "text_input-error-focus", 400, 170, view, func(tt *ui.Tester) { tt.Key(0, ui.KeyTab) tt.Key(0, ui.KeyTab) }) @@ -51,7 +51,7 @@ func TestBaselineCheckboxStates(t *testing.T) { Checkbox(c, &off, "Open", CheckboxOptions{}) }) } - overlaySnapshot(t, "checkbox-hover", 240, 110, view, func(tt *ui.Tester) { tt.Move(baselineAt(t, tt, "Open")) }) - overlaySnapshot(t, "checkbox-focus", 240, 110, view, func(tt *ui.Tester) { tt.Key(0, ui.KeyTab) }) - overlaySnapshot(t, "checkbox-pressed", 240, 110, view, func(tt *ui.Tester) { tt.Press(baselineAt(t, tt, "Sealed")) }) + snapshotAfter(t, "checkbox-hover", 240, 110, view, func(tt *ui.Tester) { tt.Move(baselineAt(t, tt, "Open")) }) + snapshotAfter(t, "checkbox-focus", 240, 110, view, func(tt *ui.Tester) { tt.Key(0, ui.KeyTab) }) + snapshotAfter(t, "checkbox-pressed", 240, 110, view, func(tt *ui.Tester) { tt.Press(baselineAt(t, tt, "Sealed")) }) } diff --git a/context_menu_test.go b/context_menu_test.go index d767599..cd6c876 100644 --- a/context_menu_test.go +++ b/context_menu_test.go @@ -93,7 +93,7 @@ func TestContextMenuDisabled(t *testing.T) { func TestContextMenuSnapshot(t *testing.T) { a := &menuApp{} - overlaySnapshot(t, "context_menu", 460, 320, func(c *ui.Context) { + snapshotAfter(t, "context_menu", 460, 320, func(c *ui.Context) { ui.Column(c).Padding(20).Children(func() { row := ui.Row(c).Height(36).FillWidth().Padding(0, 12).AlignItems(ui.Center).Background(Tokens(c).Selection) row.Children(func() { ui.Text(c, "Letter to the Countess") }) diff --git a/dropdown_menu_test.go b/dropdown_menu_test.go index d06ed43..9b4d078 100644 --- a/dropdown_menu_test.go +++ b/dropdown_menu_test.go @@ -211,7 +211,7 @@ func TestDropdownMenuTabInSubmenuClosesMenu(t *testing.T) { func TestDropdownMenuSnapshot(t *testing.T) { a := &menuApp{pinned: true} - overlaySnapshot(t, "dropdown_menu", 520, 320, func(c *ui.Context) { + snapshotAfter(t, "dropdown_menu", 520, 320, func(c *ui.Context) { ui.Column(c).Padding(20).AlignItems(ui.Start).Children(func() { DropdownMenu(c, "Actions", DropdownMenuOptions{}, a.build) }) diff --git a/hover_card_test.go b/hover_card_test.go index 8314668..43e5991 100644 --- a/hover_card_test.go +++ b/hover_card_test.go @@ -154,7 +154,7 @@ func TestHoverCardInsideDialog(t *testing.T) { } func TestHoverCardSnapshot(t *testing.T) { - overlaySnapshot(t, "hover_card", 420, 240, func(c *ui.Context) { + snapshotAfter(t, "hover_card", 420, 240, func(c *ui.Context) { ui.Column(c).Padding(24).AlignItems(ui.Start).Children(func() { b := Button(c, "Lady Uika", ButtonOptions{Variant: Ghost}) HoverCard(c, b, HoverCardOptions{OpenDelay: time.Millisecond}, func() { diff --git a/overlay_snapshot_test.go b/overlay_snapshot_test.go index 4388b69..edc40ef 100644 --- a/overlay_snapshot_test.go +++ b/overlay_snapshot_test.go @@ -1,56 +1,11 @@ package mujica import ( - "bytes" - "os" - "path/filepath" - "runtime" - "strings" - "testing" "time" "github.com/egoist/mygo/ui" ) -// overlaySnapshot is snapshot, with drive opening the real component through input before the capture. -func overlaySnapshot(t *testing.T, name string, w, h int, view func(c *ui.Context), drive func(tt *ui.Tester)) { - t.Helper() - for _, m := range []Mode{Light, Dark} { - ready := false - tt := ui.NewTester(func(c *ui.Context) { - Use(c, Settings{Mode: m}) - if ready { - view(c) - } - }, w, h) - tt.SetPreferences(ui.Preferences{ReduceMotion: true, TextScale: 1}) - ready = true - tt.Frame() - drive(tt) - got := encode(t, tt.Image()) - path := filepath.Join("testdata", "snapshots", runtime.GOOS, name+"-"+strings.ToLower(m.String())+".png") - if *update { - if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(path, got, 0o644); err != nil { - t.Fatal(err) - } - continue - } - want, err := os.ReadFile(path) - if err != nil { - t.Fatalf("%v (run go test -update)", err) - } - if !bytes.Equal(got, want) { - if err := os.WriteFile(path+".got.png", got, 0o644); err != nil { - t.Fatal(err) - } - t.Errorf("%s differs; see %s.got.png", path, path) - } - } -} - // overlayUntil draws frames until cond holds, for at most 5 s of wall time. func overlayUntil(tt *ui.Tester, cond func() bool) bool { end := time.Now().Add(5 * time.Second) diff --git a/snapshot_test.go b/snapshot_test.go index 73425b0..acab2e2 100644 --- a/snapshot_test.go +++ b/snapshot_test.go @@ -18,6 +18,12 @@ var update = flag.Bool("update", false, "rewrite snapshots") // snapshot compares view in both themes with testdata/snapshots//-.png. func snapshot(t *testing.T, name string, w, h int, view func(c *ui.Context)) { + t.Helper() + snapshotAfter(t, name, w, h, view, nil) +} + +// snapshotAfter is snapshot with drive sending input before the capture. +func snapshotAfter(t *testing.T, name string, w, h int, view func(c *ui.Context), drive func(tt *ui.Tester)) { t.Helper() for _, m := range []Mode{Light, Dark} { ready := false @@ -31,6 +37,9 @@ func snapshot(t *testing.T, name string, w, h int, view func(c *ui.Context)) { tt.SetPreferences(ui.Preferences{ReduceMotion: true, TextScale: 1}) ready = true tt.Frame() + if drive != nil { + drive(tt) + } got := encode(t, tt.Image()) path := filepath.Join("testdata", "snapshots", runtime.GOOS, name+"-"+strings.ToLower(m.String())+".png") if *update { diff --git a/tabs_test.go b/tabs_test.go index d395ae2..5148ea5 100644 --- a/tabs_test.go +++ b/tabs_test.go @@ -1,11 +1,7 @@ package mujica import ( - "bytes" "image/color" - "os" - "path/filepath" - "runtime" "strings" "testing" "time" @@ -159,38 +155,6 @@ func TestTabsSnapshot(t *testing.T) { } } -// tabsStateSnapshot compares tabsView after act in both themes with -.png. -func tabsStateSnapshot(t *testing.T, name string, act func(tt *ui.Tester)) { - t.Helper() - for _, m := range []Mode{Light, Dark} { - tt := ui.NewTester(func(c *ui.Context) { - Use(c, Settings{Mode: m}) - tabsView(c) - }, 520, 300) - tt.SetPreferences(ui.Preferences{ReduceMotion: true, TextScale: 1}) - act(tt) - tt.Frame() - got := encode(t, tt.Image()) - path := filepath.Join("testdata", "snapshots", runtime.GOOS, name+"-"+strings.ToLower(m.String())+".png") - if *update { - if err := os.WriteFile(path, got, 0o644); err != nil { - t.Fatal(err) - } - continue - } - want, err := os.ReadFile(path) - if err != nil { - t.Fatalf("%v (run go test -update)", err) - } - if !bytes.Equal(got, want) { - if err := os.WriteFile(path+".got.png", got, 0o644); err != nil { - t.Fatal(err) - } - t.Errorf("%s differs; see %s.got.png", path, path) - } - } -} - func TestTabsStateSnapshots(t *testing.T) { center := func(tt *ui.Tester, s string) (float32, float32) { r, ok := tt.Find(s) @@ -199,9 +163,9 @@ func TestTabsStateSnapshots(t *testing.T) { } return r.X + r.W/2, r.Y + r.H/2 } - tabsStateSnapshot(t, "tabs-hover", func(tt *ui.Tester) { tt.Move(center(tt, "Members")) }) - tabsStateSnapshot(t, "tabs-pressed", func(tt *ui.Tester) { tt.Press(center(tt, "Settings")) }) - tabsStateSnapshot(t, "tabs-focus", func(tt *ui.Tester) { + snapshotAfter(t, "tabs-hover", 520, 300, tabsView, func(tt *ui.Tester) { tt.Move(center(tt, "Members")) }) + snapshotAfter(t, "tabs-pressed", 520, 300, tabsView, func(tt *ui.Tester) { tt.Press(center(tt, "Settings")) }) + snapshotAfter(t, "tabs-focus", 520, 300, tabsView, func(tt *ui.Tester) { tt.Key(0, ui.KeyTab) tt.Key(0, ui.KeyRight) }) diff --git a/tooltip_test.go b/tooltip_test.go index 8f68a89..3114530 100644 --- a/tooltip_test.go +++ b/tooltip_test.go @@ -99,7 +99,7 @@ func TestTooltipScalesWithText(t *testing.T) { } func TestTooltipSnapshot(t *testing.T) { - overlaySnapshot(t, "tooltip", 360, 140, func(c *ui.Context) { + snapshotAfter(t, "tooltip", 360, 140, func(c *ui.Context) { ui.Column(c).Padding(24).AlignItems(ui.Start).Children(func() { b := Button(c, "Seal", ButtonOptions{Variant: Secondary}) Tooltip(c, b, "Seal the letter with wax", TooltipOptions{Delay: time.Millisecond})