Tests: one snapshot helper (snapshot, snapshotAfter) replaces three copies

This commit is contained in:
ZacharyZhang-NY committed 2026-10-05 13:19:52 -04:00
1 parent d934918fbb
commit b8242d4e28
8 files changed
+24 -96

No files matched your search

+8 -8
View File
@@ -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")) })
}
+1 -1
View File
@@ -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") })
+1 -1
View File
@@ -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)
})
+1 -1
View File
@@ -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() {
-45
View File
@@ -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)
+9
View File
@@ -18,6 +18,12 @@ var update = flag.Bool("update", false, "rewrite snapshots")
// snapshot compares view in both themes with testdata/snapshots/<os>/<name>-<mode>.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 {
+3 -39
View File
@@ -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 <name>-<mode>.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)
})
+1 -1
View File
@@ -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})