203 lines
5.8 KiB
Go
203 lines
5.8 KiB
Go
package mujica
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/egoist/mygo/ui"
|
|
)
|
|
|
|
type formProbe struct {
|
|
st FormState
|
|
name, email string
|
|
tags []string
|
|
asyncCalls []uint64
|
|
asyncValues []string
|
|
submits, resets int
|
|
horizontal bool
|
|
useAsync bool
|
|
}
|
|
|
|
func (p *formProbe) run(c *ui.Context) {
|
|
Use(c, Settings{})
|
|
p.view(c)
|
|
}
|
|
|
|
func (p *formProbe) view(c *ui.Context) {
|
|
res := Form(c, &p.st, FormOptions{Horizontal: p.horizontal}, func(f *FormScope) {
|
|
FormItem(f, "name", &p.name, FormItemOptions[string]{Label: "Name", Required: true, Initial: "Sakiko"}, func() *ui.Element {
|
|
return InputGroup(c, &p.name, InputGroupOptions{Invalid: p.st.Error("name") != ""}).Input
|
|
})
|
|
opts := FormItemOptions[string]{Label: "Email", Validate: func(v string) string {
|
|
if v != "" && !strings.Contains(v, "@") {
|
|
return "Enter an email address."
|
|
}
|
|
return ""
|
|
}}
|
|
if p.useAsync {
|
|
opts.Async = func(v string, version uint64) {
|
|
p.asyncCalls = append(p.asyncCalls, version)
|
|
p.asyncValues = append(p.asyncValues, v)
|
|
}
|
|
}
|
|
FormItem(f, "email", &p.email, opts, func() *ui.Element {
|
|
return InputGroup(c, &p.email, InputGroupOptions{Invalid: p.st.Error("email") != ""}).Input
|
|
})
|
|
FormItem(f, "tags", &p.tags, FormItemOptions[[]string]{Label: "Tags", Required: true, Initial: []string{"rose"}}, func() *ui.Element {
|
|
return TagsInput(c, &p.tags, TagsInputOptions{}).Input
|
|
})
|
|
})
|
|
if res.Submitted() {
|
|
p.submits++
|
|
}
|
|
if res.Reset() {
|
|
p.resets++
|
|
}
|
|
}
|
|
|
|
func TestFormBlurValidationAndUntouchedFields(t *testing.T) {
|
|
p := &formProbe{name: "Sakiko", tags: []string{"rose"}}
|
|
tt := ui.NewTester(p.run, 600, 500)
|
|
_ = tt.Click("Email")
|
|
tt.Type("mutsumi")
|
|
if tt.HasText("Enter an email address.") {
|
|
t.Fatal("error before blur")
|
|
}
|
|
tt.Key(0, ui.KeyTab)
|
|
if !tt.HasText("Enter an email address.") {
|
|
t.Fatal("no error after blur")
|
|
}
|
|
if tt.HasText("Required") {
|
|
t.Fatal("untouched field shows an error")
|
|
}
|
|
_ = tt.Click("Email")
|
|
tt.Type("@court")
|
|
if tt.HasText("Enter an email address.") || p.email != "mutsumi@court" {
|
|
t.Fatalf("touched field did not revalidate: %q", p.email)
|
|
}
|
|
}
|
|
|
|
func TestFormSubmitFailureFocusesFirstErrorAndKeepsValues(t *testing.T) {
|
|
p := &formProbe{email: "bad"}
|
|
tt := ui.NewTester(p.run, 600, 500)
|
|
if err := tt.Click("Submit"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if p.submits != 0 || !tt.HasText("Required") || !tt.HasText("Enter an email address.") {
|
|
t.Fatalf("submits %d texts %q", p.submits, tt.Texts())
|
|
}
|
|
if !tt.Focused("Name *") || p.email != "bad" {
|
|
t.Fatal("first error not focused or value lost")
|
|
}
|
|
if got := tt.Announcements(); len(got) == 0 || got[len(got)-1] != "Some fields need attention" {
|
|
t.Fatalf("announcements %q", got)
|
|
}
|
|
}
|
|
|
|
func TestFormSubmitOnceAndEndSubmit(t *testing.T) {
|
|
p := &formProbe{name: "Uika", tags: []string{"x"}}
|
|
tt := ui.NewTester(p.run, 600, 500)
|
|
_ = tt.Click("Submit")
|
|
if p.submits != 1 || !p.st.Submitting() {
|
|
t.Fatalf("submits %d", p.submits)
|
|
}
|
|
_ = tt.Click("Submit")
|
|
p.st.Submit()
|
|
tt.Frame()
|
|
if p.submits != 1 {
|
|
t.Fatalf("re-entered: %d", p.submits)
|
|
}
|
|
p.st.EndSubmit("The server is away.")
|
|
tt.Frame()
|
|
if !tt.HasText("The server is away.") || p.name != "Uika" {
|
|
t.Fatal("form error not shown")
|
|
}
|
|
_ = tt.Click("Submit")
|
|
if p.submits != 2 || tt.HasText("The server is away.") {
|
|
t.Fatalf("second submit: %d", p.submits)
|
|
}
|
|
}
|
|
|
|
func TestFormAsyncStaleResultsAndPendingSubmit(t *testing.T) {
|
|
p := &formProbe{name: "Uika", tags: []string{"x"}, useAsync: true}
|
|
tt := ui.NewTester(p.run, 600, 500)
|
|
_ = tt.Click("Email")
|
|
tt.Type("a@b")
|
|
tt.Key(0, ui.KeyTab)
|
|
if len(p.asyncCalls) != 1 || p.asyncValues[0] != "a@b" || !tt.HasText("Checking…") {
|
|
t.Fatalf("async calls %v", p.asyncCalls)
|
|
}
|
|
old := p.asyncCalls[0]
|
|
_ = tt.Click("Email")
|
|
tt.Type("c")
|
|
if p.st.Resolve("email", old, "Taken") {
|
|
t.Fatal("stale result accepted")
|
|
}
|
|
tt.Frame()
|
|
if tt.HasText("Taken") {
|
|
t.Fatal("stale result shown")
|
|
}
|
|
_ = tt.Click("Submit")
|
|
if len(p.asyncCalls) != 2 || p.asyncValues[1] != "a@bc" || p.submits != 0 {
|
|
t.Fatalf("submit did not wait for the new check: %v %d", p.asyncValues, p.submits)
|
|
}
|
|
if !p.st.Resolve("email", p.st.Version("email"), "") {
|
|
t.Fatal("current result refused")
|
|
}
|
|
tt.Frame()
|
|
if p.submits != 1 {
|
|
t.Fatalf("submit did not finish after the check: %d", p.submits)
|
|
}
|
|
}
|
|
|
|
func TestFormAsyncErrorBlocksSubmit(t *testing.T) {
|
|
p := &formProbe{name: "Uika", tags: []string{"x"}, email: "a@b", useAsync: true}
|
|
tt := ui.NewTester(p.run, 600, 500)
|
|
_ = tt.Click("Submit")
|
|
p.st.Resolve("email", p.st.Version("email"), "Already registered")
|
|
tt.Frame()
|
|
tt.Frame()
|
|
if p.submits != 0 || !tt.HasText("Already registered") || !tt.Focused("Email") {
|
|
t.Fatalf("submits %d texts %q", p.submits, tt.Texts())
|
|
}
|
|
}
|
|
|
|
func TestFormResetRestoresInitialValues(t *testing.T) {
|
|
p := &formProbe{name: "", email: "bad", tags: nil}
|
|
tt := ui.NewTester(p.run, 600, 500)
|
|
_ = tt.Click("Submit")
|
|
if err := tt.Click("Reset"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tt.Frame()
|
|
if p.name != "Sakiko" || p.email != "" || len(p.tags) != 1 || p.tags[0] != "rose" || p.resets != 1 {
|
|
t.Fatalf("reset values %q %q %q", p.name, p.email, p.tags)
|
|
}
|
|
if tt.HasText("Required") || p.st.Error("email") != "" {
|
|
t.Fatal("errors survive reset")
|
|
}
|
|
}
|
|
|
|
func TestFormHorizontalLayout(t *testing.T) {
|
|
p := &formProbe{horizontal: true}
|
|
tt := ui.NewTester(p.run, 600, 500)
|
|
name, _ := tt.Find("Name *")
|
|
email, _ := tt.Find("Email")
|
|
if name.X+name.W != email.X+email.W {
|
|
t.Fatalf("labels not right-aligned: %v %v", name, email)
|
|
}
|
|
}
|
|
|
|
func TestFormSnapshot(t *testing.T) {
|
|
p := &formProbe{name: "Sakiko Togawa", email: "oblivionis", tags: []string{"Ave Mujica"}}
|
|
snapshot(t, "form", 560, 420, func(c *ui.Context) {
|
|
ui.Column(c).Padding(24).Children(func() {
|
|
p.view(c)
|
|
if !p.st.tried {
|
|
p.st.Submit()
|
|
c.Invalidate()
|
|
}
|
|
})
|
|
})
|
|
}
|