mirror of https://github.com/ory/kratos
test(hydra): add snapshots for login & consent requests
GitOrigin-RevId: 47d041cf207af6c3e9e21bf3016e5ea0cf044344
This commit is contained in:
parent
a043b43ceb
commit
ee39bdb5bd
|
|
@ -5,4 +5,3 @@
|
|||
"message": "Unable to locate the resource"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,3 @@
|
|||
"message": "Unable to locate the resource"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,3 @@
|
|||
"message": "uuid: incorrect UUID length 10 in string \"not-a-uuid\""
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,3 @@
|
|||
"message": "uuid: incorrect UUID length 10 in string \"not-a-uuid\""
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ func TestHandler(t *testing.T) {
|
|||
t.Run("endpoint="+tc.name, func(t *testing.T) {
|
||||
body := getCourierMessag(tc.s, "not-a-uuid")
|
||||
|
||||
snapshotx.SnapshotTJSONString(t, body.String())
|
||||
snapshotx.SnapshotTJSON(t, body.Raw)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
@ -279,7 +279,7 @@ func TestHandler(t *testing.T) {
|
|||
for _, tc := range tss {
|
||||
t.Run("endpoint="+tc.name, func(t *testing.T) {
|
||||
body := getCourierMessag(tc.s, uuid.Nil.String())
|
||||
snapshotx.SnapshotTJSONString(t, body.String())
|
||||
snapshotx.SnapshotTJSON(t, body.Raw)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ require (
|
|||
github.com/ssoready/hyrumtoken v1.0.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/tidwall/pretty v1.2.1
|
||||
github.com/tidwall/sjson v1.2.5
|
||||
github.com/urfave/negroni v1.0.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.62.0
|
||||
|
|
@ -199,6 +198,7 @@ require (
|
|||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
|
|
|
|||
|
|
@ -7,93 +7,99 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/pretty"
|
||||
|
||||
"github.com/ory/x/stringslice"
|
||||
|
||||
"github.com/bradleyjkemp/cupaloy/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
)
|
||||
|
||||
type (
|
||||
ExceptOpt interface {
|
||||
apply(t *testing.T, raw []byte) []byte
|
||||
Opt = func(*options)
|
||||
options struct {
|
||||
modifiers []func(t *testing.T, raw []byte) []byte
|
||||
name string
|
||||
}
|
||||
exceptPaths []string
|
||||
exceptNestedKeys []string
|
||||
replacement struct{ str, replacement string }
|
||||
)
|
||||
|
||||
func (e exceptPaths) apply(t *testing.T, raw []byte) []byte {
|
||||
for _, ee := range e {
|
||||
var err error
|
||||
raw, err = sjson.DeleteBytes(raw, ee)
|
||||
require.NoError(t, err)
|
||||
func ExceptPaths(keys ...string) Opt {
|
||||
return func(o *options) {
|
||||
o.modifiers = append(o.modifiers, func(t *testing.T, raw []byte) []byte {
|
||||
for _, key := range keys {
|
||||
var err error
|
||||
raw, err = sjson.DeleteBytes(raw, key)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
return raw
|
||||
})
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
func (e exceptNestedKeys) apply(t *testing.T, raw []byte) []byte {
|
||||
parsed := gjson.ParseBytes(raw)
|
||||
require.True(t, parsed.IsObject() || parsed.IsArray())
|
||||
return deleteMatches(t, "", parsed, e, []string{}, raw)
|
||||
}
|
||||
|
||||
func (r *replacement) apply(_ *testing.T, raw []byte) []byte {
|
||||
return bytes.ReplaceAll(raw, []byte(r.str), []byte(r.replacement))
|
||||
}
|
||||
|
||||
func ExceptPaths(keys ...string) ExceptOpt {
|
||||
return exceptPaths(keys)
|
||||
}
|
||||
|
||||
func ExceptNestedKeys(nestedKeys ...string) ExceptOpt {
|
||||
return exceptNestedKeys(nestedKeys)
|
||||
}
|
||||
|
||||
func WithReplacement(str, replace string) ExceptOpt {
|
||||
return &replacement{str: str, replacement: replace}
|
||||
}
|
||||
|
||||
func SnapshotTJSON(t *testing.T, compare []byte, except ...ExceptOpt) {
|
||||
t.Helper()
|
||||
for _, e := range except {
|
||||
compare = e.apply(t, compare)
|
||||
func ExceptNestedKeys(nestedKeys ...string) Opt {
|
||||
return func(o *options) {
|
||||
o.modifiers = append(o.modifiers, func(t *testing.T, raw []byte) []byte {
|
||||
parsed := gjson.ParseBytes(raw)
|
||||
require.True(t, parsed.IsObject() || parsed.IsArray())
|
||||
return deleteMatches(t, "", parsed, nestedKeys, []string{}, raw)
|
||||
})
|
||||
}
|
||||
|
||||
cupaloy.New(
|
||||
cupaloy.CreateNewAutomatically(true),
|
||||
cupaloy.FailOnUpdate(true),
|
||||
cupaloy.SnapshotFileExtension(".json"),
|
||||
).SnapshotT(t, pretty.Pretty(compare))
|
||||
}
|
||||
|
||||
func SnapshotTJSONString(t *testing.T, str string, except ...ExceptOpt) {
|
||||
t.Helper()
|
||||
SnapshotTJSON(t, []byte(str), except...)
|
||||
func WithReplacement(str, replace string) Opt {
|
||||
return func(o *options) {
|
||||
o.modifiers = append(o.modifiers, func(t *testing.T, raw []byte) []byte {
|
||||
return bytes.ReplaceAll(raw, []byte(str), []byte(replace))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func SnapshotT(t *testing.T, actual interface{}, except ...ExceptOpt) {
|
||||
func WithName(name string) Opt {
|
||||
return func(o *options) {
|
||||
o.name = name
|
||||
}
|
||||
}
|
||||
|
||||
func newOptions(opts ...Opt) *options {
|
||||
o := &options{}
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *options) applyModifiers(t *testing.T, compare []byte) []byte {
|
||||
for _, modifier := range o.modifiers {
|
||||
compare = modifier(t, compare)
|
||||
}
|
||||
return compare
|
||||
}
|
||||
|
||||
var snapshot = cupaloy.New(cupaloy.SnapshotFileExtension(".json"))
|
||||
|
||||
func SnapshotTJSON[C ~string | ~[]byte](t *testing.T, compare C, opts ...Opt) {
|
||||
SnapshotT(t, json.RawMessage(compare), opts...)
|
||||
}
|
||||
|
||||
func SnapshotT(t *testing.T, actual any, opts ...Opt) {
|
||||
t.Helper()
|
||||
compare, err := json.MarshalIndent(actual, "", " ")
|
||||
require.NoErrorf(t, err, "%+v", actual)
|
||||
for _, e := range except {
|
||||
compare = e.apply(t, compare)
|
||||
}
|
||||
|
||||
cupaloy.New(
|
||||
cupaloy.CreateNewAutomatically(true),
|
||||
cupaloy.FailOnUpdate(true),
|
||||
cupaloy.SnapshotFileExtension(".json"),
|
||||
).SnapshotT(t, compare)
|
||||
o := newOptions(opts...)
|
||||
compare = o.applyModifiers(t, compare)
|
||||
|
||||
if o.name == "" {
|
||||
snapshot.SnapshotT(t, compare)
|
||||
} else {
|
||||
name := strings.ReplaceAll(t.Name()+"_"+o.name, "/", "-")
|
||||
require.NoError(t, snapshot.SnapshotWithName(name, compare))
|
||||
}
|
||||
}
|
||||
|
||||
// SnapshotTExcept is deprecated in favor of SnapshotT with ExceptOpt.
|
||||
// SnapshotTExcept is deprecated in favor of SnapshotT with Opt.
|
||||
//
|
||||
// DEPRECATED: please use SnapshotT instead
|
||||
func SnapshotTExcept(t *testing.T, actual interface{}, except []string) {
|
||||
|
|
@ -105,11 +111,7 @@ func SnapshotTExcept(t *testing.T, actual interface{}, except []string) {
|
|||
require.NoError(t, err, "%s", e)
|
||||
}
|
||||
|
||||
cupaloy.New(
|
||||
cupaloy.CreateNewAutomatically(true),
|
||||
cupaloy.FailOnUpdate(true),
|
||||
cupaloy.SnapshotFileExtension(".json"),
|
||||
).SnapshotT(t, compare)
|
||||
snapshot.SnapshotT(t, compare)
|
||||
}
|
||||
|
||||
func deleteMatches(t *testing.T, key string, result gjson.Result, matches []string, parents []string, content []byte) []byte {
|
||||
|
|
@ -132,7 +134,7 @@ func deleteMatches(t *testing.T, key string, result gjson.Result, matches []stri
|
|||
})
|
||||
}
|
||||
|
||||
if stringslice.Has(matches, key) {
|
||||
if slices.Contains(matches, key) {
|
||||
content, err := sjson.DeleteBytes(content, strings.Join(path, "."))
|
||||
require.NoError(t, err)
|
||||
return content
|
||||
|
|
@ -140,25 +142,3 @@ func deleteMatches(t *testing.T, key string, result gjson.Result, matches []stri
|
|||
|
||||
return content
|
||||
}
|
||||
|
||||
// SnapshotTExceptMatchingKeys works like SnapshotTExcept but deletes keys that match the given matches recursively.
|
||||
//
|
||||
// So instead of having deeply nested keys like `foo.bar.baz.0.key_to_delete` you can have `key_to_delete` and
|
||||
// all occurences of `key_to_delete` will be removed.
|
||||
//
|
||||
// DEPRECATED: please use SnapshotT instead
|
||||
func SnapshotTExceptMatchingKeys(t *testing.T, actual interface{}, matches []string) {
|
||||
t.Helper()
|
||||
compare, err := json.MarshalIndent(actual, "", " ")
|
||||
require.NoError(t, err, "%+v", actual)
|
||||
|
||||
parsed := gjson.ParseBytes(compare)
|
||||
require.True(t, parsed.IsObject() || parsed.IsArray())
|
||||
compare = deleteMatches(t, "", parsed, matches, []string{}, compare)
|
||||
|
||||
cupaloy.New(
|
||||
cupaloy.CreateNewAutomatically(true),
|
||||
cupaloy.FailOnUpdate(true),
|
||||
cupaloy.SnapshotFileExtension(".json"),
|
||||
).SnapshotT(t, compare)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,4 +70,3 @@
|
|||
},
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,4 +70,3 @@
|
|||
},
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,4 +70,3 @@
|
|||
},
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,4 +70,3 @@
|
|||
},
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,4 +53,3 @@
|
|||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,4 +39,3 @@
|
|||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,4 +53,3 @@
|
|||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,4 +251,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,4 +251,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,4 +251,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,4 +251,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,4 +251,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,4 +251,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,8 +67,12 @@
|
|||
"text": "You tried to sign in with \"email-exist-with-oidc-strategy-lh-true@ory.sh\", but that email is already used by another account. Sign in to your account with one of the options below to add your account \"email-exist-with-oidc-strategy-lh-true@ory.sh\" at \"generic\" as another way to sign in.",
|
||||
"type": "info",
|
||||
"context": {
|
||||
"available_credential_types": ["oidc"],
|
||||
"available_providers": ["secondProvider"],
|
||||
"available_credential_types": [
|
||||
"oidc"
|
||||
],
|
||||
"available_providers": [
|
||||
"secondProvider"
|
||||
],
|
||||
"duplicateIdentifier": "email-exist-with-oidc-strategy-lh-true@ory.sh",
|
||||
"duplicate_identifier": "email-exist-with-oidc-strategy-lh-true@ory.sh",
|
||||
"provider": "generic"
|
||||
|
|
@ -80,4 +84,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,8 +67,12 @@
|
|||
"text": "You tried to sign in with \"email-exist-with-oidc-strategy-lh-true@ory.sh\", but that email is already used by another account. Sign in to your account with one of the options below to add your account \"email-exist-with-oidc-strategy-lh-true@ory.sh\" at \"generic\" as another way to sign in.",
|
||||
"type": "info",
|
||||
"context": {
|
||||
"available_credential_types": ["oidc"],
|
||||
"available_providers": ["secondProvider"],
|
||||
"available_credential_types": [
|
||||
"oidc"
|
||||
],
|
||||
"available_providers": [
|
||||
"secondProvider"
|
||||
],
|
||||
"duplicateIdentifier": "email-exist-with-oidc-strategy-lh-true@ory.sh",
|
||||
"duplicate_identifier": "email-exist-with-oidc-strategy-lh-true@ory.sh",
|
||||
"provider": "generic"
|
||||
|
|
@ -80,4 +84,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,8 +67,12 @@
|
|||
"text": "You tried to sign in with \"email-exist-with-oidc-strategy-lh-true@ory.sh\", but that email is already used by another account. Sign in to your account with one of the options below to add your account \"email-exist-with-oidc-strategy-lh-true@ory.sh\" at \"generic\" as another way to sign in.",
|
||||
"type": "info",
|
||||
"context": {
|
||||
"available_credential_types": ["oidc"],
|
||||
"available_providers": ["secondProvider"],
|
||||
"available_credential_types": [
|
||||
"oidc"
|
||||
],
|
||||
"available_providers": [
|
||||
"secondProvider"
|
||||
],
|
||||
"duplicateIdentifier": "email-exist-with-oidc-strategy-lh-true@ory.sh",
|
||||
"duplicate_identifier": "email-exist-with-oidc-strategy-lh-true@ory.sh",
|
||||
"provider": "generic"
|
||||
|
|
@ -80,4 +84,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@
|
|||
"text": "You tried to sign in with \"email-exist-with-password-strategy-lh-true@ory.sh\", but that email is already used by another account. Sign in to your account with one of the options below to add your account \"email-exist-with-password-strategy-lh-true@ory.sh\" at \"generic\" as another way to sign in.",
|
||||
"type": "info",
|
||||
"context": {
|
||||
"available_credential_types": ["password"],
|
||||
"available_credential_types": [
|
||||
"password"
|
||||
],
|
||||
"available_providers": [],
|
||||
"duplicateIdentifier": "email-exist-with-password-strategy-lh-true@ory.sh",
|
||||
"duplicate_identifier": "email-exist-with-password-strategy-lh-true@ory.sh",
|
||||
|
|
@ -97,4 +99,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@
|
|||
"text": "You tried to sign in with \"email-exist-with-password-strategy-lh-true@ory.sh\", but that email is already used by another account. Sign in to your account with one of the options below to add your account \"email-exist-with-password-strategy-lh-true@ory.sh\" at \"generic\" as another way to sign in.",
|
||||
"type": "info",
|
||||
"context": {
|
||||
"available_credential_types": ["password"],
|
||||
"available_credential_types": [
|
||||
"password"
|
||||
],
|
||||
"available_providers": [],
|
||||
"duplicateIdentifier": "email-exist-with-password-strategy-lh-true@ory.sh",
|
||||
"duplicate_identifier": "email-exist-with-password-strategy-lh-true@ory.sh",
|
||||
|
|
@ -97,4 +99,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@
|
|||
"text": "You tried to sign in with \"email-exist-with-password-strategy-lh-true@ory.sh\", but that email is already used by another account. Sign in to your account with one of the options below to add your account \"email-exist-with-password-strategy-lh-true@ory.sh\" at \"generic\" as another way to sign in.",
|
||||
"type": "info",
|
||||
"context": {
|
||||
"available_credential_types": ["password"],
|
||||
"available_credential_types": [
|
||||
"password"
|
||||
],
|
||||
"available_providers": [],
|
||||
"duplicateIdentifier": "email-exist-with-password-strategy-lh-true@ory.sh",
|
||||
"duplicate_identifier": "email-exist-with-password-strategy-lh-true@ory.sh",
|
||||
|
|
@ -97,4 +99,3 @@
|
|||
"requested_aal": "aal1",
|
||||
"state": "choose_method"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -555,7 +555,7 @@ func TestPopulateRegistrationMethod(t *testing.T) {
|
|||
fh, ok := s.(registration.FormHydrator)
|
||||
require.True(t, ok)
|
||||
|
||||
toSnapshot := func(t *testing.T, f node.Nodes, except ...snapshotx.ExceptOpt) {
|
||||
toSnapshot := func(t *testing.T, f node.Nodes, except ...snapshotx.Opt) {
|
||||
t.Helper()
|
||||
// The CSRF token has a unique value that messes with the snapshot - ignore it.
|
||||
f.ResetNodes("csrf_token")
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ func TestCompleteLogin(t *testing.T) {
|
|||
}
|
||||
|
||||
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
|
||||
snapshotx.SnapshotTExceptMatchingKeys(t, json.RawMessage(body), []string{"value", "src", "nonce", "action", "request_url", "issued_at", "expires_at", "created_at", "updated_at", "id", "onclick"})
|
||||
snapshotx.SnapshotTJSON(t, body, snapshotx.ExceptNestedKeys("value", "src", "nonce", "action", "request_url", "issued_at", "expires_at", "created_at", "updated_at", "id", "onclick"))
|
||||
assert.Equal(t, text.NewInfoLoginWebAuthnPasswordless().Text, gjson.Get(body, "ui.messages.0.text").String(), "%s", body)
|
||||
|
||||
values.Set(node.WebAuthnLogin, string(loginFixtureSuccessResponseInvalid))
|
||||
|
|
|
|||
|
|
@ -561,7 +561,7 @@ func TestPopulateRegistrationMethod(t *testing.T) {
|
|||
fh, ok := s.(registration.FormHydrator)
|
||||
require.True(t, ok)
|
||||
|
||||
toSnapshot := func(t *testing.T, f node.Nodes, except ...snapshotx.ExceptOpt) {
|
||||
toSnapshot := func(t *testing.T, f node.Nodes, except ...snapshotx.Opt) {
|
||||
t.Helper()
|
||||
// The CSRF token has a unique value that messes with the snapshot - ignore it.
|
||||
f.ResetNodes("csrf_token")
|
||||
|
|
|
|||
Loading…
Reference in New Issue