Files
MujicaUI/dialog_test.go
T

229 lines
5.8 KiB
Go

package mujica
import (
"testing"
"time"
"github.com/egoist/mygo/ui"
"mujicaui/theme"
)
type dialogApp struct {
open bool
opts DialogOptions
saved int
name string
densities theme.Density
}
func (a *dialogApp) view(c *ui.Context) {
Use(c, Settings{Mode: Light, Density: a.densities})
if Button(c, "Rename", ButtonOptions{}).Clicked() {
a.open = true
}
a.opts.Actions = func() {
if Button(c, "Cancel", ButtonOptions{Variant: Secondary}).Clicked() {
a.open = false
}
if Button(c, "Save", ButtonOptions{}).Clicked() {
a.saved++
a.open = false
}
}
Dialog(c, &a.open, a.opts, func() {
ui.TextInput(c, &a.name)
})
}
func newDialogApp(opts DialogOptions) (*dialogApp, *ui.Tester) {
opts.Title = "Rename"
a := &dialogApp{opts: opts}
tt := ui.NewTester(a.view, 600, 400)
tt.SetPreferences(ui.Preferences{ReduceMotion: true, TextScale: 1})
return a, tt
}
func TestDialogOpenFocusTrapRestore(t *testing.T) {
a, tt := newDialogApp(DialogOptions{Description: "Pick a new name."})
if err := tt.Click("Rename"); err != nil {
t.Fatal(err)
}
if !a.open || !tt.HasText("Pick a new name.") {
t.Fatalf("open %v, texts %q", a.open, tt.Texts())
}
if !tt.Focused("Close") {
t.Fatalf("focus did not move into the dialog")
}
// Tab cycles Close, input, Cancel, Save and back to Close.
for range 3 {
tt.Key(0, ui.KeyTab)
}
if !tt.Focused("Save") {
t.Fatalf("tab order left the dialog")
}
tt.Key(0, ui.KeyTab)
if !tt.Focused("Close") {
t.Fatalf("tab did not wrap inside the dialog")
}
tt.Key(0, ui.KeyEscape)
if a.open {
t.Fatal("Escape did not close")
}
if !tt.Focused("Rename") {
t.Fatal("focus not restored to the opener")
}
}
func TestDialogActionsAndClose(t *testing.T) {
a, tt := newDialogApp(DialogOptions{})
_ = tt.Click("Rename")
if err := tt.Click("Save"); err != nil {
t.Fatal(err)
}
if a.saved != 1 || a.open {
t.Fatalf("saved %d open %v", a.saved, a.open)
}
_ = tt.Click("Rename")
if err := tt.Click("Close"); err != nil {
t.Fatal(err)
}
if a.open || a.saved != 1 {
t.Fatalf("close button: open %v saved %d", a.open, a.saved)
}
}
func TestDialogCloseRules(t *testing.T) {
a, tt := newDialogApp(DialogOptions{})
_ = tt.Click("Rename")
tt.ClickAt(10, 390)
if a.open {
t.Fatal("backdrop click did not close")
}
a, tt = newDialogApp(DialogOptions{KeepOnBackdrop: true, KeepOnEscape: true, HideClose: true})
_ = tt.Click("Rename")
tt.ClickAt(10, 390)
tt.Key(0, ui.KeyEscape)
if !a.open {
t.Fatal("kept dialog closed")
}
if tt.HasText("Close") {
t.Fatal("close button shown with HideClose")
}
if _, ok := tt.Find("Close"); ok {
t.Fatal("close button present with HideClose")
}
}
func TestDialogEscapeGoesToNestedPopoverFirst(t *testing.T) {
open, inner := true, false
tt := ui.NewTester(func(c *ui.Context) {
Use(c, Settings{})
Dialog(c, &open, DialogOptions{Title: "Outer"}, func() {
b := Button(c, "More", ButtonOptions{})
if b.Clicked() {
inner = true
}
Popover(c, b, &inner, PopoverOptions{}, func() { ui.Text(c, "Inner") })
})
}, 600, 400)
_ = tt.Click("More")
if !inner {
t.Fatal("popover did not open")
}
tt.Key(0, ui.KeyEscape)
if inner || !open {
t.Fatalf("after one Escape inner %v outer %v", inner, open)
}
tt.Key(0, ui.KeyEscape)
if open {
t.Fatal("second Escape did not close the dialog")
}
}
func TestDialogNeedsTitle(t *testing.T) {
defer func() {
if recover() == nil {
t.Fatal("no panic")
}
}()
open := true
ui.NewTester(func(c *ui.Context) {
Use(c, Settings{})
Dialog(c, &open, DialogOptions{}, nil)
}, 300, 200)
}
func dialogSnapshotView(d theme.Density, decorated bool) func(c *ui.Context) {
return func(c *ui.Context) {
mode := Light
if Tokens(c).Dark {
mode = Dark
}
Use(c, Settings{Mode: mode, Density: d})
open := true
name := "Ophelia"
ui.Column(c).Padding(24).Children(func() { ui.Text(c, "Behind the dialog") })
Dialog(c, &open, DialogOptions{
Title: "Rename the chamber", Description: "The new name shows in every hall.", Decorated: decorated,
Actions: func() {
Button(c, "Cancel", ButtonOptions{Variant: Secondary})
Button(c, "Rename", ButtonOptions{})
},
}, func() { ui.TextInput(c, &name) })
}
}
func TestDialogEscapeHidesTooltipBeforeClosing(t *testing.T) {
open := true
tt := ui.NewTester(func(c *ui.Context) {
Use(c, Settings{})
Dialog(c, &open, DialogOptions{Title: "Outer", HideClose: true}, func() {
b := Button(c, "Seal", ButtonOptions{})
Tooltip(c, b, "Seal with wax", TooltipOptions{Delay: time.Millisecond})
})
}, 600, 400)
tt.Key(0, ui.KeyTab) // keyboard focus on Seal
if !overlayUntil(tt, func() bool { return tt.HasText("Seal with wax") }) {
t.Fatal("tooltip did not show in the dialog")
}
tt.Key(0, ui.KeyEscape)
if tt.HasText("Seal with wax") || !open {
t.Fatalf("first Escape: tip shown %v, dialog open %v", tt.HasText("Seal with wax"), open)
}
tt.Key(0, ui.KeyEscape)
if open {
t.Fatal("second Escape did not close the dialog")
}
}
func TestDialogFocusFallsBackWhenOpenerIsGone(t *testing.T) {
open, gone := false, false
tt := ui.NewTester(func(c *ui.Context) {
Use(c, Settings{})
ui.Column(c).Children(func() {
Button(c, "First", ButtonOptions{})
if !gone && Button(c, "Open", ButtonOptions{}).Clicked() {
open, gone = true, true
}
Dialog(c, &open, DialogOptions{Title: "Gone"}, nil)
Button(c, "Next", ButtonOptions{})
})
}, 600, 400)
_ = tt.Click("Open")
tt.Key(0, ui.KeyEscape)
if open {
t.Fatal("Escape did not close")
}
tt.Key(0, ui.KeyTab)
if !tt.Focused("Next") {
t.Fatal("focus did not fall back to the dialog's place in the window")
}
}
func TestDialogSnapshot(t *testing.T) {
snapshot(t, "dialog", 560, 360, dialogSnapshotView(theme.Default, true))
snapshot(t, "dialog-compact", 560, 360, dialogSnapshotView(theme.Compact, false))
snapshot(t, "dialog-comfortable", 560, 400, dialogSnapshotView(theme.Comfortable, true))
}