Fix test setup and middleware chain - Handler tests now passing
- Fix TestRequireRoleMiddleware by chaining RequireAuth before RequireRole (role context requirement) - Remove unused 'strings' import from testdb.go - Create crussell_test database in Docker setup - Tests now properly initialize authentication context for role-based tests Result: handlers test suite passes (13/13 tests) Remaining failures in admin/auth/bookings/portfolio/scheduling/services/user packages need further investigation (environment setup, database constraints, endpoint initialization)
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
//go:build test
|
||||
// +build test
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"crussell/db"
|
||||
"crussell/handlers/services"
|
||||
"crussell/mw"
|
||||
)
|
||||
|
||||
func TestAdminServices_Create(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create admin user in DB first
|
||||
_, err := db.DB.Exec(context.Background(), `
|
||||
INSERT INTO users (n_first_name, n_last_name, email, password_hash, account_role, account_type)
|
||||
VALUES ('Admin', 'User', 'admin@test.com', 'hash', 'admin', 'email')
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(services.CreateServiceHandler)
|
||||
|
||||
createReq := services.CreateServiceRequest{
|
||||
Name: "Test Manicure",
|
||||
Description: stringPtr("A test manicure service"),
|
||||
Price: 35.00,
|
||||
DurationMinutes: 45,
|
||||
PatchTestDurationHours: 0,
|
||||
MinimumAgeRequired: 16,
|
||||
}
|
||||
|
||||
w := makeAdminRequest(handler, "POST", "/api/admin/services", createReq)
|
||||
|
||||
if w.Code != http.StatusCreated {
|
||||
t.Errorf("expected status 201, got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
var response services.Service
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if response.Name != "Test Manicure" {
|
||||
t.Errorf("expected name 'Test Manicure', got %s", response.Name)
|
||||
}
|
||||
if response.Price != 35.00 {
|
||||
t.Errorf("expected price 35.00, got %f", response.Price)
|
||||
}
|
||||
if !response.IsActive {
|
||||
t.Error("expected new service to be active by default")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminServices_List(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
// Insert test services
|
||||
_, err := db.DB.Exec(context.Background(), `
|
||||
INSERT INTO services (name, description, price, duration_minutes, is_active, patch_test_duration_hours, minimum_age_required)
|
||||
VALUES
|
||||
('Manicure', 'Basic manicure', 25.00, 30, true, 0, 0),
|
||||
('Pedicure', 'Basic pedicure', 30.00, 45, false, 0, 0),
|
||||
('Gel Polish', 'Gel polish service', 40.00, 60, true, 48, 16)
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create services: %v", err)
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(services.AllServicesHandler)
|
||||
w := makeAdminRequest(handler, "GET", "/api/admin/services", nil)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
var response []services.Service
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if len(response) != 3 {
|
||||
t.Errorf("expected 3 services, got %d", len(response))
|
||||
}
|
||||
|
||||
// Verify all services including inactive are returned
|
||||
found := map[string]bool{}
|
||||
for _, s := range response {
|
||||
found[s.Name] = true
|
||||
}
|
||||
|
||||
if !found["Manicure"] {
|
||||
t.Error("expected Manicure in response")
|
||||
}
|
||||
if !found["Pedicure"] {
|
||||
t.Error("expected Pedicure in response (including inactive)")
|
||||
}
|
||||
if !found["Gel Polish"] {
|
||||
t.Error("expected Gel Polish in response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminServices_Toggle(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create a service
|
||||
var serviceID string
|
||||
err := db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO services (name, description, price, duration_minutes, is_active, patch_test_duration_hours, minimum_age_required)
|
||||
VALUES ('Test Service', 'A test service', 50.00, 60, true, 0, 16)
|
||||
RETURNING id
|
||||
`).Scan(&serviceID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create service: %v", err)
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(services.ToggleService)
|
||||
w := makeAdminRequest(handler, "PUT", "/api/admin/services/"+serviceID+"/toggle", nil)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
// Verify service is now inactive
|
||||
var isActive bool
|
||||
err = db.DB.QueryRow(context.Background(), "SELECT is_active FROM services WHERE id = $1", serviceID).Scan(&isActive)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to check service: %v", err)
|
||||
}
|
||||
if isActive {
|
||||
t.Error("expected service to be inactive after toggle")
|
||||
}
|
||||
|
||||
// Toggle again
|
||||
w = makeAdminRequest(handler, "PUT", "/api/admin/services/"+serviceID+"/toggle", nil)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200 on second toggle, got %d", w.Code)
|
||||
}
|
||||
|
||||
// Verify service is active again
|
||||
err = db.DB.QueryRow(context.Background(), "SELECT is_active FROM services WHERE id = $1", serviceID).Scan(&isActive)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to check service: %v", err)
|
||||
}
|
||||
if !isActive {
|
||||
t.Error("expected service to be active after second toggle")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminServices_Delete(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create a service
|
||||
var serviceID string
|
||||
err := db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO services (name, description, price, duration_minutes, is_active, patch_test_duration_hours, minimum_age_required)
|
||||
VALUES ('Test Service', 'A test service', 50.00, 60, true, 0, 16)
|
||||
RETURNING id
|
||||
`).Scan(&serviceID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create service: %v", err)
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(services.DeleteServiceHandler)
|
||||
w := makeAdminRequest(handler, "DELETE", "/api/admin/services/"+serviceID, nil)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
// Verify service is deleted
|
||||
var count int
|
||||
err = db.DB.QueryRow(context.Background(), "SELECT COUNT(*) FROM services WHERE id = $1", serviceID).Scan(&count)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to check service: %v", err)
|
||||
}
|
||||
if count != 0 {
|
||||
t.Error("expected service to be deleted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminServices_NonAdmin(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create regular user in DB
|
||||
_, err := db.DB.Exec(context.Background(), `
|
||||
INSERT INTO users (n_first_name, n_last_name, email, password_hash, account_role, account_type)
|
||||
VALUES ('Regular', 'User', 'user@test.com', 'hash', 'verified_email', 'email')
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create user: %v", err)
|
||||
}
|
||||
|
||||
// Test CREATE - should get 403 when using middleware
|
||||
createHandler := mw.RequireAdmin(http.HandlerFunc(services.CreateServiceHandler))
|
||||
createReq := services.CreateServiceRequest{
|
||||
Name: "Test Service",
|
||||
Description: stringPtr("Test"),
|
||||
Price: 50.00,
|
||||
DurationMinutes: 60,
|
||||
PatchTestDurationHours: 0,
|
||||
MinimumAgeRequired: 16,
|
||||
}
|
||||
w := makeUserRequest(createHandler, "POST", "/api/admin/services", createReq)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("CREATE: expected status 403, got %d", w.Code)
|
||||
}
|
||||
|
||||
// Test LIST - should get 403 when using middleware
|
||||
listHandler := mw.RequireAdmin(http.HandlerFunc(services.AllServicesHandler))
|
||||
w = makeUserRequest(listHandler, "GET", "/api/admin/services", nil)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("LIST: expected status 403, got %d", w.Code)
|
||||
}
|
||||
|
||||
// Test TOGGLE - should get 403 when using middleware
|
||||
var serviceID string
|
||||
err = db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO services (name, description, price, duration_minutes, is_active, patch_test_duration_hours, minimum_age_required)
|
||||
VALUES ('Test Service', 'A test service', 50.00, 60, true, 0, 16)
|
||||
RETURNING id
|
||||
`).Scan(&serviceID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create service: %v", err)
|
||||
}
|
||||
|
||||
toggleHandler := mw.RequireAdmin(http.HandlerFunc(services.ToggleService))
|
||||
w = makeUserRequest(toggleHandler, "PUT", "/api/admin/services/"+serviceID+"/toggle", nil)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("TOGGLE: expected status 403, got %d", w.Code)
|
||||
}
|
||||
|
||||
// Test DELETE - should get 403 when using middleware
|
||||
deleteHandler := mw.RequireAdmin(http.HandlerFunc(services.DeleteServiceHandler))
|
||||
w = makeUserRequest(deleteHandler, "DELETE", "/api/admin/services/"+serviceID, nil)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("DELETE: expected status 403, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func stringPtr(s string) *string {
|
||||
return &s
|
||||
}
|
||||
Reference in New Issue
Block a user