181 lines
5.1 KiB
Go
181 lines
5.1 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"bytes"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/log"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
func TestSignupLogsAuthStoreMutations(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
restore := log.Logger
|
|
log.Logger = zerolog.New(&buf)
|
|
defer func() {
|
|
log.Logger = restore
|
|
}()
|
|
|
|
handler := newTestAuthHandler(t)
|
|
|
|
form := url.Values{}
|
|
form.Set("email", "new@xtablo.com")
|
|
form.Set("password", "xtablo-secret")
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/signup", strings.NewReader(form.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.PostSignup().ServeHTTP(rec, req)
|
|
|
|
output := buf.String()
|
|
for _, want := range []string{
|
|
`"action":"create_user"`,
|
|
`"email":"new@xtablo.com"`,
|
|
`"action":"create_session"`,
|
|
`"session_id":"`,
|
|
} {
|
|
if !strings.Contains(output, want) {
|
|
t.Fatalf("expected log output to contain %q, got %q", want, output)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSignupHashesPasswordBeforeStoringUser(t *testing.T) {
|
|
repo := NewInMemoryAuthRepository()
|
|
handler := NewAuthHandler(repo)
|
|
|
|
form := url.Values{}
|
|
form.Set("email", "new@xtablo.com")
|
|
form.Set("password", "xtablo-secret")
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/signup", strings.NewReader(form.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.PostSignup().ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status 200, got %d", rec.Code)
|
|
}
|
|
|
|
storedUser, err := repo.GetAuthUserByEmail(req.Context(), "new@xtablo.com")
|
|
if err != nil {
|
|
t.Fatalf("expected stored user, got error %v", err)
|
|
}
|
|
if storedUser.EncryptedPassword == "xtablo-secret" {
|
|
t.Fatalf("expected stored password hash, got plaintext")
|
|
}
|
|
if bcrypt.CompareHashAndPassword([]byte(storedUser.EncryptedPassword), []byte("xtablo-secret")) != nil {
|
|
t.Fatalf("expected stored password to match bcrypt hash")
|
|
}
|
|
}
|
|
|
|
func TestLogoutLogsSessionDeletion(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
restore := log.Logger
|
|
log.Logger = zerolog.New(&buf)
|
|
defer func() {
|
|
log.Logger = restore
|
|
}()
|
|
|
|
handler := newTestAuthHandler(t)
|
|
|
|
loginForm := url.Values{}
|
|
loginForm.Set("email", "demo@xtablo.com")
|
|
loginForm.Set("password", "xtablo-demo")
|
|
|
|
loginReq := httptest.NewRequest(http.MethodPost, "/login", strings.NewReader(loginForm.Encode()))
|
|
loginReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
loginRec := httptest.NewRecorder()
|
|
handler.PostLogin().ServeHTTP(loginRec, loginReq)
|
|
|
|
sessionCookie := loginRec.Result().Cookies()[0]
|
|
|
|
logoutReq := httptest.NewRequest(http.MethodPost, "/logout", nil)
|
|
logoutReq.AddCookie(sessionCookie)
|
|
logoutRec := httptest.NewRecorder()
|
|
handler.PostLogout().ServeHTTP(logoutRec, logoutReq)
|
|
|
|
output := buf.String()
|
|
for _, want := range []string{
|
|
`"action":"delete_session"`,
|
|
`"email":"demo@xtablo.com"`,
|
|
`"session_id":"`,
|
|
} {
|
|
if !strings.Contains(output, want) {
|
|
t.Fatalf("expected log output to contain %q, got %q", want, output)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTasksPageSidebarShowsRealTablos(t *testing.T) {
|
|
repo := NewInMemoryAuthRepository()
|
|
handler := NewAuthHandler(repo)
|
|
sessionCookie := loginTestUser(t, handler, "demo@xtablo.com", "xtablo-demo")
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
req.AddCookie(sessionCookie)
|
|
userID, ok := handler.currentUserID(req.Context(), req)
|
|
if !ok {
|
|
t.Fatal("expected user session")
|
|
}
|
|
|
|
for _, tablo := range []CreateTabloInput{
|
|
{OwnerID: userID, Name: "Blue", Color: "#3B82F6", Status: TabloStatusTodo},
|
|
{OwnerID: userID, Name: "Green", Color: "#22C55E", Status: TabloStatusTodo},
|
|
{OwnerID: userID, Name: "Purple", Color: "#A855F7", Status: TabloStatusTodo},
|
|
{OwnerID: userID, Name: "Red", Color: "#EF4444", Status: TabloStatusTodo},
|
|
{OwnerID: userID, Name: "Hidden Fifth", Color: "#EAB308", Status: TabloStatusTodo},
|
|
} {
|
|
if _, err := repo.CreateTablo(context.Background(), tablo); err != nil {
|
|
t.Fatalf("create tablo %q: %v", tablo.Name, err)
|
|
}
|
|
}
|
|
|
|
pageReq := httptest.NewRequest(http.MethodGet, "/tasks", nil)
|
|
pageReq.AddCookie(sessionCookie)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.GetTasksPage().ServeHTTP(rec, pageReq)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status 200, got %d", rec.Code)
|
|
}
|
|
|
|
body := rec.Body.String()
|
|
projectSection := body
|
|
if index := strings.Index(body, `id="sidebar-projects-section"`); index >= 0 {
|
|
projectSection = body[index:]
|
|
if end := strings.Index(projectSection, `<ul class="sidebar-list sidebar-footer-links"`); end >= 0 {
|
|
projectSection = projectSection[:end]
|
|
}
|
|
}
|
|
for _, want := range []string{
|
|
"Green",
|
|
"Purple",
|
|
"Red",
|
|
"Hidden Fifth",
|
|
} {
|
|
if !strings.Contains(projectSection, want) {
|
|
t.Fatalf("expected sidebar to contain %q, got %q", want, projectSection)
|
|
}
|
|
}
|
|
if strings.Contains(projectSection, "Blue") {
|
|
t.Fatalf("expected sidebar to limit to the four most recent tablos, got %q", projectSection)
|
|
}
|
|
if !strings.Contains(body, `href="/tablos/`) {
|
|
t.Fatalf("expected sidebar project links, got %q", body)
|
|
}
|
|
}
|
|
|
|
func newTestAuthHandler(t *testing.T) *AuthHandler {
|
|
t.Helper()
|
|
return NewAuthHandler(NewInMemoryAuthRepository())
|
|
}
|