Skip to content

Commit

Permalink
feat: improve test readability for password method
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr committed Aug 28, 2020
1 parent e08ece9 commit a896d9b
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 160 deletions.
58 changes: 22 additions & 36 deletions internal/testhelpers/selfservice_login.go
Expand Up @@ -2,7 +2,6 @@ package testhelpers

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
Expand All @@ -22,7 +21,6 @@ import (
"github.com/ory/kratos/internal/httpclient/client/common"
"github.com/ory/kratos/internal/httpclient/models"
"github.com/ory/kratos/selfservice/flow/login"
"github.com/ory/kratos/selfservice/strategy/password"
"github.com/ory/kratos/x"
)

Expand Down Expand Up @@ -93,56 +91,44 @@ func LoginMakeRequest(
return string(x.MustReadAll(res.Body)), res
}

// SubmitLoginFormAndExpectValidationError initiates a login 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 SubmitLoginFormAndExpectValidationError(
// SubmitLoginForm initiates a login flow (for Browser and API!), fills out the form and modifies
// the form values with `withValues`, and submits the form. Returns the body and checks for expectedStatusCode and
// expectedURL on completion
func SubmitLoginForm(
t *testing.T,
isAPI bool,
hc *http.Client,
publicTS *httptest.Server,
withValues func(v url.Values) url.Values,
withValues func(v url.Values),
method identity.CredentialsType,
forced bool,
expectedStatusCode int,
expectedURL string,
) string {
if hc == nil {
hc = new(http.Client)
if !isAPI {
hc = NewClientWithCookies(t)
}
}

hc.Transport = NewTransportWithLogger(hc.Transport, t)
var payload *models.LoginFlow
var f *models.LoginFlow
if isAPI {
payload = InitializeLoginFlowViaAPI(t, hc, publicTS, forced).Payload
f = InitializeLoginFlowViaAPI(t, hc, publicTS, forced).Payload
} else {
payload = InitializeLoginFlowViaBrowser(t, hc, publicTS, forced).Payload
f = InitializeLoginFlowViaBrowser(t, hc, publicTS, forced).Payload
}

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

config := GetLoginFlowMethodConfig(t, payload, method.String())
config := GetLoginFlowMethodConfig(t, f, method.String())

b, res := LoginMakeRequest(t, isAPI, config, hc, EncodeFormAsJSON(t, isAPI,
withValues(SDKFormFieldsToURLValues(config.Fields))))
payload := SDKFormFieldsToURLValues(config.Fields)
withValues(payload)
b, res := LoginMakeRequest(t, isAPI, config, hc, EncodeFormAsJSON(t, isAPI, payload))
assert.EqualValues(t, expectedStatusCode, res.StatusCode, "%s", b)
assert.Contains(t, res.Request.URL.String(), expectedURL, "%+v\n\t%s", res.Request, b)

expectURL := viper.GetString(configuration.ViperKeySelfServiceLoginUI)
if isAPI {
switch method {
case identity.CredentialsTypePassword:
expectURL = password.RouteLogin
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.GetSelfServiceLoginFlow(
common.NewGetSelfServiceLoginFlowParams().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)
return b
}
49 changes: 15 additions & 34 deletions internal/testhelpers/selfservice_registration.go
Expand Up @@ -2,7 +2,6 @@ package testhelpers

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
Expand All @@ -21,7 +20,6 @@ import (
"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"
)

Expand Down Expand Up @@ -82,17 +80,23 @@ func RegistrationMakeRequest(
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(
// SubmitRegistrationForm (for Browser and API!), fills out the form and modifies
// // the form values with `withValues`, and submits the form. Returns the body and checks for expectedStatusCode and
// // expectedURL on completion
func SubmitRegistrationForm(
t *testing.T,
isAPI bool,
hc *http.Client,
publicTS *httptest.Server,
withValues func(v url.Values) url.Values,
withValues func(v url.Values),
method identity.CredentialsType,
expectedStatusCode int,
expectedURL string,
) string {
if hc == nil {
hc = new(http.Client)
}

hc.Transport = NewTransportWithLogger(hc.Transport, t)
var payload *models.RegistrationFlow
if isAPI {
Expand All @@ -104,33 +108,10 @@ func SubmitRegistrationFormAndExpectValidationError(
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))))
values := SDKFormFieldsToURLValues(config.Fields)
withValues(values)
b, res := RegistrationMakeRequest(t, isAPI, config, hc, EncodeFormAsJSON(t, isAPI, values))
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)
assert.Contains(t, res.Request.URL.String(), expectedURL, "%+v\n\t%s", res.Request, b)
return b
}
2 changes: 1 addition & 1 deletion selfservice/flow/registration/persistence.go
Expand Up @@ -120,6 +120,7 @@ func TestFlowPersister(p FlowPersister) func(t *testing.T) {

t.Run("case=should not cause data loss when updating a request without changes", func(t *testing.T) {
expected := newFlow(t)
expected.Active = ""
err := p.CreateRegistrationFlow(context.Background(), expected)
require.NoError(t, err)

Expand All @@ -132,7 +133,6 @@ func TestFlowPersister(p FlowPersister) func(t *testing.T) {
actual, err = p.GetRegistrationFlow(context.Background(), expected.ID)
require.NoError(t, err)
require.Len(t, actual.Methods, 2)
assert.EqualValues(t, identity.CredentialsTypePassword, actual.Active)

assert.Equal(t,
expected.Methods[identity.CredentialsTypePassword].Config.FlowMethodConfigurator.(*form.HTMLForm).Action,
Expand Down
66 changes: 28 additions & 38 deletions selfservice/strategy/password/login_test.go
Expand Up @@ -35,15 +35,15 @@ import (
)

func TestCompleteLogin(t *testing.T) {
_, reg := internal.NewFastRegistryWithMocks(t)
conf, reg := internal.NewFastRegistryWithMocks(t)

viper.Set(configuration.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypePassword),
map[string]interface{}{"enabled": true})
publicTS, _ := testhelpers.NewKratosServer(t, reg)

errTS := testhelpers.NewErrorTestServer(t, reg)
uiTS := testhelpers.NewLoginUIFlowEchoServer(t, reg)
newReturnTs(t, reg)
redirTS := newReturnTs(t, reg)

// Overwrite these two:
viper.Set(configuration.ViperKeySelfServiceErrorUI, errTS.URL+"/error-ts")
Expand Down Expand Up @@ -181,28 +181,31 @@ func TestCompleteLogin(t *testing.T) {
})
})

var expectValidationError = func(t *testing.T, isAPI, forced bool, values func(url.Values)) string {
return testhelpers.SubmitLoginForm(t, isAPI, nil, publicTS, values,
identity.CredentialsTypePassword, forced,
testhelpers.ExpectStatusCode(isAPI, http.StatusBadRequest, http.StatusOK),
testhelpers.ExpectURL(isAPI, publicTS.URL+password.RouteLogin, conf.SelfServiceFlowLoginUI().String()))
}

t.Run("should return an error because the credentials are invalid (user does not exist)", func(t *testing.T) {
var check = func(t *testing.T, body string) {
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
assert.Contains(t, gjson.Get(body, "methods.password.config.action").String(), publicTS.URL+password.RouteLogin, "%s", body)
assert.Equal(t, text.NewErrorValidationInvalidCredentials().Text, gjson.Get(body, "methods.password.config.messages.0.text").String())
}

var values = func(v url.Values) url.Values {
var values = func(v url.Values) {
v.Set("identifier", "identifier")
v.Set("password", "password")
return v
}

t.Run("type=browser", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
actual := testhelpers.SubmitLoginFormAndExpectValidationError(t, false, browserClient, publicTS, values, identity.CredentialsTypePassword, false, http.StatusOK)
check(t, actual)
check(t, expectValidationError(t, false, false, values))
})

t.Run("type=api", func(t *testing.T) {
actual := testhelpers.SubmitLoginFormAndExpectValidationError(t, true, apiClient, publicTS, values, identity.CredentialsTypePassword, false, http.StatusBadRequest)
check(t, actual)
check(t, expectValidationError(t, true, false, values))
})
})

Expand All @@ -218,21 +221,17 @@ func TestCompleteLogin(t *testing.T) {
assert.Empty(t, gjson.Get(body, "methods.password.config.fields.#(name==password).value").String())
}

var values = func(v url.Values) url.Values {
var values = func(v url.Values) {
v.Del("identifier")
v.Set("password", "password")
return v
}

t.Run("type=browser", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
actual := testhelpers.SubmitLoginFormAndExpectValidationError(t, false, browserClient, publicTS, values, identity.CredentialsTypePassword, false, http.StatusOK)
check(t, actual)
check(t, expectValidationError(t, false, false, values))
})

t.Run("type=api", func(t *testing.T) {
actual := testhelpers.SubmitLoginFormAndExpectValidationError(t, true, apiClient, publicTS, values, identity.CredentialsTypePassword, false, http.StatusBadRequest)
check(t, actual)
check(t, expectValidationError(t, true, false, values))
})
})

Expand All @@ -249,21 +248,17 @@ func TestCompleteLogin(t *testing.T) {
assert.Empty(t, gjson.Get(body, "methods.password.config.fields.#(name==password).value").String())
}

var values = func(v url.Values) url.Values {
var values = func(v url.Values) {
v.Set("identifier", "identifier")
v.Del("password")
return v
}

t.Run("type=browser", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
actual := testhelpers.SubmitLoginFormAndExpectValidationError(t, false, browserClient, publicTS, values, identity.CredentialsTypePassword, false, http.StatusOK)
check(t, actual)
check(t, expectValidationError(t, false, false, values))
})

t.Run("type=api", func(t *testing.T) {
actual := testhelpers.SubmitLoginFormAndExpectValidationError(t, true, apiClient, publicTS, values, identity.CredentialsTypePassword, false, http.StatusBadRequest)
check(t, actual)
check(t, expectValidationError(t, true, false, values))
})
})

Expand All @@ -286,42 +281,35 @@ func TestCompleteLogin(t *testing.T) {
identifier, pwd := x.NewUUID().String(), "password"
createIdentity(identifier, pwd)

var values = func(v url.Values) url.Values {
var values = func(v url.Values) {
v.Set("identifier", identifier)
v.Set("password", "not-password")
return v
}

t.Run("type=browser", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
actual := testhelpers.SubmitLoginFormAndExpectValidationError(t, false, browserClient, publicTS, values, identity.CredentialsTypePassword, false, http.StatusOK)
check(t, actual)
check(t, expectValidationError(t, false, false, values))
})

t.Run("type=api", func(t *testing.T) {
actual := testhelpers.SubmitLoginFormAndExpectValidationError(t, true, apiClient, publicTS, values, identity.CredentialsTypePassword, false, http.StatusBadRequest)
check(t, actual)
check(t, expectValidationError(t, true, false, values))
})
})

t.Run("should pass with real request", func(t *testing.T) {
identifier, pwd := x.NewUUID().String(), "password"
createIdentity(identifier, pwd)

var values = func(v url.Values) url.Values {
var values = func(v url.Values) {
v.Set("identifier", identifier)
v.Set("password", pwd)
return v
}

t.Run("type=browser", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false)
c := testhelpers.GetLoginFlowMethodConfig(t, f.Payload, identity.CredentialsTypePassword.String())

body, res := testhelpers.LoginMakeRequest(t, false, c, browserClient, values(testhelpers.SDKFormFieldsToURLValues(c.Fields)).Encode())
require.EqualValues(t, http.StatusOK, res.StatusCode)
require.Contains(t, res.Request.URL.Path, "return-ts", "%s", res.Request.URL.String())
body := testhelpers.SubmitLoginForm(t, false, browserClient, publicTS, values,
identity.CredentialsTypePassword, false, http.StatusOK, redirTS.URL)

assert.Equal(t, identifier, gjson.Get(body, "identity.traits.subject").String(), "%s", body)

t.Run("retry with different refresh", func(t *testing.T) {
Expand Down Expand Up @@ -353,7 +341,9 @@ func TestCompleteLogin(t *testing.T) {
})

t.Run("type=api", func(t *testing.T) {
body := testhelpers.SubmitLoginFormAndExpectValidationError(t, true, apiClient, publicTS, values, identity.CredentialsTypePassword, false, http.StatusOK)
body := testhelpers.SubmitLoginForm(t, true, nil, publicTS, values,
identity.CredentialsTypePassword, false, http.StatusOK, publicTS.URL+password.RouteLogin)

assert.Equal(t, identifier, gjson.Get(body, "session.identity.traits.subject").String(), "%s", body)
st := gjson.Get(body, "session_token").String()
assert.NotEmpty(t, st, "%s", body)
Expand Down

0 comments on commit a896d9b

Please sign in to comment.