Skip to content

Commit

Permalink
feat: implement matchYAML (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
gkampitakis authored Dec 25, 2024
1 parent 09cd270 commit f81115d
Show file tree
Hide file tree
Showing 18 changed files with 1,051 additions and 127 deletions.
95 changes: 63 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/gkampitakis/go-snaps.svg)](https://pkg.go.dev/github.com/gkampitakis/go-snaps)

<p align="center">
<b>Jest-like snapshot testing in Golang</b>
<b>Jest-like snapshot testing in Go</b>
</p>

<br>
Expand All @@ -18,12 +18,13 @@

- [Installation](#installation)
- [MatchSnapshot](#matchsnapshot)
- [MatchStandaloneSnapshot](#matchstandalonesnapshot) `New`
- [MatchJSON](#matchjson)
- [Matchers](#matchers)
- [match.Any](#matchany)
- [match.Custom](#matchcustom)
- [match.Type\[ExpectedType\]](#matchtype)
- [MatchStandaloneSnapshot](#matchstandalonesnapshot)
- [MatchYAML](#matchyaml) `New`
- [Matchers](#matchers)
- [match.Any](#matchany)
- [match.Custom](#matchcustom)
- [match.Type\[ExpectedType\]](#matchtype)
- [Configuration](#configuration)
- [Update Snapshots](#update-snapshots)
- [Clean obsolete Snapshots](#clean-obsolete-snapshots)
Expand Down Expand Up @@ -85,6 +86,29 @@ name is the test file name with extension `.snap`.
So for example if your test is called `test_simple.go` when you run your tests, a snapshot file
will be created at `./__snapshots__/test_simple.snaps`.

## MatchStandaloneSnapshot

`MatchStandaloneSnapshot` will create snapshots on separate files as opposed to `MatchSnapshot` which adds multiple snapshots inside the same file.

_Combined with `snaps.Ext` you can have proper syntax highlighting and better readability_

```go
// test_simple.go

func TestSimple(t *testing.T) {
snaps.MatchStandaloneSnapshot(t, "Hello World")
// or create an html snapshot file
snaps.WithConfig(snaps.Ext(".html")).
MatchStandaloneSnapshot(t, "<html><body><h1>Hello World</h1></body></html>")
}
```

`go-snaps` saves the snapshots in `__snapshots__` directory and the file
name is the test file name with extension `.snap`.

So for example if your test is called `test_simple.go` when you run your tests, a snapshot file
will be created at `./__snapshots__/TestSimple_1.snaps`.

## MatchJSON

`MatchJSON` can be used to capture data that can represent a valid json.
Expand All @@ -107,21 +131,51 @@ func TestJSON(t *testing.T) {

JSON will be saved in snapshot in pretty format for more readability and deterministic diffs.

## MatchYAML

`MatchYAML` can be used to capture data that can represent a valid yaml.

You can pass a valid json in form of `string` or `[]byte` or whatever value can be passed
successfully on `yaml.Marshal`.

```go
func TestYAML(t *testing.T) {
type User struct {
Age int
Email string
}

snaps.MatchYAML(t, "user: \"mock-user\"\nage: 10\nemail: mock@email.com")
snaps.MatchYAML(t, []byte("user: \"mock-user\"\nage: 10\nemail: mock@email.com"))
snaps.MatchYAML(t, User{10, "mock-email"})
}
```

### Matchers

`MatchJSON`'s third argument can accept a list of matchers. Matchers are functions that can act
`MatchJSON`'s and `MatchYAML`'s third argument can accept a list of matchers. Matchers are functions that can act
as property matchers and test values.

You can pass the path of the property you want to match and test.

_More information about the supported path syntax from [gjson](https://github.com/tidwall/gjson/blob/v1.17.0/SYNTAX.md)._

Currently `go-snaps` has three build in matchers

- `match.Any`
- `match.Custom`
- `match.Type[ExpectedType]`

_Open to feedback for building more matchers or you can build your own [example](./examples/matchJSON_test.go#L16)._

#### Path Syntax

For JSON go-snaps utilises gjson.

_More information about the supported path syntax from [gjson](https://github.com/tidwall/gjson/blob/v1.17.0/SYNTAX.md)._

As for YAML go-snaps utilises [github.com/goccy/go-yaml#5-use-yamlpath](https://github.com/goccy/go-yaml#5-use-yamlpath).

_More information about the supported syntax [PathString](https://github.com/goccy/go-yaml/blob/9cbf5d4217830fd4ad1504e9ed117c183ade0994/path.go#L17-L26)._

#### match.Any

Any matcher acts as a placeholder for any value. It replaces any targeted path with a
Expand Down Expand Up @@ -196,29 +250,6 @@ match.Type[string]("user.info").

You can see more [examples](./examples/matchJSON_test.go#L96).

## MatchStandaloneSnapshot

`MatchStandaloneSnapshot` will create snapshots on separate files as opposed to `MatchSnapshot` which adds multiple snapshots inside the same file.

_Combined with `snaps.Ext` you can have proper syntax highlighting and better readability_

```go
// test_simple.go

func TestSimple(t *testing.T) {
snaps.MatchStandaloneSnapshot(t, "Hello World")
// or create an html snapshot file
snaps.WithConfig(snaps.Ext(".html")).
MatchStandaloneSnapshot(t, "<html><body><h1>Hello World</h1></body></html>")
}
```

`go-snaps` saves the snapshots in `__snapshots__` directory and the file
name is the test file name with extension `.snap`.

So for example if your test is called `test_simple.go` when you run your tests, a snapshot file
will be created at `./__snapshots__/TestSimple_1.snaps`.

## Configuration

`go-snaps` allows passing configuration for overriding
Expand Down
29 changes: 29 additions & 0 deletions examples/__snapshots__/matchYAML_test.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

[TestMatchYaml/should_match_struct_yaml - 1]
name: John Doe
age: 30
email: john.doe@example.com
address: mock-address
time: mock-time

---

[TestMatchYaml/custom_matching_logic - 1]
name: mock-user
email: mock-user@email.com
keys:
- 1
- 2
- 3
- 4
- 5

---

[TestMatchYaml/type_matcher - 1]
data: <Type:uint64>
---

[TestMatchYaml/type_matcher - 2]
metadata: <Type:map[string]interface {}>
---
67 changes: 67 additions & 0 deletions examples/matchYAML_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package examples

import (
"fmt"
"testing"
"time"

"github.com/gkampitakis/go-snaps/match"
"github.com/gkampitakis/go-snaps/snaps"
)

func TestMatchYaml(t *testing.T) {
t.Run("should match struct yaml", func(t *testing.T) {
type User struct {
Name string `yaml:"name"`
Age int `yaml:"age"`
Email string `yaml:"email"`
Address string `yaml:"address"`
Time time.Time `yaml:"time"`
}

snaps.MatchYAML(t, User{
Name: "John Doe",
Age: 30,
Email: "john.doe@example.com",
Address: "123 Main St",
Time: time.Now(),
}, match.Any("$.time").Placeholder("mock-time"), match.Any("$.address").Placeholder("mock-address"))
})

t.Run("custom matching logic", 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.MatchYAML(t, u, match.Custom("$.keys", func(val any) (any, error) {
keys, ok := val.([]any)
if !ok {
return nil, fmt.Errorf("expected []any but got %T", val)
}

if len(keys) > 5 {
return nil, fmt.Errorf("expected less than 5 keys")
}

return val, nil
}))
})

t.Run("type matcher", func(t *testing.T) {
snaps.MatchYAML(t, "data: 10", match.Type[uint64]("$.data"))

snaps.MatchYAML(
t,
"metadata:\n timestamp: 1687108093142",
match.Type[map[string]any]("$.metadata"),
)
})
}
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
module github.com/gkampitakis/go-snaps

go 1.21
go 1.22

require (
github.com/gkampitakis/ciinfo v0.3.0
github.com/gkampitakis/ciinfo v0.3.1
github.com/gkampitakis/go-diff v1.3.2
github.com/goccy/go-yaml v1.15.13
github.com/kr/pretty v0.3.1
github.com/maruel/natural v1.1.1
github.com/tidwall/gjson v1.17.0
github.com/tidwall/gjson v1.18.0
github.com/tidwall/pretty v1.2.1
github.com/tidwall/sjson v1.2.5
)

require (
github.com/kr/text v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
)
14 changes: 8 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/gkampitakis/ciinfo v0.3.0 h1:gWZlOC2+RYYttL0hBqcoQhM7h1qNkVqvRCV1fOvpAv8=
github.com/gkampitakis/ciinfo v0.3.0/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/ciinfo v0.3.1 h1:lzjbemlGI4Q+XimPg64ss89x8Mf3xihJqy/0Mgagapo=
github.com/gkampitakis/ciinfo v0.3.1/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
github.com/goccy/go-yaml v1.15.13 h1:Xd87Yddmr2rC1SLLTm2MNDcTjeO/GYo0JGiww6gSTDg=
github.com/goccy/go-yaml v1.15.13/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
Expand All @@ -11,11 +13,11 @@ github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
Expand Down
Loading

0 comments on commit f81115d

Please sign in to comment.