gkampitakis / go-snaps

Jest-like snapshot testing in Go 📸
https://pkg.go.dev/github.com/gkampitakis/go-snaps
MIT License
174 stars 6 forks source link

[Feature Request ]: Configurable snapshot file #58

Closed RusEu closed 1 year ago

RusEu commented 1 year ago

🚀 Feature Proposal

Configurable snapshot file

Motivation

It will be nice to have the ability to save a snapshot to a different file. This way if you have a test that generates a lot of snapshots, you can easily check and see what adds each one, and also makes easier to review the diff in git.

Example

BEFORE:

            snaps.MatchJSON(t, data,
                match.Custom("payload.id", matchers.MatchAny[float64]),
                match.Custom("payload.created_at", matchers.MatchTime(time.RFC3339Nano)),
                match.Custom("payload.updated_at", matchers.MatchTime(time.RFC3339Nano)),
            )

AFTER


            snaps.MatchJSON(t, "test_1.snap", data,
                match.Custom("payload.id", matchers.MatchAny[float64]),
                match.Custom("payload.created_at", matchers.MatchTime(time.RFC3339Nano)),
                match.Custom("payload.updated_at", matchers.MatchTime(time.RFC3339Nano)),
            )
gkampitakis commented 1 year ago

Hey 👋 Thanks for opening this issue.

Just to understand your use case when you say

save a snapshot to a different file

do you mean save the snapshot to it's own seperate file?

I was thinking about providing some configuration at test level about this but I don't want to break the current signature and keep compatibility. Something I had in mind was providing chained methods so it could look like

# or a similar method name
snaps.MatchJSON(t, data, matchers...).SaveSeparately()

and save each snapshot on a file name e.g. TestMatchJSON/should_make_a_json_object_snapshot _1.snap would that work for your use case ? Or are you looking at something different ?


On another note I am curious on the matchers you use on your example. They look interesting 😄

RusEu commented 1 year ago

This may generate a lot of files, i was thinking on 1 file per test name(this may include multiple snapshots) or a way to define the name of the file where the snapshot will be saved so you can group multiple snapshots in the same filename. Using chained methods may be a very clean solution.

RusEu commented 1 year ago

The matchers I used in the example are custom matchers:

func MatchAny[T any](val any) (any, error) {
    _, ok := val.(T)
    if !ok {
        return nil, fmt.Errorf("expected %T but got %T", *new(T), val)
    }
    return fmt.Sprintf("<Any %T>", val), nil
}

func MatchTime(rfc string) func(val any) (any, error) {
    return func(val any) (any, error) {
        if _, err := MatchAny[string](val); err != nil {
            return nil, err
        }

        _, err := time.Parse(rfc, val.(string))
        if err != nil {
            return nil, fmt.Errorf("expected time but got %T", val)
        }

        return fmt.Sprintf("<Str %s>", rfc), nil
    }
}

Maybe not the cleanest solution but works pretty nice :-D

gkampitakis commented 1 year ago

I really like it 😄 Especially the type check with the generic function is really smart. Might try to create a MatchType matcher based on your idea 👍