testastic

package module
v0.0.0-...-7d1d322 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 10, 2026 License: MIT Imports: 17 Imported by: 0

README

testastic

A Go testing toolkit with JSON comparison and general assertions.

Install

go get github.com/monkescience/testastic

JSON Assertions

Compare API responses against expected JSON files with template matchers:

testastic.AssertJSON(t, "testdata/user.expected.json", resp.Body)

Expected file with matchers:

{
  "id": "{{anyString}}",
  "count": "{{anyInt}}",
  "email": "{{regex `^[a-z]+@example\\.com$`}}",
  "status": "{{oneOf \"pending\" \"active\"}}",
  "timestamp": "{{ignore}}"
}

Available matchers: {{anyString}}, {{anyInt}}, {{anyFloat}}, {{anyBool}}, {{anyValue}}, {{ignore}}, {{regex ``}}, {{oneOf ""}}

Options:

AssertJSON(t, expected, actual, IgnoreArrayOrder())
AssertJSON(t, expected, actual, IgnoreArrayOrderAt("$.items"))
AssertJSON(t, expected, actual, IgnoreFields("id", "timestamp"))

Update expected files: go test -update

General Assertions

// Equality
testastic.Equal(t, expected, actual)
testastic.NotEqual(t, unexpected, actual)
testastic.DeepEqual(t, expected, actual)

// Nil/Boolean
testastic.Nil(t, value)
testastic.NotNil(t, value)
testastic.True(t, value)
testastic.False(t, value)

// Errors
testastic.NoError(t, err)
testastic.Error(t, err)
testastic.ErrorIs(t, err, target)
testastic.ErrorContains(t, err, "substring")

// Comparison
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)

// Strings
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)

// Collections
testastic.Len(t, collection, expected)
testastic.Empty(t, collection)
testastic.NotEmpty(t, collection)
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.MapEqual(t, expected, actual)

Output

Colored diff output (red for expected, green for actual):

testastic: assertion failed

  Equal
    expected: "Alice"
    actual:   "Bob"

JSON mismatches show git-style inline diff:

testastic: assertion failed

  AssertJSON (testdata/user.expected.json)
  {
-   "name": "Alice",
+   "name": "Bob",
    "age": 30
  }

Documentation

Overview

Package testastic provides JSON assertion utilities for Go tests. It compares API responses against expected JSON files with support for template-based matchers, semantic comparison, and automatic updates.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidRegexSyntax = errors.New("invalid regex syntax")
	ErrInvalidOneOfSyntax = errors.New("invalid oneOf syntax")
	ErrUnknownMatcher     = errors.New("unknown matcher")
)

Matcher parsing errors.

View Source
var ErrUnknownPlaceholder = errors.New("unknown placeholder")

ErrUnknownPlaceholder is returned when a placeholder is not found in the matcher map.

View Source
var ErrUnsupportedHTMLType = errors.New("unsupported type for HTML comparison")

ErrUnsupportedHTMLType is returned when an unsupported type is passed to AssertHTML.

Functions

func AssertHTML

func AssertHTML[T any](tb testing.TB, expectedFile string, actual T, opts ...HTMLOption)

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

func AssertJSON[T any](tb testing.TB, expectedFile string, actual T, opts ...Option)

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)

func Between

func Between[T cmp.Ordered](tb testing.TB, value, minVal, maxVal T)

Between asserts that minVal <= value <= maxVal.

func Contains

func Contains(tb testing.TB, s, substring string)

Contains asserts that s contains substring.

func DeepEqual

func DeepEqual[T any](tb testing.TB, expected, actual T)

DeepEqual asserts that expected and actual are deeply equal using reflect.DeepEqual.

func Empty

func Empty(tb testing.TB, collection any)

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.

func Error

func Error(tb testing.TB, err error)

Error asserts that err is not nil.

func ErrorContains

func ErrorContains(tb testing.TB, err error, substring string)

ErrorContains asserts that err contains the given substring.

func ErrorIs

func ErrorIs(tb testing.TB, err, target error)

ErrorIs asserts that err matches target using errors.Is.

func False

func False(tb testing.TB, value bool)

False asserts that value is false.

func FormatDiff

func FormatDiff(diffs []Difference) string

FormatDiff formats a slice of differences into a human-readable string. This is the simple format showing paths and values.

func FormatDiffInline

func FormatDiffInline(expected, actual any) string

FormatDiffInline generates a git-style inline diff between expected and actual JSON. Shows the full JSON with - prefix for removed lines and + prefix for added lines.

func FormatHTMLDiff

func FormatHTMLDiff(diffs []HTMLDifference) string

FormatHTMLDiff formats a slice of HTML differences into a human-readable string.

func FormatHTMLDiffInline

func FormatHTMLDiffInline(expected, actual *HTMLNode) string

FormatHTMLDiffInline generates a git-style inline diff between expected and actual HTML. Uses the same format as JSON diff.

func Greater

func Greater[T cmp.Ordered](tb testing.TB, a, b T)

Greater asserts that a > b.

func GreaterOrEqual

func GreaterOrEqual[T cmp.Ordered](tb testing.TB, a, b T)

GreaterOrEqual asserts that a >= b.

func HasPrefix

func HasPrefix(tb testing.TB, s, prefix string)

HasPrefix asserts that s has the given prefix.

func HasSuffix

func HasSuffix(tb testing.TB, s, suffix string)

HasSuffix asserts that s has the given suffix.

func IsIgnore

func IsIgnore(m Matcher) bool

IsIgnore returns true if the matcher is an ignore matcher.

func Len

func Len(tb testing.TB, collection any, expected int)

Len asserts that the collection has the expected length. Works with slices, maps, strings, arrays, and channels.

func Less

func Less[T cmp.Ordered](tb testing.TB, a, b T)

Less asserts that a < b.

func LessOrEqual

func LessOrEqual[T cmp.Ordered](tb testing.TB, a, b T)

LessOrEqual asserts that a <= b.

func MapEqual

func MapEqual[K comparable, V comparable](tb testing.TB, expected, actual map[K]V)

MapEqual asserts that two maps are equal.

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.

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.

func Matches

func Matches(tb testing.TB, s, pattern string)

Matches asserts that s matches the given regular expression pattern.

func Nil

func Nil(tb testing.TB, value any)

Nil asserts that value is nil.

func NoError

func NoError(tb testing.TB, err error)

NoError asserts that err is nil.

func NotContains

func NotContains(tb testing.TB, s, substring string)

NotContains asserts that s does not contain substring.

func NotEmpty

func NotEmpty(tb testing.TB, collection any)

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.

func NotNil

func NotNil(tb testing.TB, value any)

NotNil asserts that value is not nil.

func SliceContains

func SliceContains[T comparable](tb testing.TB, slice []T, element T)

SliceContains asserts that slice contains element.

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.

func StringEmpty

func StringEmpty(tb testing.TB, s string)

StringEmpty asserts that s is an empty string.

func StringNotEmpty

func StringNotEmpty(tb testing.TB, s string)

StringNotEmpty asserts that s is not an empty string.

func True

func True(tb testing.TB, value bool)

True asserts that value is true.

Types

type Config

type Config struct {
	IgnoreArrayOrder      bool
	IgnoreArrayOrderPaths []string
	IgnoredFields         []string
	Update                bool
}

Config holds the configuration for JSON comparison.

type DiffType

type DiffType int

DiffType represents the type of difference found.

const (
	// DiffChanged indicates a value was modified.
	DiffChanged DiffType = iota
	// DiffAdded indicates a value was added (exists in actual but not expected).
	DiffAdded
	// DiffRemoved indicates a value was removed (exists in expected but not actual).
	DiffRemoved
	// DiffTypeMismatch indicates the types don't match.
	DiffTypeMismatch
	// DiffMatcherFailed indicates a matcher didn't match the actual value.
	DiffMatcherFailed
)

func (DiffType) String

func (d DiffType) String() string

String returns a human-readable description of the diff type.

type Difference

type Difference struct {
	Path     string   // JSON path, e.g., "$.users[0].name"
	Expected any      // Expected value (or matcher description)
	Actual   any      // Actual value
	Type     DiffType // Type of difference
}

Difference represents a single difference between expected and actual JSON.

type ExpectedHTML

type ExpectedHTML struct {
	Root     *HTMLNode
	Matchers map[string]string
	Raw      string
}

ExpectedHTML represents a parsed expected HTML file with matchers.

func ParseExpectedHTMLFile

func ParseExpectedHTMLFile(path string) (*ExpectedHTML, error)

ParseExpectedHTMLFile reads and parses an expected HTML file, replacing template expressions with matchers.

func ParseExpectedHTMLString

func ParseExpectedHTMLString(content string) (*ExpectedHTML, error)

ParseExpectedHTMLString parses an expected HTML string with template expressions.

func (*ExpectedHTML) ExtractMatcherPositions

func (e *ExpectedHTML) ExtractMatcherPositions() map[string]string

ExtractMatcherPositions returns a map of HTML paths to their original template expressions.

type ExpectedJSON

type ExpectedJSON struct {
	Data     any               // Parsed JSON with Matcher objects in place of template expressions
	Matchers map[string]string // Map of placeholder to original template expression
	Raw      string            // Original file content for update operations
}

ExpectedJSON represents a parsed expected file with matchers.

func ParseExpectedFile

func ParseExpectedFile(path string) (*ExpectedJSON, error)

ParseExpectedFile reads and parses an expected file, replacing template expressions with matchers.

func ParseExpectedString

func ParseExpectedString(content string) (*ExpectedJSON, error)

ParseExpectedString parses an expected JSON string with template expressions.

func (*ExpectedJSON) ExtractMatcherPositions

func (e *ExpectedJSON) ExtractMatcherPositions() map[string]string

ExtractMatcherPositions returns a map of JSON paths to their original template expressions. This is used when updating expected files to preserve matchers.

type HTMLConfig

type HTMLConfig struct {
	IgnoreComments        bool
	PreserveWhitespace    bool
	IgnoreChildOrder      bool
	IgnoreChildOrderPaths []string
	IgnoredElements       []string
	IgnoredAttributes     []string
	IgnoredAttributePaths []string
	Update                bool
}

HTMLConfig holds the configuration for HTML comparison.

type HTMLDifference

type HTMLDifference struct {
	Path     string
	Expected any
	Actual   any
	Type     DiffType
}

HTMLDifference represents a single difference between expected and actual HTML.

type HTMLNode

type HTMLNode struct {
	Type       HTMLNodeType
	Tag        string
	Attributes map[string]any
	Children   []*HTMLNode
	Text       any
	Path       string
}

HTMLNode represents a normalized HTML node for comparison.

type HTMLNodeType

type HTMLNodeType int

HTMLNodeType represents the type of an HTML node.

const (
	// HTMLElement represents an HTML element node.
	HTMLElement HTMLNodeType = iota
	// HTMLText represents a text node.
	HTMLText
	// HTMLComment represents a comment node.
	HTMLComment
	// HTMLDoctype represents a doctype node.
	HTMLDoctype
)

type HTMLOption

type HTMLOption func(*HTMLConfig)

HTMLOption is a functional option for configuring HTML comparison.

func HTMLUpdate

func HTMLUpdate() HTMLOption

HTMLUpdate forces updating the expected file with the actual value.

func IgnoreAttributeAt

func IgnoreAttributeAt(pathAttr string) HTMLOption

IgnoreAttributeAt excludes a specific attribute at a given path. Format: "path@attribute" e.g., "html > body > div@class".

func IgnoreAttributes

func IgnoreAttributes(attrs ...string) HTMLOption

IgnoreAttributes excludes the specified attribute names from comparison globally.

func IgnoreChildOrder

func IgnoreChildOrder() HTMLOption

IgnoreChildOrder makes child element comparison order-insensitive globally.

func IgnoreChildOrderAt

func IgnoreChildOrderAt(path string) HTMLOption

IgnoreChildOrderAt makes child comparison order-insensitive at the specified HTML path.

func IgnoreElements

func IgnoreElements(tags ...string) HTMLOption

IgnoreElements excludes elements matching the specified tag names from comparison.

func IgnoreHTMLComments

func IgnoreHTMLComments() HTMLOption

IgnoreHTMLComments excludes HTML comments from comparison.

func PreserveWhitespace

func PreserveWhitespace() HTMLOption

PreserveWhitespace disables whitespace normalization. By default, insignificant whitespace is collapsed.

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 AnyBool

func AnyBool() Matcher

AnyBool returns a matcher that matches any boolean value.

func AnyFloat

func AnyFloat() Matcher

AnyFloat returns a matcher that matches any numeric value.

func AnyInt

func AnyInt() Matcher

AnyInt returns a matcher that matches any integer value.

func AnyString

func AnyString() Matcher

AnyString returns a matcher that matches any string value.

func AnyValue

func AnyValue() Matcher

AnyValue returns a matcher that matches any value including null.

func Ignore

func Ignore() Matcher

Ignore returns a matcher that causes the field to be skipped.

func OneOf

func OneOf(values ...any) Matcher

OneOf returns a matcher that matches if the value equals one of the given values.

func ParseMatcher

func ParseMatcher(expr string) (Matcher, error)

ParseMatcher creates a Matcher from a template expression. The expression is the content between {{ and }}.

func Regex

func Regex(pattern string) (Matcher, error)

Regex returns a matcher that matches strings against a regex pattern.

type Option

type Option func(*Config)

Option is a functional option for configuring JSON comparison.

func IgnoreArrayOrder

func IgnoreArrayOrder() Option

IgnoreArrayOrder makes array comparison order-insensitive globally.

func IgnoreArrayOrderAt

func IgnoreArrayOrderAt(path string) Option

IgnoreArrayOrderAt makes array comparison order-insensitive at the specified JSON path.

func IgnoreFields

func IgnoreFields(fields ...string) Option

IgnoreFields excludes the specified fields from comparison. Fields can be simple names or JSON paths (e.g., "$.user.id").

func Update

func Update() Option

Update forces updating the expected file with the actual value.

type TemplateSegment

type TemplateSegment struct {
	Literal string  // Literal text (empty if Matcher is set).
	Matcher Matcher // Matcher (nil if Literal is set).
}

TemplateSegment represents part of a template string.

type TemplateString

type TemplateString struct {
	Segments []TemplateSegment
	Original string // For display: "border-left: 6px solid {{anyString}}".
}

TemplateString represents a string with embedded matchers.

func (TemplateString) Match

func (t TemplateString) Match(actual string) bool

Match checks if the actual string matches the template pattern.

func (TemplateString) String

func (t TemplateString) String() string

String returns the original template representation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL