Approval-based snapshot testing library for Go (mirror)
1# Shutter
2
3A [birdie](https://github.com/giacomocavalieri/birdie) and [insta](https://github.com/mitsuhiko/insta) inspired snapshot testing library for Go.
4
5")
6
7## Installation
8
9```sh
10go get github.com/ptdewey/shutter
11```
12
13The review TUI is shipped separately to avoid adding unnecessary project dependencies (installation of the TUI is recommended):
14
15```sh
16# executable is installed as `shutter`
17go install github.com/ptdewey/shutter/cmd/shutter@latest
18```
19
20## Usage
21
22### Basic Usage
23
24```go
25package package_test
26
27func TestSomething(t *testing.T) {
28 result := SomeFunction("foo")
29 shutter.Snap(t, "test title", result)
30}
31```
32
33### Snapshotting Multiple Values
34
35Use `SnapMany()` when you need to snapshot multiple related values together:
36
37```go
38func TestMultipleValues(t *testing.T) {
39 request := buildRequest()
40 response := handleRequest(request)
41
42 // Snapshot both request and response together
43 shutter.SnapMany(t, "title", []any{request, response})
44}
45```
46
47### Advanced Usage: Scrubbers and Ignore Patterns
48
49shutter supports data scrubbing and field filtering to handle dynamic or sensitive data in snapshots.
50
51#### Scrubbers
52
53Scrubbers transform content before snapshotting, typically to replace dynamic or sensitive data with placeholders:
54
55```go
56func TestUserAPI(t *testing.T) {
57 user := api.GetUser("123")
58
59 // Replace UUIDs and timestamps with placeholders
60 shutter.Snap(t, "user", user,
61 shutter.ScrubUUID(),
62 shutter.ScrubTimestamp(),
63 )
64}
65```
66
67**Built-in Scrubbers:**
68
69- `ScrubUUID()` - Replaces UUIDs with `<UUID>`
70- `ScrubTimestamp()` - Replaces ISO8601 timestamps with `<TIMESTAMP>`
71- `ScrubEmail()` - Replaces email addresses with `<EMAIL>`
72- `ScrubIP()` - Replaces IPv4 addresses with `<IP>`
73- `ScrubJWT()` - Replaces JWT tokens with `<JWT>`
74- `ScrubCreditCard()` - Replaces credit card numbers with `<CREDIT_CARD>`
75- `ScrubAPIKey()` - Replaces API keys with `<API_KEY>`
76- `ScrubDate()` - Replaces various date formats with `<DATE>`
77- `ScrubUnixTimestamp()` - Replaces Unix timestamps with `<UNIX_TS>`
78
79**Custom Scrubbers:**
80
81```go
82// Using regex patterns
83shutter.ScrubRegex(`user-\d+`, "<USER_ID>")
84
85// Using exact string matching
86shutter.ScrubExact("secret_value", "<REDACTED>")
87
88// Using custom functions
89shutter.ScrubWith(func(content string) string {
90 return strings.ReplaceAll(content, "localhost", "<HOST>")
91})
92```
93
94#### Ignore Patterns
95
96Ignore patterns remove specific fields from JSON structures before snapshotting:
97
98```go
99func TestAPIResponse(t *testing.T) {
100 response := api.GetData()
101 jsonBytes, _ := json.Marshal(response)
102
103 // Ignore sensitive fields and null values
104 shutter.SnapJSON(t, "response", string(jsonBytes),
105 shutter.IgnoreSensitive(),
106 shutter.IgnoreNull(),
107 shutter.IgnoreKey("created_at", "updated_at"),
108 )
109}
110```
111
112**Built-in Ignore Patterns:**
113
114- `IgnoreSensitive()` - Ignores common sensitive keys (password, token, api_key, etc.)
115- `IgnoreEmpty()` - Ignores fields with empty string values
116- `IgnoreNull()` - Ignores fields with null values
117
118**Custom Ignore Patterns:**
119
120```go
121// Ignore specific keys
122shutter.IgnoreKey("id", "timestamp", "version")
123
124// Ignore key-value pairs
125shutter.IgnoreKeyValue("status", "pending")
126
127// Ignore keys matching a regex pattern
128shutter.IgnoreKeyMatching(`^_.*`) // Ignore all keys starting with underscore
129
130// Ignore specific values
131shutter.IgnoreValue("null", "undefined", "")
132
133// Using custom functions
134shutter.IgnoreWith(func(key, value string) bool {
135 return strings.HasPrefix(key, "temp_")
136})
137```
138
139#### Combining Options
140
141You can combine multiple scrubbers and ignore patterns:
142
143```go
144func TestComplexData(t *testing.T) {
145 data := generateTestData()
146 jsonBytes, _ := json.Marshal(data)
147
148 shutter.SnapJSON(t, "data", string(jsonBytes),
149 // First, remove unwanted fields
150 shutter.IgnoreSensitive(),
151 shutter.IgnoreKey("debug_info"),
152 shutter.IgnoreNull(),
153
154 // Then, scrub dynamic values in remaining fields
155 shutter.ScrubUUID(),
156 shutter.ScrubTimestamp(),
157 shutter.ScrubEmail(),
158 )
159}
160```
161
162**Note:** Ignore patterns only work with `SnapJSON()`. Use scrubbers with `Snap()`, `SnapMany()`, or `SnapString()`.
163
164#### API Reference
165
166**Snapshot Functions:**
167
168```go
169// For single values (structs, maps, slices, etc.)
170shutter.Snap(t, "title", value, options...)
171
172// For multiple related values
173shutter.SnapMany(t, "title", []any{value1, value2, value3}, options...)
174
175// For JSON strings (supports both scrubbers and ignore patterns)
176shutter.SnapJSON(t, "title", jsonString, options...)
177
178// For plain strings
179shutter.SnapString(t, "title", content, options...)
180```
181
182### Reviewing Snapshots
183
184To review a set of snapshots, run (CLI version -- not recommended):
185
186```sh
187go run github.com/ptdewey/shutter/cmd/cli review
188```
189
190Shutter can also be used programmatically:
191
192```go
193// Example: tools/shutter/main.go
194package main
195
196import "github.com/ptdewey/shutter"
197
198func main() {
199 // This will start the CLI review tool
200 shutter.Review()
201}
202```
203
204Which can then be run with:
205
206```sh
207go run tools/shutter/main.go
208```
209
210Shutter also includes (in a separate Go module) a [Bubbletea](https://github.com/charmbracelet/bubbletea) TUI in [cmd/tui/main.go](./cmd/tui/main.go).
211(The TUI is shipped in a separate module to make the added dependencies optional)
212
213### TUI Usage
214
215After installing the TUI:
216
217```sh
218shutter
219```
220
221#### Interactive Controls
222
223- `a` - Accept current snapshot
224- `r` - Reject current snapshot
225- `s` - Skip current snapshot
226- `A` - Accept all remaining snapshots
227- `R` - Reject all remaining snapshots
228- `S` - Skip all remaining snapshots
229- `q` - Quit
230
231#### Alternative Commands
232
233```sh
234# Accept all new snapshots without review
235shutter accept-all
236
237# Reject all new snapshots without review
238shutter reject-all
239```
240
241## Other Libraries
242
243- [go-snaps](https://github.com/gkampitakis/go-snaps)
244 - shutter uses the diff implementation from `go-snaps`.
245- [cupaloy](https://github.com/bradleyjkemp/cupaloy)