More than a year after the previous post about Go Snaps and there have been some improvements and a lot bug fixes.
Introduction
go-snaps is a Go library that makes snapshot testing in Go easier.
Snapshot testing is an important part of the unit testing process. It simplifies writing assertions for complex or dynamic output which can be time consuming and can catch regressions or unintended changes that otherwise might went unnoticed.
Updates to go-snaps
The improvements and updates in the library can be put into 3 categories, visual changes, new features and bug fixes.
Visual Changes
Visual changes are always the one that make the more difference in the experience of using the library. So I focused on making the diff output better more easy to distinguish where the regression is happening in a long output.
An example diff
or with long diffs
The second important visual change was on the the reporting of the library and the summary of the tests.
An example when Go Snaps identifies snapshots that are no longer used there is a message prompting cleaning them and showing which tests are marked for deletion.
Finally now the library supports NO_COLOR.
New Features
Two new big features landed on Go Snaps on is complimentary to the other.
It's snaps.MatchJSON
and property Matchers.
MatchJSON
method as the name indicates is for capturing snapshots for JSON structured data. It can accept a valid json in form of string
or []byte
or whatever value can be passed successfully on json.Marshal
.
func TestJSON(t *testing.T) {
type User struct {
Age int
Email string
}
snaps.MatchJSON(t, `{"user":"mock-user","age":10,"email":"mock@email.com"}`)
snaps.MatchJSON(t, []byte(`{"user":"mock-user","age":10,"email":"mock@email.com"}`))
snaps.MatchJSON(t, User{10, "mock-email"})
}
JSON will be saved in snapshot in pretty format for better readability.
Having a method that accepts structured data also enabled building another feature that can be useful in snapshot testing, property matchers.
MatchJSON
can accept a list of arguments called Matchers
. Matchers
are functions that can act as property matchers and test values on a specific path of the JSON.
Currently Go Snaps has two builtin matchers
match.Any
match.Custom
match.Any
can be convenient when some fields are dynamic and you have different snapshots on every run, e.g. containing a date or time field.
t.Run("should ignore fields", func(t *testing.T) {
value := fmt.Sprintf(
`{"user":"mock-user","age":10,"nested":{"now":["%s"]}}`,
time.Now(),
)
snaps.MatchJSON(t, value, match.Any("nested.now.0"))
})
the resulting snapshot will be
{
"age": 10,
"nested": {
"now": [
"<Any value>"
]
},
"user": "mock-user"
}
so you can see we are ignoring the dynamic value there.
On the other hand, match.Custom
allows you to build your own matcher that either validates or mutates a specific path.
t.Run("struct marshalling", func(t *testing.T) {
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Keys []int `json:"keys"`
}
u := User{
Name: "mock-user",
Email: "mock-user@email.com",
Keys: []int{1, 2, 3, 4, 5},
}
snaps.MatchJSON(t, u, match.Custom("keys", func(val interface{}) (interface{}, error) {
keys, ok := val.([]interface{})
if !ok {
return nil, fmt.Errorf("expected []interface{} but got %T", val)
}
if len(keys) > 5 {
return nil, fmt.Errorf("expected less than 5 keys")
}
return val, nil
}))
})
Custom matcher provides a lot of expressiveness and can support very complex use cases. In the future I am thinking of adding support for common used Matchers
like type
, or Date
.
If you are using a Matcher
and you think it should added in the library feel free to open an issue or contribute.
For more information around Matchers.
Bug Fixes
As more people start using the library noticed some edge cases ( or not that edge 馃槄 ) that the library was either not handling gracefully or was misbehaving.
I am not going into much detail but I will share the list of pull requests if you are interested.
- fix: update isSkippedFile, replace file absolute match w/ regex match by @gparasyris in #48
- fix: permission denied when running from test suite by @gkampitakis in #44
- fix: issue with updating snapshots with expand chars, fixes #30
- fix: issue with marking non child tests as skipped v0.3.0...v0.3.1
- fix: issue with newlines when removing obsolete snaps v0.3.0...v0.3.1
- fix: ignore end chars --- inside snapshot in #26
Conclusion
The latest changes and updates to go-snaps improved and simplified using snapshot testing into unit testing workflow. Alongside the bug fixes it makes the library more reliable for people to use it and rely on catching issues and potential regressions.
If you liked or found go-snaps useful you can leave a 猸愶笍.