Go Snaps: The Latest Updates and Improvements
Tags: go, testing, unittesting, jest
Published: 2023-02-27 21:33:16


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](https://github.com/gkampitakis/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

![small diff before](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5u7sbw0lca7if95runad.png)
![small diff after](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9pyytfvhe22pgojh1lef.png)

or with long diffs

![big diff before](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1nv47tr25loh9zo8k8h3.png)
![big diff after](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k41meo25cwga1tkos3cm.png)

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.

![summary-obsolete](https://raw.githubusercontent.com/gkampitakis/go-snaps/e1c425c09b32f523d2f4da4c307527bdcdd98f92/images/summary-obsolete.png)

Finally now the library supports [NO_COLOR](https://no-color.org).

### 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`.

```go
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.


```go
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. 

```go
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](https://github.com/gkampitakis/go-snaps/issues) or contribute._

For more information around [Matchers](https://github.com/gkampitakis/go-snaps#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](https://github.com/gkampitakis/go-snaps/pull/48)
- fix: permission denied when running from test suite by @gkampitakis in [#44](https://github.com/gkampitakis/go-snaps/pull/44)
- fix: issue with updating snapshots with expand chars, fixes [#30](https://github.com/gkampitakis/go-snaps/issues/30)
- fix: issue with marking non child tests as skipped [v0.3.0...v0.3.1](https://github.com/gkampitakis/go-snaps/compare/v0.3.0...v0.3.1)
- fix: issue with newlines when removing obsolete snaps [v0.3.0...v0.3.1](https://github.com/gkampitakis/go-snaps/compare/v0.3.0...v0.3.1)
- fix: ignore end chars --- inside snapshot in [#26](https://github.com/gkampitakis/go-snaps/pull/26)


## Conclusion

The latest changes and updates to [go-snaps](https://github.com/gkampitakis/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](https://github.com/gkampitakis/go-snaps) useful you can leave a ⭐️.