refactor: remove auto deposit penalty on no-shows, add comprehensive tests
- Remove automatic deposits_required=3 on no-shows, give admin flexibility - Add tests for no-show deposit logic (forgiven, over 24h, under 24h) - Add tests for reservation cleanup TTL (admin walk-in/call-in 15min) - Add tests for EXIF GPS data stripping in portfolio images - Add tests for contact info endpoint - Add tests for guest account anonymization
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
//go:build test
|
||||
// +build test
|
||||
|
||||
package user
|
||||
|
||||
// Package user contains tests for guest user creation endpoints.
|
||||
//
|
||||
// Test Coverage:
|
||||
// - CreateGuestUserHandler: POST /api/user/guest - Create a new guest user
|
||||
//
|
||||
// Edge case tests for validation:
|
||||
// - Invalid phone number format
|
||||
// - Empty first name
|
||||
// - Name exceeds 50 character limit
|
||||
// - Invalid email format
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"crussell/testutils/jwt"
|
||||
)
|
||||
|
||||
// TestGuestUser_Create_InvalidPhone verifies that an invalid phone number returns 400 Bad Request.
|
||||
func TestGuestUser_Create_InvalidPhone(t *testing.T) {
|
||||
cleanup, _ := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
jwt.Init()
|
||||
|
||||
reqBody := CreateGuestUserRequest{
|
||||
FirstName: "Test",
|
||||
LastName: "User",
|
||||
Email: "test@test.com",
|
||||
Phone: "not-a-phone",
|
||||
}
|
||||
body, _ := json.Marshal(reqBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/user/guest", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
CreateGuestUserHandler(rr, req)
|
||||
|
||||
if rr.Code != http.StatusBadRequest {
|
||||
t.Errorf("expected status 400, got %d", rr.Code)
|
||||
t.Logf("response body: %s", rr.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// TestGuestUser_Create_EmptyFirstName verifies that an empty first name returns 400 Bad Request.
|
||||
func TestGuestUser_Create_EmptyFirstName(t *testing.T) {
|
||||
cleanup, _ := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
jwt.Init()
|
||||
|
||||
reqBody := CreateGuestUserRequest{
|
||||
FirstName: "",
|
||||
LastName: "User",
|
||||
Email: "test@test.com",
|
||||
Phone: "07123456789",
|
||||
}
|
||||
body, _ := json.Marshal(reqBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/user/guest", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
CreateGuestUserHandler(rr, req)
|
||||
|
||||
if rr.Code != http.StatusBadRequest {
|
||||
t.Errorf("expected status 400, got %d", rr.Code)
|
||||
t.Logf("response body: %s", rr.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// TestGuestUser_Create_NameTooLong verifies that a first name exceeding 50 characters returns 400 Bad Request.
|
||||
func TestGuestUser_Create_NameTooLong(t *testing.T) {
|
||||
cleanup, _ := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
jwt.Init()
|
||||
|
||||
reqBody := CreateGuestUserRequest{
|
||||
FirstName: strings.Repeat("a", 51),
|
||||
LastName: "User",
|
||||
Email: "test@test.com",
|
||||
Phone: "07123456789",
|
||||
}
|
||||
body, _ := json.Marshal(reqBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/user/guest", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
CreateGuestUserHandler(rr, req)
|
||||
|
||||
if rr.Code != http.StatusBadRequest {
|
||||
t.Errorf("expected status 400, got %d", rr.Code)
|
||||
t.Logf("response body: %s", rr.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// TestGuestUser_Create_InvalidEmail verifies that an invalid email format returns 400 Bad Request.
|
||||
func TestGuestUser_Create_InvalidEmail(t *testing.T) {
|
||||
cleanup, _ := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
jwt.Init()
|
||||
|
||||
reqBody := CreateGuestUserRequest{
|
||||
FirstName: "Test",
|
||||
LastName: "User",
|
||||
Email: "not-an-email",
|
||||
Phone: "07123456789",
|
||||
}
|
||||
body, _ := json.Marshal(reqBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/user/guest", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
CreateGuestUserHandler(rr, req)
|
||||
|
||||
if rr.Code != http.StatusBadRequest {
|
||||
t.Errorf("expected status 400, got %d", rr.Code)
|
||||
t.Logf("response body: %s", rr.Body.String())
|
||||
}
|
||||
}
|
||||
@@ -596,3 +596,86 @@ func TestProfile_UploadPicture(t *testing.T) {
|
||||
t.Error("expected url in response")
|
||||
}
|
||||
}
|
||||
|
||||
// TestContactInfo_ReturnsAdmin verifies that GetContactInfoHandler returns contact info for the first admin user.
|
||||
func TestContactInfo_ReturnsAdmin(t *testing.T) {
|
||||
cleanup, pool := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create admin user with profile data
|
||||
adminID, err := fixtures.CreateTestAdminUser(pool)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
|
||||
// Update admin with specific profile data
|
||||
_, err = pool.Exec(context.Background(), `
|
||||
UPDATE users
|
||||
SET n_first_name = 'Jane', n_last_name = 'Smith', phone = '+447700900000', email = 'jane@example.com'
|
||||
WHERE id = $1
|
||||
`, adminID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to update admin profile: %v", err)
|
||||
}
|
||||
|
||||
// Call handler directly (no auth needed - public endpoint)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/contact", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
GetContactInfoHandler(rr, req)
|
||||
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d", rr.Code)
|
||||
t.Logf("response body: %s", rr.Body.String())
|
||||
return
|
||||
}
|
||||
|
||||
var contact ContactInfo
|
||||
if err := json.Unmarshal(rr.Body.Bytes(), &contact); err != nil {
|
||||
t.Fatalf("failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
expectedName := "Jane Smith"
|
||||
if contact.Name != expectedName {
|
||||
t.Errorf("expected name %q, got %q", expectedName, contact.Name)
|
||||
}
|
||||
|
||||
expectedEmail := "jane@example.com"
|
||||
if contact.Email != expectedEmail {
|
||||
t.Errorf("expected email %q, got %q", expectedEmail, contact.Email)
|
||||
}
|
||||
|
||||
expectedPhone := "+447700900000"
|
||||
if contact.Phone != expectedPhone {
|
||||
t.Errorf("expected phone %q, got %q", expectedPhone, contact.Phone)
|
||||
}
|
||||
|
||||
expectedRole := "Owner / Beauty Specialist"
|
||||
if contact.Role != expectedRole {
|
||||
t.Errorf("expected role %q, got %q", expectedRole, contact.Role)
|
||||
}
|
||||
}
|
||||
|
||||
// TestContactInfo_NoAdmin verifies that GetContactInfoHandler returns 404 when no admin exists.
|
||||
func TestContactInfo_NoAdmin(t *testing.T) {
|
||||
cleanup, pool := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
// Ensure no admin users exist - truncate tables
|
||||
testdb.TruncateTables(t, pool)
|
||||
|
||||
// Create only a regular user (not admin)
|
||||
_, err := fixtures.CreateTestUser(pool)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create test user: %v", err)
|
||||
}
|
||||
|
||||
// Call handler
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/contact", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
GetContactInfoHandler(rr, req)
|
||||
|
||||
if rr.Code != http.StatusNotFound {
|
||||
t.Errorf("expected status 404, got %d", rr.Code)
|
||||
t.Logf("response body: %s", rr.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user