Skip to content

Commit

Permalink
refactor: improve registration tests with testhelpers
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr committed Aug 26, 2020
1 parent 8d47113 commit 9bf4530
Show file tree
Hide file tree
Showing 21 changed files with 489 additions and 369 deletions.
4 changes: 4 additions & 0 deletions internal/testhelpers/http.go
Expand Up @@ -11,6 +11,10 @@ import (
"github.com/stretchr/testify/require"
)

func NewDebugClient(t *testing.T) *http.Client {
return &http.Client{Transport: NewTransportWithLogger(http.DefaultTransport, t)}
}

func NewHTTPGetJSONRequest(t *testing.T, url string) *http.Request {
req, err := http.NewRequest("GET", url, nil)
require.NoError(t, err)
Expand Down
Expand Up @@ -5,12 +5,15 @@ import (
"net/http/httptest"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/ory/viper"

"github.com/ory/kratos/driver"
"github.com/ory/kratos/driver/configuration"
"github.com/ory/kratos/internal/httpclient/client/common"
"github.com/ory/kratos/selfservice/flow/login"
"github.com/ory/kratos/x"
)

Expand Down Expand Up @@ -46,3 +49,31 @@ func NewSettingsUIFlowEchoServer(t *testing.T, reg driver.Registry) *httptest.Se
t.Cleanup(ts.Close)
return ts
}

func InitializeLoginFlowViaBrowser(t *testing.T, client *http.Client, ts *httptest.Server) *common.GetSelfServiceLoginFlowOK {
publicClient := NewSDKClient(ts)

res, err := client.Get(ts.URL + login.RouteInitBrowserFlow)
require.NoError(t, err)
require.NoError(t, res.Body.Close())

rs, err := publicClient.Common.GetSelfServiceLoginFlow(
common.NewGetSelfServiceLoginFlowParams().WithHTTPClient(client).
WithID(res.Request.URL.Query().Get("flow")),
)
require.NoError(t, err)
assert.Empty(t, rs.Payload.Active)

return rs
}

func InitializeLoginFlowViaAPI(t *testing.T, client *http.Client, ts *httptest.Server) *common.InitializeSelfServiceLoginViaAPIFlowOK {
publicClient := NewSDKClient(ts)

rs, err := publicClient.Common.InitializeSelfServiceLoginViaAPIFlow(common.
NewInitializeSelfServiceLoginViaAPIFlowParams().WithHTTPClient(client))
require.NoError(t, err)
assert.Empty(t, rs.Payload.Active)

return rs
}
134 changes: 134 additions & 0 deletions internal/testhelpers/selfservice_registration.go
@@ -0,0 +1,134 @@
package testhelpers

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/ory/viper"
"github.com/ory/x/pointerx"

"github.com/ory/kratos/driver/configuration"
"github.com/ory/kratos/identity"
"github.com/ory/kratos/internal/httpclient/client/common"
"github.com/ory/kratos/internal/httpclient/models"
"github.com/ory/kratos/selfservice/flow/registration"
"github.com/ory/kratos/selfservice/strategy/password"
"github.com/ory/kratos/x"
)

func InitializeRegistrationFlowViaBrowser(t *testing.T, client *http.Client, ts *httptest.Server) *common.GetSelfServiceRegistrationFlowOK {
res, err := client.Get(ts.URL + registration.RouteInitBrowserFlow)
require.NoError(t, err)
require.NoError(t, res.Body.Close())

rs, err := NewSDKClient(ts).Common.GetSelfServiceRegistrationFlow(
common.NewGetSelfServiceRegistrationFlowParams().WithHTTPClient(client).
WithID(res.Request.URL.Query().Get("flow")))
require.NoError(t, err)
assert.Empty(t, rs.Payload.Active)

return rs
}

func InitializeRegistrationFlowViaAPI(t *testing.T, client *http.Client, ts *httptest.Server) *common.InitializeSelfServiceRegistrationViaAPIFlowOK {
rs, err := NewSDKClient(ts).Common.InitializeSelfServiceRegistrationViaAPIFlow(common.
NewInitializeSelfServiceRegistrationViaAPIFlowParams().WithHTTPClient(client))
require.NoError(t, err)
assert.Empty(t, rs.Payload.Active)

return rs
}

func GetRegistrationFlowMethodConfig(t *testing.T, rs *models.RegistrationFlow, id string) *models.RegistrationFlowMethodConfig {
require.NotEmpty(t, rs.Methods[id])
require.NotEmpty(t, rs.Methods[id].Config)
require.NotEmpty(t, rs.Methods[id].Config.Action)
return rs.Methods[id].Config
}

func RegistrationMakeRequest(
t *testing.T,
isAPI bool,
f *models.RegistrationFlowMethodConfig,
hc *http.Client,
values string,
) (string, *http.Response) {
require.NotEmpty(t, f.Action)

req, err := http.NewRequest("POST", pointerx.StringR(f.Action), bytes.NewBufferString(values))
require.NoError(t, err)

req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "text/html")
if isAPI {
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
}

res, err := hc.Do(req)
require.NoError(t, err)
defer res.Body.Close()

return string(x.MustReadAll(res.Body)), res
}

// SubmitRegistrationFormAndExpectValidationError initiates a registration flow (for Browser and API!), fills out the form and modifies
// the form values with `withValues`, and submits the form. If completed, it will return the flow as JSON.
func SubmitRegistrationFormAndExpectValidationError(
t *testing.T,
isAPI bool,
hc *http.Client,
publicTS *httptest.Server,
withValues func(v url.Values) url.Values,
method identity.CredentialsType,
expectedStatusCode int,
) string {
hc.Transport = NewTransportWithLogger(hc.Transport, t)
var payload *models.RegistrationFlow
if isAPI {
payload = InitializeRegistrationFlowViaAPI(t, hc, publicTS).Payload
} else {
payload = InitializeRegistrationFlowViaBrowser(t, hc, publicTS).Payload
}

time.Sleep(time.Millisecond) // add a bit of delay to allow `1ns` to time out.

config := GetRegistrationFlowMethodConfig(t, payload, method.String())

b, res := RegistrationMakeRequest(t, isAPI, config, hc, EncodeFormAsJSON(t, isAPI,
withValues(SDKFormFieldsToURLValues(config.Fields))))
assert.EqualValues(t, expectedStatusCode, res.StatusCode, "%s", b)

expectURL := viper.GetString(configuration.ViperKeySelfServiceRegistrationUI)
if isAPI {
switch method {
case identity.CredentialsTypePassword:
expectURL = password.RouteRegistration
default:
t.Logf("Expected method to be profile ior password but got: %s", method)
t.FailNow()
}
}

assert.Contains(t, res.Request.URL.String(), expectURL, "%+v\n\t%s", res.Request, b)

if isAPI {
return b
}

rs, err := NewSDKClientFromURL(viper.GetString(configuration.ViperKeyPublicBaseURL)).Common.GetSelfServiceRegistrationFlow(
common.NewGetSelfServiceRegistrationFlowParams().WithHTTPClient(hc).WithID(res.Request.URL.Query().Get("flow")))
require.NoError(t, err)

body, err := json.Marshal(rs.Payload)
require.NoError(t, err)
return string(body)
}
2 changes: 1 addition & 1 deletion internal/testhelpers/selfservice_settings.go
Expand Up @@ -247,7 +247,7 @@ func SubmitSettingsForm(
method string,
expectedStatusCode int,
) string {
hc.Transport = NewTransportWithLogger(hc.Transport , t)
hc.Transport = NewTransportWithLogger(hc.Transport, t)
var payload *models.SettingsFlow
if isAPI {
payload = InitializeSettingsFlowViaAPI(t, hc, publicTS).Payload
Expand Down
3 changes: 1 addition & 2 deletions internal/testhelpers/session.go
Expand Up @@ -64,7 +64,7 @@ func NewHTTPClientWithSessionCookie(t *testing.T, reg *driver.RegistryDefault, s
func NewTransportWithLogger(parent http.RoundTripper, t *testing.T) *TransportWithLogger {
return &TransportWithLogger{
RoundTripper: parent,
t:t,
t: t,
}
}

Expand All @@ -81,7 +81,6 @@ func (ct *TransportWithLogger) RoundTrip(req *http.Request) (*http.Response, err
return ct.RoundTripper.RoundTrip(req)
}


func NewHTTPClientWithSessionToken(t *testing.T, reg *driver.RegistryDefault, sess *session.Session) *http.Client {
maybePersistSession(t, reg, sess)

Expand Down
6 changes: 3 additions & 3 deletions selfservice/flow/registration/flow_method.go
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/ory/kratos/selfservice/form"
)

// swagger:model registrationRequestMethod
// swagger:model registrationFlowMethod
type FlowMethod struct {
// Method contains the flow method's credentials type.
Method identity.CredentialsType `json:"method" faker:"string" db:"method"`
Expand Down Expand Up @@ -67,15 +67,15 @@ type FlowMethodConfigurator interface {
form.MessageAdder
}

// swagger:model registrationRequestMethodConfig
// swagger:model registrationFlowMethodConfig
type FlowMethodConfig struct {
// swagger:ignore
FlowMethodConfigurator

flowMethodConfigMock
}

// swagger:model registrationRequestMethodConfigPayload
// swagger:model registrationFlowMethodConfigPayload
type flowMethodConfigMock struct {
*form.HTMLForm

Expand Down
3 changes: 2 additions & 1 deletion selfservice/flow/request.go
Expand Up @@ -4,9 +4,10 @@ import (
"net/http"

"github.com/justinas/nosurf"
"github.com/ory/herodot"
"github.com/pkg/errors"

"github.com/ory/herodot"

"github.com/ory/kratos/x"
)

Expand Down
4 changes: 2 additions & 2 deletions selfservice/flow/request_test.go
Expand Up @@ -14,9 +14,9 @@ func TestVerifyRequest(t *testing.T) {
require.NoError(t, VerifyRequest(&http.Request{}, TypeBrowser, x.FakeCSRFTokenGenerator, x.FakeCSRFToken), nil)
require.NoError(t, VerifyRequest(&http.Request{}, TypeAPI, x.FakeCSRFTokenGenerator, ""))
require.EqualError(t, VerifyRequest(&http.Request{
Header: http.Header{"Origin":{"https://www.ory.sh"}},
Header: http.Header{"Origin": {"https://www.ory.sh"}},
}, TypeAPI, x.FakeCSRFTokenGenerator, ""), ErrOriginHeaderNeedsBrowserFlow.Error())
require.EqualError(t, VerifyRequest(&http.Request{
Header: http.Header{"Cookie":{"cookie=ory"}},
Header: http.Header{"Cookie": {"cookie=ory"}},
}, TypeAPI, x.FakeCSRFTokenGenerator, ""), ErrCookieHeaderNeedsBrowserFlow.Error())
}
2 changes: 1 addition & 1 deletion selfservice/flow/settings/error.go
Expand Up @@ -20,7 +20,7 @@ import (
)

var (
ErrHookAbortRequest = errors.New("aborted settings hook execution")
ErrHookAbortRequest = errors.New("aborted settings hook execution")
)

type (
Expand Down
2 changes: 1 addition & 1 deletion selfservice/flow/settings/flow_method.go
Expand Up @@ -66,7 +66,7 @@ type FlowMethodConfigurator interface {
form.MessageAdder
}

// swagger:type settingsFlowMethodConfigPayload
// swagger:type settingsFlowMethodConfig
type FlowMethodConfig struct {
// swagger:ignore
FlowMethodConfigurator
Expand Down
2 changes: 1 addition & 1 deletion selfservice/flow/settings/hook.go
Expand Up @@ -189,7 +189,7 @@ func (e *HookExecutor) PostSettingsHook(w http.ResponseWriter, r *http.Request,
Debug("Completed all PostSettingsPrePersistHooks and PostSettingsPostPersistHooks.")

if ctxUpdate.Flow.Type == flow.TypeAPI {
updatedFlow, err := e.d.SettingsFlowPersister().GetSettingsFlow(r.Context(),ctxUpdate.Flow.ID)
updatedFlow, err := e.d.SettingsFlowPersister().GetSettingsFlow(r.Context(), ctxUpdate.Flow.ID)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion selfservice/strategy/password/login.go
Expand Up @@ -110,7 +110,7 @@ func (s *Strategy) handleLogin(w http.ResponseWriter, r *http.Request, _ httprou
return
}

if err := flow.VerifyRequest(r,ar.Type,s.d.GenerateCSRFToken,p.CSRFToken); err != nil {
if err := flow.VerifyRequest(r, ar.Type, s.d.GenerateCSRFToken, p.CSRFToken); err != nil {
s.handleLoginError(w, r, ar, &p, x.ErrInvalidCSRFToken)
return
}
Expand Down
4 changes: 2 additions & 2 deletions selfservice/strategy/password/registration.go
Expand Up @@ -35,7 +35,7 @@ const (
type RegistrationFormPayload struct {
Password string `json:"password"`
Traits json.RawMessage `json:"traits"`
CSRFToken string `json:"csrf_token"`
CSRFToken string `json:"csrf_token"`
}

func (s *Strategy) RegisterRegistrationRoutes(public *x.RouterPublic) {
Expand Down Expand Up @@ -164,7 +164,7 @@ func (s *Strategy) handleRegistration(w http.ResponseWriter, r *http.Request, _
return
}

if err := flow.VerifyRequest(r,ar.Type,s.d.GenerateCSRFToken,p.CSRFToken); err != nil {
if err := flow.VerifyRequest(r, ar.Type, s.d.GenerateCSRFToken, p.CSRFToken); err != nil {
s.handleRegistrationError(w, r, ar, &p, err)
return
}
Expand Down

0 comments on commit 9bf4530

Please sign in to comment.