Documentation
¶
Overview ¶
Package testastic provides expressive testing utilities for Go.
Testastic offers structured comparison for JSON, YAML, HTML, and plain text documents with support for template-based matchers, alongside general-purpose assertions for values, errors, strings, and collections.
JSON, YAML, HTML, and File Assertions ¶
Compare API responses or rendered documents against expected files with flexible matching:
testastic.AssertJSON(t, "testdata/user.expected.json", resp.Body) testastic.AssertYAML(t, "testdata/config.expected.yaml", configBytes) testastic.AssertHTML(t, "testdata/page.expected.html", renderedHTML) testastic.AssertFile(t, "testdata/output.expected.txt", actualString)
Input types by assertion:
- AssertJSON and AssertYAML: string, []byte, io.Reader, or any struct (auto-marshaled)
- AssertHTML: string, []byte, io.Reader, or fmt.Stringer
- AssertFile: string, []byte, or io.Reader
Expected files support template matchers for dynamic values:
{
"id": "{{anyUUID}}",
"count": "{{anyInt}}",
"email": "{{regex `^[a-z]+@example\\.com$`}}",
"status": "{{oneOf \"pending\" \"active\"}}",
"timestamp": "{{ignore}}"
}
Available built-in matchers:
- {{anyString}} - matches any string
- {{anyInt}} - matches any integer
- {{anyFloat}} - matches any number
- {{anyBool}} - matches any boolean
- {{anyValue}} - matches any value including null
- {{anyUUID}} - matches UUID strings (RFC 4122)
- {{anyDateTime}} - matches ISO 8601 datetime strings
- {{anyURL}} - matches URL strings
- {{ignore}} - skips the field during comparison
- {{regex `pattern`}} - matches against a regular expression
- {{oneOf "a" "b"}} - matches one of the specified values
Comparison Options ¶
Configure comparison behavior with options:
testastic.AssertJSON(t, expected, actual,
testastic.IgnoreArrayOrder(), // ignore order globally
testastic.IgnoreArrayOrderAt("$.items"), // ignore order at path
testastic.IgnoreFields("id", "timestamp"), // exclude fields
testastic.Message("user creation response"), // custom failure message
)
HTML-Specific Options ¶
Additional options are available for HTML comparison:
testastic.AssertHTML(t, expected, actual,
testastic.IgnoreHTMLComments(), // exclude comments
testastic.PreserveWhitespace(), // disable whitespace normalization
testastic.IgnoreChildOrder(), // order-insensitive globally
testastic.IgnoreChildOrderAt("html > body > ul"), // order-insensitive at path
testastic.IgnoreElements("script", "style"), // exclude elements by tag
testastic.IgnoreAttributes("class", "style"), // exclude attributes globally
testastic.IgnoreAttributeAt("html > body > div@id"), // exclude attribute at path
)
Updating Expected Files ¶
When API responses change, update expected files automatically:
go test -update # or TESTASTIC_UPDATE=true go test
Basic Assertions ¶
General-purpose assertions for common test scenarios:
testastic.Equal(t, expected, actual) testastic.NotEqual(t, unexpected, actual) testastic.DeepEqual(t, expected, actual) testastic.Nil(t, value) testastic.NotNil(t, value) testastic.True(t, condition) testastic.False(t, condition)
Error Assertions ¶
testastic.NoError(t, err) testastic.Error(t, err) testastic.ErrorIs(t, err, target) testastic.ErrorAs(t, err, &pathErr) testastic.ErrorContains(t, err, "substring")
Panic Assertions ¶
testastic.Panics(t, func() { panic("boom") })
testastic.NotPanics(t, func() { safeFunc() })
Comparison Assertions ¶
testastic.Greater(t, a, b) testastic.GreaterOrEqual(t, a, b) testastic.Less(t, a, b) testastic.LessOrEqual(t, a, b) testastic.Between(t, value, min, max)
String Assertions ¶
testastic.Contains(t, s, "substring") testastic.NotContains(t, s, "substring") testastic.HasPrefix(t, s, "prefix") testastic.HasSuffix(t, s, "suffix") testastic.Matches(t, s, `^\d+$`) testastic.StringEmpty(t, s) testastic.StringNotEmpty(t, s)
Collection Assertions ¶
testastic.Len(t, slice, 3) testastic.Empty(t, slice) testastic.NotEmpty(t, slice) testastic.SliceContains(t, slice, element) testastic.SliceNotContains(t, slice, element) testastic.SliceEqual(t, expected, actual) testastic.MapHasKey(t, m, "key") testastic.MapNotHasKey(t, m, "key") testastic.MapHasValue(t, m, "value") testastic.MapEqual(t, expected, actual)
Eventual Assertions ¶
For asynchronous operations, retry until a condition is met or timeout is reached. The condition is checked immediately, then at regular intervals (default 100ms).
testastic.Eventually(t, func() bool {
return server.IsReady()
}, 5*time.Second)
testastic.EventuallyTrue(t, func() bool {
return isReady
}, 3*time.Second)
testastic.EventuallyFalse(t, func() bool {
return server.IsProcessing()
}, 5*time.Second)
testastic.EventuallyEqual(t, "ready", func() string {
return service.Status()
}, 3*time.Second, testastic.WithInterval(50*time.Millisecond))
testastic.EventuallyNil(t, func() any {
return cache.Get("key")
}, 2*time.Second)
testastic.EventuallyNotNil(t, func() any {
return cache.Get("key")
}, 2*time.Second)
testastic.EventuallyNoError(t, func() error {
_, err := client.Ping()
return err
}, 5*time.Second)
testastic.EventuallyError(t, func() error {
return service.HealthCheck()
}, 3*time.Second)
Configure polling with WithInterval and WithMessage:
testastic.Eventually(t, condition, 5*time.Second,
testastic.WithInterval(50*time.Millisecond),
testastic.WithMessage("waiting for server startup"),
)
Custom Matchers ¶
Register custom matchers for domain-specific validation:
testastic.RegisterMatcher("customID", func(args string) (testastic.Matcher, error) {
return myCustomMatcher{}, nil
})
Then use in expected files: "id": "{{customID}}"
Index ¶
- func AssertFile[T any](tb testing.TB, expectedFile string, actual T, opts ...Option)
- func AssertHTML[T any](tb testing.TB, expectedFile string, actual T, opts ...Option)
- func AssertJSON[T any](tb testing.TB, expectedFile string, actual T, opts ...Option)
- func AssertYAML[T any](tb testing.TB, expectedFile string, actual T, opts ...Option)
- func Between[T cmp.Ordered](tb testing.TB, value, minVal, maxVal T)
- func Contains(tb testing.TB, s, substring string)
- func DeepEqual[T any](tb testing.TB, expected, actual T)
- func Empty(tb testing.TB, collection any)
- func Equal[T comparable](tb testing.TB, expected, actual T)
- func Error(tb testing.TB, err error)
- func ErrorAs(tb testing.TB, err error, target any)
- func ErrorContains(tb testing.TB, err error, substring string)
- func ErrorIs(tb testing.TB, err, target error)
- func Eventually(tb testing.TB, condition func() bool, timeout time.Duration, ...)
- func EventuallyEqual[T comparable](tb testing.TB, expected T, getValue func() T, timeout time.Duration, ...)
- func EventuallyError(tb testing.TB, getErr func() error, timeout time.Duration, ...)
- func EventuallyFalse(tb testing.TB, condition func() bool, timeout time.Duration, ...)
- func EventuallyNil(tb testing.TB, getValue func() any, timeout time.Duration, ...)
- func EventuallyNoError(tb testing.TB, getErr func() error, timeout time.Duration, ...)
- func EventuallyNotNil(tb testing.TB, getValue func() any, timeout time.Duration, ...)
- func EventuallyTrue(tb testing.TB, condition func() bool, timeout time.Duration, ...)
- func False(tb testing.TB, value bool)
- func Greater[T cmp.Ordered](tb testing.TB, a, b T)
- func GreaterOrEqual[T cmp.Ordered](tb testing.TB, a, b T)
- func HasPrefix(tb testing.TB, s, prefix string)
- func HasSuffix(tb testing.TB, s, suffix string)
- func Len(tb testing.TB, collection any, expected int)
- func Less[T cmp.Ordered](tb testing.TB, a, b T)
- func LessOrEqual[T cmp.Ordered](tb testing.TB, a, b T)
- func MapEqual[K comparable, V comparable](tb testing.TB, expected, actual map[K]V)
- func MapHasKey[K comparable, V any](tb testing.TB, m map[K]V, key K)
- func MapHasValue[K comparable, V comparable](tb testing.TB, m map[K]V, value V)
- func MapNotHasKey[K comparable, V any](tb testing.TB, m map[K]V, key K)
- func Matches(tb testing.TB, s, pattern string)
- func Nil(tb testing.TB, value any)
- func NoError(tb testing.TB, err error)
- func NotContains(tb testing.TB, s, substring string)
- func NotEmpty(tb testing.TB, collection any)
- func NotEqual[T comparable](tb testing.TB, unexpected, actual T)
- func NotNil(tb testing.TB, value any)
- func NotPanics(tb testing.TB, fn func())
- func Panics(tb testing.TB, fn func())
- func RegisterMatcher(name string, factory MatcherFactory)
- func SliceContains[T comparable](tb testing.TB, slice []T, element T)
- func SliceEqual[T comparable](tb testing.TB, expected, actual []T)
- func SliceNotContains[T comparable](tb testing.TB, slice []T, element T)
- func StringEmpty(tb testing.TB, s string)
- func StringNotEmpty(tb testing.TB, s string)
- func True(tb testing.TB, value bool)
- type EventuallyOption
- type Matcher
- type MatcherFactory
- type Option
- func IgnoreArrayOrder() Option
- func IgnoreArrayOrderAt(path string) Option
- func IgnoreAttributeAt(pathAttr string) Option
- func IgnoreAttributes(attrs ...string) Option
- func IgnoreChildOrder() Option
- func IgnoreChildOrderAt(path string) Option
- func IgnoreElements(tags ...string) Option
- func IgnoreFields(fields ...string) Option
- func IgnoreHTMLComments() Option
- func Message(msg string) Option
- func PreserveWhitespace() Option
- func Update() Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AssertFile ¶
AssertFile compares actual content against an expected file with template matcher support. Supports {{anyString}}, {{regex `pattern`}}, and other matchers inline within text.
Supported actual types: string, []byte, or io.Reader.
func AssertHTML ¶
AssertHTML compares actual HTML against an expected HTML file. T can be: []byte, string, io.Reader, or any type implementing fmt.Stringer.
Example:
testastic.AssertHTML(t, "testdata/user.expected.html", resp.Body) testastic.AssertHTML(t, "testdata/user.expected.html", htmlBytes) testastic.AssertHTML(t, "testdata/user.expected.html", htmlString)
func AssertJSON ¶
AssertJSON compares actual JSON against an expected JSON file. T can be: []byte, string, io.Reader, or any struct (auto-marshaled).
Example:
testastic.AssertJSON(t, "testdata/user.expected.json", resp.Body) testastic.AssertJSON(t, "testdata/user.expected.json", myUser) testastic.AssertJSON(t, "testdata/user.expected.json", jsonBytes)
Example ¶
package main
import (
"fmt"
)
func main() {
// In a test function:
//
// func TestUserAPI(t *testing.T) {
// resp, _ := http.Get("/api/user/123")
// defer resp.Body.Close()
//
// // Compare response body against expected file
// testastic.AssertJSON(t, "testdata/user.expected.json", resp.Body)
// }
//
// The expected file can contain matchers for dynamic values:
//
// {
// "id": "{{anyUUID}}",
// "name": "Alice",
// "email": "{{regex `^[a-z]+@example\\.com$`}}",
// "createdAt": "{{anyDateTime}}",
// "role": "{{oneOf \"admin\" \"user\"}}"
// }
//
// AssertJSON accepts []byte, string, io.Reader, or any struct:
//
// testastic.AssertJSON(t, "testdata/user.expected.json", userStruct)
// testastic.AssertJSON(t, "testdata/user.expected.json", jsonBytes)
// testastic.AssertJSON(t, "testdata/user.expected.json", jsonString)
fmt.Println("See godoc for usage examples")
}
Output: See godoc for usage examples
Example (WithOptions) ¶
package main
import (
"fmt"
)
func main() {
// Use options to customize comparison behavior:
//
// func TestListUsers(t *testing.T) {
// resp := getUsers()
//
// // Ignore array order when comparing lists
// testastic.AssertJSON(t, "testdata/users.expected.json", resp,
// testastic.IgnoreArrayOrder(),
// )
//
// // Ignore order only at specific paths
// testastic.AssertJSON(t, "testdata/response.expected.json", resp,
// testastic.IgnoreArrayOrderAt("$.data.items"),
// testastic.IgnoreArrayOrderAt("$.data.tags"),
// )
//
// // Exclude volatile fields from comparison
// testastic.AssertJSON(t, "testdata/user.expected.json", resp,
// testastic.IgnoreFields("id", "createdAt", "updatedAt"),
// )
//
// // Add context to failure messages
// testastic.AssertJSON(t, "testdata/user.expected.json", resp,
// testastic.Message("user creation response"),
// )
//
// // Combine multiple options
// testastic.AssertJSON(t, "testdata/complex.expected.json", resp,
// testastic.IgnoreArrayOrder(),
// testastic.IgnoreFields("timestamp"),
// testastic.Message("complex response validation"),
// )
// }
//
// Update expected files when API changes:
//
// go test -update
// # or use the Update option programmatically:
// testastic.AssertJSON(t, expected, actual, testastic.Update())
fmt.Println("See godoc for usage examples")
}
Output: See godoc for usage examples
func AssertYAML ¶
AssertYAML compares actual YAML against an expected YAML file. T can be: []byte, string, io.Reader, or any struct (auto-marshaled).
Example:
testastic.AssertYAML(t, "testdata/config.expected.yaml", configBytes) testastic.AssertYAML(t, "testdata/config.expected.yaml", myConfig) testastic.AssertYAML(t, "testdata/config.expected.yaml", resp.Body)
func Contains ¶
Contains asserts that s contains the given substring. Reports a non-fatal error on failure, displaying the string and missing substring.
func DeepEqual ¶
DeepEqual asserts that expected and actual are deeply equal using reflect.DeepEqual.
func Empty ¶
Empty asserts that the collection is empty. Works with slices, maps, strings, arrays, and channels.
func Equal ¶
func Equal[T comparable](tb testing.TB, expected, actual T)
Equal asserts that expected and actual are equal using the == operator. Reports a non-fatal error on failure, allowing the test to continue.
Example ¶
package main
import (
"fmt"
)
func main() {
// In a test function:
//
// func TestCalculation(t *testing.T) {
// result := Calculate(10, 20)
// testastic.Equal(t, 30, result)
//
// name := GetUserName(123)
// testastic.Equal(t, "Alice", name)
// }
//
// For complex types, use DeepEqual:
//
// func TestStructEquality(t *testing.T) {
// expected := User{Name: "Alice", Age: 30}
// actual := GetUser(123)
// testastic.DeepEqual(t, expected, actual)
// }
//
// Related assertions:
//
// testastic.NotEqual(t, unexpected, actual) // values must differ
// testastic.Nil(t, value) // value must be nil
// testastic.NotNil(t, value) // value must not be nil
// testastic.True(t, condition) // condition must be true
// testastic.False(t, condition) // condition must be false
fmt.Println("See godoc for usage examples")
}
Output: See godoc for usage examples
func Error ¶
Error asserts that err is not nil. Reports a non-fatal error on failure, allowing the test to continue.
func ErrorAs ¶ added in v0.1.0
ErrorAs asserts that err matches the target type using errors.As. The target must be a non-nil pointer to either an error interface or a concrete type that implements error.
var pathErr *os.PathError testastic.ErrorAs(t, err, &pathErr)
func ErrorContains ¶
ErrorContains asserts that err is non-nil and its message contains the given substring.
func Eventually ¶
func Eventually(tb testing.TB, condition func() bool, timeout time.Duration, opts ...EventuallyOption)
Eventually retries a condition function until it returns true or timeout is reached. The condition is checked immediately, then at regular intervals (default 100ms).
Example:
testastic.Eventually(t, func() bool {
return server.IsReady()
}, 5*time.Second)
testastic.Eventually(t, func() bool {
return len(queue) > 0
}, 2*time.Second, testastic.WithInterval(50*time.Millisecond))
Example ¶
package main
import (
"fmt"
)
func main() {
// In a test function, wait for an async condition:
//
// func TestServerStartup(t *testing.T) {
// go startServer()
//
// // Wait up to 5 seconds for server to be ready
// testastic.Eventually(t, func() bool {
// resp, err := http.Get("http://localhost:8080/health")
// return err == nil && resp.StatusCode == 200
// }, 5*time.Second)
// }
//
// Customize polling interval:
//
// testastic.Eventually(t, condition, 5*time.Second,
// testastic.WithInterval(50*time.Millisecond), // check every 50ms
// testastic.WithMessage("waiting for server"), // add context to failures
// )
//
// Type-specific variants provide better error messages:
//
// // Wait for specific value
// testastic.EventuallyEqual(t, "ready", func() string {
// return service.Status()
// }, 3*time.Second)
//
// // Wait for no error
// testastic.EventuallyNoError(t, func() error {
// _, err := client.Ping()
// return err
// }, 5*time.Second)
//
// // Wait for condition to become false
// testastic.EventuallyFalse(t, func() bool {
// return server.IsProcessing()
// }, 10*time.Second)
fmt.Println("See godoc for usage examples")
}
Output: See godoc for usage examples
func EventuallyEqual ¶
func EventuallyEqual[T comparable]( tb testing.TB, expected T, getValue func() T, timeout time.Duration, opts ...EventuallyOption, )
EventuallyEqual retries until expected equals the result of getValue.
Example:
testastic.EventuallyEqual(t, "ready", func() string {
return service.Status()
}, 3*time.Second)
func EventuallyError ¶
func EventuallyError(tb testing.TB, getErr func() error, timeout time.Duration, opts ...EventuallyOption)
EventuallyError retries until getErr returns a non-nil error.
Example:
testastic.EventuallyError(t, func() error {
return service.HealthCheck()
}, 3*time.Second)
func EventuallyFalse ¶
func EventuallyFalse(tb testing.TB, condition func() bool, timeout time.Duration, opts ...EventuallyOption)
EventuallyFalse retries until condition returns false.
Example:
testastic.EventuallyFalse(t, func() bool {
return server.IsProcessing()
}, 5*time.Second)
func EventuallyNil ¶
func EventuallyNil(tb testing.TB, getValue func() any, timeout time.Duration, opts ...EventuallyOption)
EventuallyNil retries until getValue returns nil.
Example:
testastic.EventuallyNil(t, func() any {
return cache.Get("key")
}, 2*time.Second)
func EventuallyNoError ¶
func EventuallyNoError(tb testing.TB, getErr func() error, timeout time.Duration, opts ...EventuallyOption)
EventuallyNoError retries until getErr returns nil.
Example:
testastic.EventuallyNoError(t, func() error {
_, err := client.Ping()
return err
}, 5*time.Second)
func EventuallyNotNil ¶
func EventuallyNotNil(tb testing.TB, getValue func() any, timeout time.Duration, opts ...EventuallyOption)
EventuallyNotNil retries until getValue returns a non-nil value.
Example:
testastic.EventuallyNotNil(t, func() any {
return cache.Get("key")
}, 2*time.Second)
func EventuallyTrue ¶
func EventuallyTrue(tb testing.TB, condition func() bool, timeout time.Duration, opts ...EventuallyOption)
EventuallyTrue is an alias for Eventually for readability.
Example:
testastic.EventuallyTrue(t, func() bool {
return isReady
}, 3*time.Second)
func False ¶
False asserts that value is false. Reports a non-fatal error on failure, allowing the test to continue.
func Greater ¶
Greater asserts that a > b using cmp.Ordered comparison.
func GreaterOrEqual ¶
GreaterOrEqual asserts that a >= b using cmp.Ordered comparison.
func Len ¶
Len asserts that the collection has the expected length. Works with slices, maps, strings, arrays, and channels.
func Less ¶
Less asserts that a < b using cmp.Ordered comparison.
func LessOrEqual ¶
LessOrEqual asserts that a <= b using cmp.Ordered comparison.
func MapEqual ¶
func MapEqual[K comparable, V comparable](tb testing.TB, expected, actual map[K]V)
MapEqual asserts that two maps have the same keys and values using == comparison. Reports the first differing key found.
func MapHasKey ¶
func MapHasKey[K comparable, V any](tb testing.TB, m map[K]V, key K)
MapHasKey asserts that the map contains the given key using map index lookup.
func MapHasValue ¶ added in v0.1.0
func MapHasValue[K comparable, V comparable](tb testing.TB, m map[K]V, value V)
MapHasValue asserts that the map contains the given value using == comparison. Performs a linear scan of all map values.
func MapNotHasKey ¶
func MapNotHasKey[K comparable, V any](tb testing.TB, m map[K]V, key K)
MapNotHasKey asserts that the map does not contain the given key using map index lookup.
func Nil ¶
Nil asserts that value is nil. Handles interface nil correctly by checking the underlying pointer for pointer, map, slice, channel, and func types.
func NoError ¶
NoError asserts that err is nil. Reports a non-fatal error on failure, displaying the error message.
func NotContains ¶
NotContains asserts that s does not contain the given substring.
func NotEmpty ¶
NotEmpty asserts that the collection is not empty. Works with slices, maps, strings, arrays, and channels.
func NotEqual ¶
func NotEqual[T comparable](tb testing.TB, unexpected, actual T)
NotEqual asserts that expected and actual are not equal using the == operator. Reports a non-fatal error on failure, allowing the test to continue.
func NotNil ¶
NotNil asserts that value is not nil. Handles interface nil correctly by checking the underlying pointer for pointer, map, slice, channel, and func types.
func NotPanics ¶ added in v0.1.0
NotPanics asserts that the function does not panic when called.
testastic.NotPanics(t, func() {
doSomethingSafe()
})
func Panics ¶ added in v0.1.0
Panics asserts that the function panics when called.
testastic.Panics(t, func() {
panic("something went wrong")
})
func RegisterMatcher ¶
func RegisterMatcher(name string, factory MatcherFactory)
RegisterMatcher registers a custom matcher factory with the given name. Once registered, the matcher can be used in expected files as {{name}} or {{name args}}.
Registration should typically happen in TestMain or an init function to ensure matchers are available before tests run.
Example without arguments:
testastic.RegisterMatcher("orderID", func(args string) (testastic.Matcher, error) {
return &orderIDMatcher{}, nil
})
// Use in expected file: "id": "{{orderID}}"
Example with arguments:
testastic.RegisterMatcher("minLength", func(args string) (testastic.Matcher, error) {
n, err := strconv.Atoi(strings.TrimSpace(args))
if err != nil {
return nil, fmt.Errorf("minLength requires integer argument: %w", err)
}
return &minLengthMatcher{min: n}, nil
})
// Use in expected file: "name": "{{minLength 3}}"
Custom matchers must implement the Matcher interface.
Example ¶
package main
import (
"fmt"
"github.com/monkescience/testastic"
)
func main() {
// Register a custom matcher for domain-specific validation.
// This is typically done in TestMain or an init function.
// Example: matcher for order IDs with format "ORD-XXXXXX"
testastic.RegisterMatcher("orderID", func(args string) (testastic.Matcher, error) {
return &orderIDMatcher{}, nil
})
// Example: matcher with arguments for currency amounts
testastic.RegisterMatcher("currency", func(args string) (testastic.Matcher, error) {
// args contains everything after the matcher name
// e.g., for {{currency USD}}, args would be "USD"
return ¤cyMatcher{currency: args}, nil
})
// Now use in expected JSON files:
//
// {
// "orderId": "{{orderID}}",
// "total": "{{currency USD}}"
// }
fmt.Println("Custom matchers registered")
}
// orderIDMatcher matches order IDs with format "ORD-XXXXXX".
type orderIDMatcher struct{}
func (m *orderIDMatcher) Match(actual any) bool {
s, ok := actual.(string)
if !ok || len(s) != 10 {
return false
}
return s[:4] == "ORD-"
}
func (m *orderIDMatcher) String() string {
return "{{orderID}}"
}
// currencyMatcher matches currency amounts for a specific currency.
type currencyMatcher struct {
currency string
}
func (m *currencyMatcher) Match(actual any) bool {
switch v := actual.(type) {
case float64:
return v >= 0
case int:
return v >= 0
}
return false
}
func (m *currencyMatcher) String() string {
return fmt.Sprintf("{{currency %s}}", m.currency)
}
Output: Custom matchers registered
func SliceContains ¶
func SliceContains[T comparable](tb testing.TB, slice []T, element T)
SliceContains asserts that slice contains element using == comparison. Reports a non-fatal error on failure, allowing the test to continue.
func SliceEqual ¶
func SliceEqual[T comparable](tb testing.TB, expected, actual []T)
SliceEqual asserts that two slices are equal (same length and elements in same order).
func SliceNotContains ¶
func SliceNotContains[T comparable](tb testing.TB, slice []T, element T)
SliceNotContains asserts that slice does not contain element using == comparison.
func StringEmpty ¶
StringEmpty asserts that s is an empty string ("").
func StringNotEmpty ¶
StringNotEmpty asserts that s is not an empty string ("").
Types ¶
type EventuallyOption ¶
type EventuallyOption func(*eventuallyConfig)
EventuallyOption configures Eventually behavior using functional options (see WithInterval and WithMessage).
func WithInterval ¶
func WithInterval(d time.Duration) EventuallyOption
WithInterval sets the polling interval between condition checks. Default is 100ms.
func WithMessage ¶
func WithMessage(msg string) EventuallyOption
WithMessage adds context to the timeout failure message, helping identify which Eventually assertion failed when a test has multiple.
type Matcher ¶
type Matcher interface {
// Match returns true if the actual value matches the expected pattern.
Match(actual any) bool
// String returns a description of what this matcher expects.
String() string
}
Matcher defines the interface for custom value matching.
func AnyDateTime ¶
func AnyDateTime() Matcher
AnyDateTime returns a matcher that matches ISO 8601 datetime strings.
func AnyFloat ¶
func AnyFloat() Matcher
AnyFloat returns a Matcher that accepts any numeric value (int or float types).
func AnyInt ¶
func AnyInt() Matcher
AnyInt returns a Matcher that accepts any integer value, including float64 values with no fractional part (as produced by JSON unmarshaling).
func AnyString ¶
func AnyString() Matcher
AnyString returns a Matcher that accepts any string value.
func AnyURL ¶
func AnyURL() Matcher
AnyURL returns a Matcher that accepts strings matching common HTTP/HTTPS URL patterns.
func AnyUUID ¶
func AnyUUID() Matcher
AnyUUID returns a matcher that matches UUID strings (RFC 4122).
func AnyValue ¶
func AnyValue() Matcher
AnyValue returns a matcher that matches any value including null.
type MatcherFactory ¶
MatcherFactory creates a Matcher from arguments extracted from a template expression. The args parameter contains everything after the matcher name in the template.
For {{myMatcher}}, args is an empty string. For {{myMatcher foo bar}}, args is "foo bar".
Return an error if the arguments are invalid. The error will be wrapped and reported during template parsing.
type Option ¶ added in v0.1.0
type Option func(*config)
Option configures the behavior of assertion functions. Use the provided option constructors (IgnoreFields, IgnoreArrayOrder, etc.) to create options.
func IgnoreArrayOrder ¶
func IgnoreArrayOrder() Option
IgnoreArrayOrder makes array comparison order-insensitive globally. When enabled, arrays are compared as sets: [1, 2, 3] equals [3, 1, 2].
Use IgnoreArrayOrderAt to apply order-insensitive comparison only at specific paths.
func IgnoreArrayOrderAt ¶
IgnoreArrayOrderAt makes array comparison order-insensitive at the specified path. Unlike IgnoreArrayOrder, this only affects the array at the given path.
Path format uses JSONPath-like syntax:
IgnoreArrayOrderAt("$.items") // root-level items array
IgnoreArrayOrderAt("$.users[0].roles") // roles array in first user
The option also applies to nested arrays within the specified path.
func IgnoreAttributeAt ¶
IgnoreAttributeAt excludes a specific attribute at a given HTML path. The pathAttr format is "path@attribute", e.g., "html > body > div@class".
func IgnoreAttributes ¶
IgnoreAttributes excludes the specified attribute names from HTML comparison globally.
func IgnoreChildOrder ¶
func IgnoreChildOrder() Option
IgnoreChildOrder makes child element comparison order-insensitive globally in HTML. Child elements are compared as sets rather than sequences.
func IgnoreChildOrderAt ¶
IgnoreChildOrderAt makes child element comparison order-insensitive at the specified HTML path.
func IgnoreElements ¶
IgnoreElements excludes elements matching the specified tag names from HTML comparison. Tag matching is case-insensitive.
func IgnoreFields ¶
IgnoreFields excludes the specified fields from comparison. Fields can be specified by name (matches at any depth) or by full path.
By name (matches all occurrences):
IgnoreFields("id", "timestamp") // ignores all "id" and "timestamp" fields
By path (matches specific locations):
IgnoreFields("$.user.id", "$.metadata.createdAt")
Path format uses JSONPath-like syntax:
- $ represents the root
- .field accesses object properties
- [0] accesses array elements
func IgnoreHTMLComments ¶
func IgnoreHTMLComments() Option
IgnoreHTMLComments excludes HTML comment nodes (<!-- ... -->) from comparison.
func Message ¶
Message adds a custom message to the assertion failure output. This helps identify which assertion failed when a test has multiple assertions.
testastic.AssertJSON(t, expected, actual,
testastic.Message("user creation response"),
)
func PreserveWhitespace ¶
func PreserveWhitespace() Option
PreserveWhitespace disables whitespace normalization in HTML comparison.
func Update ¶
func Update() Option
Update forces updating the expected file with the actual value. This is equivalent to running tests with the -update flag or setting TESTASTIC_UPDATE=true.
Use this option when you need to programmatically update expected files:
if shouldUpdateGoldenFiles {
testastic.AssertJSON(t, expected, actual, testastic.Update())
}