run added password reset and verification sent hooks tests

This commit is contained in:
Gani Georgiev 2022-07-19 14:20:28 +03:00
parent 383b2a1279
commit f295ce9403
5 changed files with 86 additions and 36 deletions

View File

@ -34,6 +34,9 @@ jobs:
# - name: Run linter # - name: Run linter
# uses: golangci/golangci-lint-action@v3 # uses: golangci/golangci-lint-action@v3
- name: Run tests
run: go test ./...
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3 uses: goreleaser/goreleaser-action@v3
with: with:

View File

@ -7,8 +7,10 @@ import (
"github.com/labstack/echo/v5" "github.com/labstack/echo/v5"
"github.com/pocketbase/dbx" "github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
"github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/tests" "github.com/pocketbase/pocketbase/tests"
"github.com/pocketbase/pocketbase/tools/types"
) )
func TestAdminAuth(t *testing.T) { func TestAdminAuth(t *testing.T) {
@ -100,14 +102,12 @@ func TestAdminRequestPasswordReset(t *testing.T) {
Url: "/api/admins/request-password-reset", Url: "/api/admins/request-password-reset",
Body: strings.NewReader(`{"email":"test@example.com"}`), Body: strings.NewReader(`{"email":"test@example.com"}`),
ExpectedStatus: 204, ExpectedStatus: 204,
// usually this events are fired but since the submit is ExpectedEvents: map[string]int{
// executed in a separate go routine they are fired async "OnModelBeforeUpdate": 1,
// ExpectedEvents: map[string]int{ "OnModelAfterUpdate": 1,
// "OnModelBeforeUpdate": 1, "OnMailerBeforeAdminResetPasswordSend": 1,
// "OnModelAfterUpdate": 1, "OnMailerAfterAdminResetPasswordSend": 1,
// "OnMailerBeforeUserResetPasswordSend:1": 1, },
// "OnMailerAfterUserResetPasswordSend:1": 1,
// },
}, },
{ {
Name: "existing admin (after already sent)", Name: "existing admin (after already sent)",
@ -115,6 +115,18 @@ func TestAdminRequestPasswordReset(t *testing.T) {
Url: "/api/admins/request-password-reset", Url: "/api/admins/request-password-reset",
Body: strings.NewReader(`{"email":"test@example.com"}`), Body: strings.NewReader(`{"email":"test@example.com"}`),
ExpectedStatus: 204, ExpectedStatus: 204,
BeforeFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
// simulate recent password request
admin, err := app.Dao().FindAdminByEmail("test@example.com")
if err != nil {
t.Fatal(err)
}
admin.LastResetSentAt = types.NowDateTime()
dao := daos.New(app.Dao().DB()) // new dao to ignore hooks
if err := dao.Save(admin); err != nil {
t.Fatal(err)
}
},
}, },
} }

View File

@ -6,7 +6,9 @@ import (
"testing" "testing"
"github.com/labstack/echo/v5" "github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase/daos"
"github.com/pocketbase/pocketbase/tests" "github.com/pocketbase/pocketbase/tests"
"github.com/pocketbase/pocketbase/tools/types"
) )
func TestUsersAuthMethods(t *testing.T) { func TestUsersAuthMethods(t *testing.T) {
@ -140,14 +142,12 @@ func TestUserRequestPasswordReset(t *testing.T) {
Url: "/api/users/request-password-reset", Url: "/api/users/request-password-reset",
Body: strings.NewReader(`{"email":"test@example.com"}`), Body: strings.NewReader(`{"email":"test@example.com"}`),
ExpectedStatus: 204, ExpectedStatus: 204,
// usually this events are fired but since the submit is ExpectedEvents: map[string]int{
// executed in a separate go routine they are fired async "OnModelBeforeUpdate": 1,
// ExpectedEvents: map[string]int{ "OnModelAfterUpdate": 1,
// "OnModelBeforeUpdate": 1, "OnMailerBeforeUserResetPasswordSend": 1,
// "OnModelAfterUpdate": 1, "OnMailerAfterUserResetPasswordSend": 1,
// "OnMailerBeforeUserResetPasswordSend": 1, },
// "OnMailerAfterUserResetPasswordSend": 1,
// },
}, },
{ {
Name: "existing user (after already sent)", Name: "existing user (after already sent)",
@ -155,6 +155,18 @@ func TestUserRequestPasswordReset(t *testing.T) {
Url: "/api/users/request-password-reset", Url: "/api/users/request-password-reset",
Body: strings.NewReader(`{"email":"test@example.com"}`), Body: strings.NewReader(`{"email":"test@example.com"}`),
ExpectedStatus: 204, ExpectedStatus: 204,
BeforeFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
// simulate recent password request
user, err := app.Dao().FindUserByEmail("test@example.com")
if err != nil {
t.Fatal(err)
}
user.LastResetSentAt = types.NowDateTime()
dao := daos.New(app.Dao().DB()) // new dao to ignore hooks
if err := dao.Save(user); err != nil {
t.Fatal(err)
}
},
}, },
} }
@ -216,50 +228,67 @@ func TestUserConfirmPasswordReset(t *testing.T) {
func TestUserRequestVerification(t *testing.T) { func TestUserRequestVerification(t *testing.T) {
scenarios := []tests.ApiScenario{ scenarios := []tests.ApiScenario{
// empty data
{ {
Name: "empty data",
Method: http.MethodPost, Method: http.MethodPost,
Url: "/api/users/request-verification", Url: "/api/users/request-verification",
Body: strings.NewReader(``), Body: strings.NewReader(``),
ExpectedStatus: 400, ExpectedStatus: 400,
ExpectedContent: []string{`"data":{"email":{"code":"validation_required","message":"Cannot be blank."}}`}, ExpectedContent: []string{`"data":{"email":{"code":"validation_required","message":"Cannot be blank."}}`},
}, },
// invalid data
{ {
Name: "invalid data",
Method: http.MethodPost, Method: http.MethodPost,
Url: "/api/users/request-verification", Url: "/api/users/request-verification",
Body: strings.NewReader(`{"email`), Body: strings.NewReader(`{"email`),
ExpectedStatus: 400, ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`}, ExpectedContent: []string{`"data":{}`},
}, },
// missing user
{ {
Name: "missing user",
Method: http.MethodPost, Method: http.MethodPost,
Url: "/api/users/request-verification", Url: "/api/users/request-verification",
Body: strings.NewReader(`{"email":"missing@example.com"}`), Body: strings.NewReader(`{"email":"missing@example.com"}`),
ExpectedStatus: 204, ExpectedStatus: 204,
}, },
// existing already verified user
{ {
Name: "existing already verified user",
Method: http.MethodPost, Method: http.MethodPost,
Url: "/api/users/request-verification", Url: "/api/users/request-verification",
Body: strings.NewReader(`{"email":"test@example.com"}`), Body: strings.NewReader(`{"email":"test@example.com"}`),
ExpectedStatus: 204, ExpectedStatus: 204,
}, },
// existing unverified user
{ {
Name: "existing unverified user",
Method: http.MethodPost, Method: http.MethodPost,
Url: "/api/users/request-verification", Url: "/api/users/request-verification",
Body: strings.NewReader(`{"email":"test2@example.com"}`), Body: strings.NewReader(`{"email":"test2@example.com"}`),
ExpectedStatus: 204, ExpectedStatus: 204,
// usually this events are fired but since the submit is ExpectedEvents: map[string]int{
// executed in a separate go routine they are fired async "OnModelBeforeUpdate": 1,
// ExpectedEvents: map[string]int{ "OnModelAfterUpdate": 1,
// "OnModelBeforeUpdate": 1, "OnMailerBeforeUserVerificationSend": 1,
// "OnModelAfterUpdate": 1, "OnMailerAfterUserVerificationSend": 1,
// "OnMailerBeforeUserVerificationSend": 1, },
// "OnMailerAfterUserVerificationSend": 1, },
// }, {
Name: "existing unverified user (after already sent)",
Method: http.MethodPost,
Url: "/api/users/request-verification",
Body: strings.NewReader(`{"email":"test2@example.com"}`),
ExpectedStatus: 204,
BeforeFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
// simulate recent verification sent
user, err := app.Dao().FindUserByEmail("test2@example.com")
if err != nil {
t.Fatal(err)
}
user.LastVerificationSentAt = types.NowDateTime()
dao := daos.New(app.Dao().DB()) // new dao to ignore hooks
if err := dao.Save(user); err != nil {
t.Fatal(err)
}
},
}, },
} }

View File

@ -23,7 +23,7 @@ func TestExpandRecords(t *testing.T) {
expands []string expands []string
fetchFunc daos.ExpandFetchFunc fetchFunc daos.ExpandFetchFunc
expectExpandProps int expectExpandProps int
expectExpandFailires int expectExpandFailures int
}{ }{
// empty records // empty records
{ {
@ -130,8 +130,8 @@ func TestExpandRecords(t *testing.T) {
records, _ := app.Dao().FindRecordsByIds(col, ids, nil) records, _ := app.Dao().FindRecordsByIds(col, ids, nil)
failed := app.Dao().ExpandRecords(records, s.expands, s.fetchFunc) failed := app.Dao().ExpandRecords(records, s.expands, s.fetchFunc)
if len(failed) != s.expectExpandFailires { if len(failed) != s.expectExpandFailures {
t.Errorf("(%d) Expected %d failures, got %d: \n%v", i, s.expectExpandFailires, len(failed), failed) t.Errorf("(%d) Expected %d failures, got %d: \n%v", i, s.expectExpandFailures, len(failed), failed)
} }
encoded, _ := json.Marshal(records) encoded, _ := json.Marshal(records)
@ -155,7 +155,7 @@ func TestExpandRecord(t *testing.T) {
expands []string expands []string
fetchFunc daos.ExpandFetchFunc fetchFunc daos.ExpandFetchFunc
expectExpandProps int expectExpandProps int
expectExpandFailires int expectExpandFailures int
}{ }{
// empty expand // empty expand
{ {
@ -241,8 +241,8 @@ func TestExpandRecord(t *testing.T) {
record, _ := app.Dao().FindFirstRecordByData(col, "id", s.recordId) record, _ := app.Dao().FindFirstRecordByData(col, "id", s.recordId)
failed := app.Dao().ExpandRecord(record, s.expands, s.fetchFunc) failed := app.Dao().ExpandRecord(record, s.expands, s.fetchFunc)
if len(failed) != s.expectExpandFailires { if len(failed) != s.expectExpandFailures {
t.Errorf("(%d) Expected %d failures, got %d: \n%v", i, s.expectExpandFailires, len(failed), failed) t.Errorf("(%d) Expected %d failures, got %d: \n%v", i, s.expectExpandFailures, len(failed), failed)
} }
encoded, _ := json.Marshal(record) encoded, _ := json.Marshal(record)

View File

@ -27,7 +27,7 @@ type ApiScenario struct {
ExpectedContent []string ExpectedContent []string
NotExpectedContent []string NotExpectedContent []string
ExpectedEvents map[string]int ExpectedEvents map[string]int
// test events // test hooks
BeforeFunc func(t *testing.T, app *TestApp, e *echo.Echo) BeforeFunc func(t *testing.T, app *TestApp, e *echo.Echo)
AfterFunc func(t *testing.T, app *TestApp, e *echo.Echo) AfterFunc func(t *testing.T, app *TestApp, e *echo.Echo)
} }
@ -81,6 +81,12 @@ func (scenario *ApiScenario) Test(t *testing.T) {
t.Errorf("[%s] Expected status code %d, got %d", prefix, scenario.ExpectedStatus, res.StatusCode) t.Errorf("[%s] Expected status code %d, got %d", prefix, scenario.ExpectedStatus, res.StatusCode)
} }
// @todo consider replacing with sync.WaitGroup
//
// apply a small delay before checking the expectations to ensure
// that all fired go routines have complicated before cleaning up the app instance
time.Sleep(5 * time.Millisecond)
if len(scenario.ExpectedContent) == 0 && len(scenario.NotExpectedContent) == 0 { if len(scenario.ExpectedContent) == 0 && len(scenario.NotExpectedContent) == 0 {
if len(recorder.Body.Bytes()) != 0 { if len(recorder.Body.Bytes()) != 0 {
t.Errorf("[%s] Expected empty body, got \n%v", prefix, recorder.Body.String()) t.Errorf("[%s] Expected empty body, got \n%v", prefix, recorder.Body.String())