Fields created via Context.Field are now tracked on the page context, so ValidateAll() and ResetFields() with no arguments operate on all fields by default. Explicit field args still work for selective use. Also switches MinLen/MaxLen to utf8.RuneCountInString for correct unicode handling and replaces fmt.Errorf with errors.New where format strings are unnecessary.
207 lines
4.6 KiB
Go
207 lines
4.6 KiB
Go
package via
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/ryanhamamura/via/h"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func newTestField(initial any, rules ...Rule) *Field {
|
|
v := New()
|
|
var f *Field
|
|
v.Page("/", func(c *Context) {
|
|
f = c.Field(initial, rules...)
|
|
c.View(func() h.H { return h.Div() })
|
|
})
|
|
return f
|
|
}
|
|
|
|
func TestFieldCreation(t *testing.T) {
|
|
f := newTestField("hello", Required())
|
|
assert.Equal(t, "hello", f.String())
|
|
assert.NotEmpty(t, f.ID())
|
|
}
|
|
|
|
func TestFieldSignalDelegation(t *testing.T) {
|
|
f := newTestField(42)
|
|
assert.Equal(t, "42", f.String())
|
|
assert.Equal(t, 42, f.Int())
|
|
|
|
f.SetValue("new")
|
|
assert.Equal(t, "new", f.String())
|
|
|
|
// Bind returns an h.H element
|
|
assert.NotNil(t, f.Bind())
|
|
}
|
|
|
|
func TestFieldValidateSingleRule(t *testing.T) {
|
|
f := newTestField("", Required())
|
|
assert.False(t, f.Validate())
|
|
assert.True(t, f.HasError())
|
|
assert.Equal(t, "This field is required", f.FirstError())
|
|
|
|
f.SetValue("ok")
|
|
assert.True(t, f.Validate())
|
|
assert.False(t, f.HasError())
|
|
assert.Equal(t, "", f.FirstError())
|
|
}
|
|
|
|
func TestFieldValidateMultipleRules(t *testing.T) {
|
|
f := newTestField("ab", Required(), MinLen(3))
|
|
assert.False(t, f.Validate())
|
|
errs := f.Errors()
|
|
assert.Len(t, errs, 1)
|
|
assert.Equal(t, "Must be at least 3 characters", errs[0])
|
|
|
|
f.SetValue("")
|
|
assert.False(t, f.Validate())
|
|
errs = f.Errors()
|
|
assert.Len(t, errs, 2)
|
|
}
|
|
|
|
func TestFieldErrors(t *testing.T) {
|
|
f := newTestField("")
|
|
assert.Nil(t, f.Errors())
|
|
assert.False(t, f.HasError())
|
|
assert.Equal(t, "", f.FirstError())
|
|
}
|
|
|
|
func TestFieldAddError(t *testing.T) {
|
|
f := newTestField("ok")
|
|
f.AddError("username taken")
|
|
assert.True(t, f.HasError())
|
|
assert.Equal(t, "username taken", f.FirstError())
|
|
assert.Len(t, f.Errors(), 1)
|
|
}
|
|
|
|
func TestFieldClearErrors(t *testing.T) {
|
|
f := newTestField("", Required())
|
|
f.Validate()
|
|
assert.True(t, f.HasError())
|
|
f.ClearErrors()
|
|
assert.False(t, f.HasError())
|
|
}
|
|
|
|
func TestFieldReset(t *testing.T) {
|
|
f := newTestField("initial", Required(), MinLen(3))
|
|
f.SetValue("changed")
|
|
f.AddError("some error")
|
|
|
|
f.Reset()
|
|
assert.Equal(t, "initial", f.String())
|
|
assert.False(t, f.HasError())
|
|
}
|
|
|
|
func TestValidateAll(t *testing.T) {
|
|
v := New()
|
|
v.Page("/", func(c *Context) {
|
|
c.Field("", Required(), MinLen(3))
|
|
c.Field("", Required(), Email())
|
|
c.View(func() h.H { return h.Div() })
|
|
|
|
// both empty → both fail
|
|
assert.False(t, c.ValidateAll())
|
|
})
|
|
|
|
v2 := New()
|
|
v2.Page("/", func(c *Context) {
|
|
c.Field("joe", Required(), MinLen(3))
|
|
c.Field("joe@x.com", Required(), Email())
|
|
c.View(func() h.H { return h.Div() })
|
|
|
|
assert.True(t, c.ValidateAll())
|
|
})
|
|
}
|
|
|
|
func TestValidateAllPartialFailure(t *testing.T) {
|
|
v := New()
|
|
v.Page("/", func(c *Context) {
|
|
good := c.Field("valid", Required())
|
|
bad := c.Field("", Required())
|
|
c.View(func() h.H { return h.Div() })
|
|
|
|
ok := c.ValidateAll()
|
|
assert.False(t, ok)
|
|
assert.False(t, good.HasError())
|
|
assert.True(t, bad.HasError())
|
|
})
|
|
}
|
|
|
|
func TestValidateAllSelectiveArgs(t *testing.T) {
|
|
v := New()
|
|
v.Page("/", func(c *Context) {
|
|
a := c.Field("", Required())
|
|
b := c.Field("ok", Required())
|
|
cField := c.Field("", Required())
|
|
c.View(func() h.H { return h.Div() })
|
|
|
|
// only validate a and b — cField should be untouched
|
|
ok := c.ValidateAll(a, b)
|
|
assert.False(t, ok)
|
|
assert.True(t, a.HasError())
|
|
assert.False(t, b.HasError())
|
|
assert.False(t, cField.HasError(), "unselected field should not be validated")
|
|
})
|
|
}
|
|
|
|
func TestResetFields(t *testing.T) {
|
|
v := New()
|
|
v.Page("/", func(c *Context) {
|
|
a := c.Field("a", Required())
|
|
b := c.Field("b", Required())
|
|
c.View(func() h.H { return h.Div() })
|
|
|
|
a.SetValue("changed-a")
|
|
b.SetValue("changed-b")
|
|
a.AddError("err")
|
|
|
|
c.ResetFields()
|
|
assert.Equal(t, "a", a.String())
|
|
assert.Equal(t, "b", b.String())
|
|
assert.False(t, a.HasError())
|
|
})
|
|
}
|
|
|
|
func TestResetFieldsSelectiveArgs(t *testing.T) {
|
|
v := New()
|
|
v.Page("/", func(c *Context) {
|
|
a := c.Field("a")
|
|
b := c.Field("b")
|
|
c.View(func() h.H { return h.Div() })
|
|
|
|
a.SetValue("changed-a")
|
|
b.SetValue("changed-b")
|
|
|
|
// only reset a
|
|
c.ResetFields(a)
|
|
assert.Equal(t, "a", a.String())
|
|
assert.Equal(t, "changed-b", b.String(), "unselected field should not be reset")
|
|
})
|
|
}
|
|
|
|
func TestFieldValidateClearsPreviousErrors(t *testing.T) {
|
|
f := newTestField("", Required())
|
|
f.Validate()
|
|
assert.True(t, f.HasError())
|
|
|
|
f.SetValue("ok")
|
|
f.Validate()
|
|
assert.False(t, f.HasError())
|
|
}
|
|
|
|
func TestFieldCustomValidator(t *testing.T) {
|
|
f := newTestField("bad", Custom(func(val string) error {
|
|
if val == "bad" {
|
|
return fmt.Errorf("no bad words")
|
|
}
|
|
return nil
|
|
}))
|
|
assert.False(t, f.Validate())
|
|
assert.Equal(t, "no bad words", f.FirstError())
|
|
|
|
f.SetValue("good")
|
|
assert.True(t, f.Validate())
|
|
}
|