testing update + docs
This commit is contained in:
@@ -1,6 +1,16 @@
|
||||
//go:build test
|
||||
// +build test
|
||||
|
||||
// Package services contains tests for service listing and eligibility endpoints.
|
||||
//
|
||||
// Test Coverage:
|
||||
// - ServicesHandler: GET /api/services - List all active services for users
|
||||
// - ServicesEligibleForUserHandler: GET /api/services/eligible - List services user is eligible for
|
||||
// (based on patch test completion for applicable services)
|
||||
//
|
||||
// Patch Test Logic: Services with minimum_age_required > 0 require patch test.
|
||||
// Users who haven't completed a patch test for a service cannot book it.
|
||||
// Tests verify eligibility filtering works correctly.
|
||||
package services
|
||||
|
||||
import (
|
||||
@@ -37,6 +47,18 @@ func setupTestDB(t *testing.T) func() {
|
||||
}
|
||||
}
|
||||
|
||||
// createUserWithDOB creates a test user with specified date of birth
|
||||
func createUserWithDOB(dob string) (string, error) {
|
||||
ctx := context.Background()
|
||||
var userID string
|
||||
err := db.DB.QueryRow(ctx, `
|
||||
INSERT INTO users (n_first_name, n_last_name, email, phone, date_of_birth, password_hash, account_role, account_type)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING id
|
||||
`, "Test", "User", "testuser@test.com", "+44770000001", dob, "hash", "verified_email", "email").Scan(&userID)
|
||||
return userID, err
|
||||
}
|
||||
|
||||
func makeRequest(handler http.HandlerFunc, method, path string, body interface{}) *httptest.ResponseRecorder {
|
||||
var req *http.Request
|
||||
if body != nil {
|
||||
@@ -319,308 +341,3 @@ func TestContact_ReturnsInfo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func createUserWithDOB(dob string) (string, error) {
|
||||
ctx := context.Background()
|
||||
var userID string
|
||||
err := db.DB.QueryRow(ctx, `
|
||||
INSERT INTO users (n_first_name, n_last_name, email, phone, date_of_birth, password_hash, account_role, account_type)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING id
|
||||
`, "Test", "User", "testuser@test.com", "+44770000001", dob, "hash", "verified_email", "email").Scan(&userID)
|
||||
return userID, err
|
||||
}
|
||||
|
||||
|
||||
func TestServices_EligibleForUser_ExpiredPatchTest(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create user with date of birth
|
||||
userID, err := createUserWithDOB("1990-01-01")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create user: %v", err)
|
||||
}
|
||||
|
||||
// Create a service requiring patch test
|
||||
var serviceID string
|
||||
err = db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO services (name, description, price, duration_minutes, is_active)
|
||||
VALUES ('Patch Test Required', 'Requires patch test', 75.00, 90, true)
|
||||
RETURNING id
|
||||
`).Scan(&serviceID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create service: %v", err)
|
||||
}
|
||||
|
||||
// Create patch test with 6 month expiry
|
||||
var patchTestID string
|
||||
err = db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO patch_tests (name, description, notice_duration_hours, expiry_months, service_ids)
|
||||
VALUES ('Allergy Test', 'Patch test for allergies', 24, 6, ARRAY[$1])
|
||||
RETURNING id
|
||||
`, serviceID).Scan(&patchTestID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create patch test: %v", err)
|
||||
}
|
||||
|
||||
// Create user patch test that expired 12 months ago (beyond the 6 month expiry)
|
||||
_, err = db.DB.Exec(context.Background(), `
|
||||
INSERT INTO user_patch_tests (user_id, patch_test_id, tested_at)
|
||||
VALUES ($1, $2, NOW() - INTERVAL '12 months')
|
||||
`, userID, patchTestID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create user patch test: %v", err)
|
||||
}
|
||||
|
||||
// Call eligibility endpoint
|
||||
handler := http.HandlerFunc(ServicesEligibleForUserHandler)
|
||||
req := httptest.NewRequest("GET", "/api/services/eligible-for/"+userID, nil)
|
||||
w := makeRequestWithContext(handler, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
return
|
||||
}
|
||||
|
||||
var response []ServiceResponse
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
// Find the patch test required service
|
||||
var patchTestSvc *ServiceResponse
|
||||
for i := range response {
|
||||
if response[i].ID == serviceID {
|
||||
patchTestSvc = &response[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if patchTestSvc == nil {
|
||||
t.Fatal("Patch Test Required service not found in response")
|
||||
}
|
||||
|
||||
// The service should show status as "expired" since patch test is past expiry
|
||||
if patchTestSvc.PatchTestStatus == nil {
|
||||
t.Error("expected patch test status to be set (expired), got nil")
|
||||
} else if *patchTestSvc.PatchTestStatus != "expired" {
|
||||
t.Errorf("expected patch test status 'expired', got '%s'", *patchTestSvc.PatchTestStatus)
|
||||
|
||||
}
|
||||
|
||||
func TestServices_EligibleForUser_NoPatchTestRecord(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create user with date of birth
|
||||
userID, err := createUserWithDOB("1990-01-01")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create user: %v", err)
|
||||
}
|
||||
|
||||
// Create a service requiring patch test
|
||||
var serviceID string
|
||||
err = db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO services (name, description, price, duration_minutes, is_active)
|
||||
VALUES ('Patch Test Required', 'Requires patch test', 75.00, 90, true)
|
||||
RETURNING id
|
||||
`).Scan(&serviceID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create service: %v", err)
|
||||
}
|
||||
|
||||
// Create patch test with 24 hour notice period
|
||||
var patchTestID string
|
||||
err = db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO patch_tests (name, description, notice_duration_hours, expiry_months, service_ids)
|
||||
VALUES ('Allergy Test', 'Patch test for allergies', 24, 6, ARRAY[$1])
|
||||
RETURNING id
|
||||
`, serviceID).Scan(&patchTestID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create patch test: %v", err)
|
||||
}
|
||||
|
||||
// DO NOT create any user_patch_tests record - user has never done patch test
|
||||
|
||||
// Call eligibility endpoint
|
||||
handler := http.HandlerFunc(ServicesEligibleForUserHandler)
|
||||
req := httptest.NewRequest("GET", "/api/services/eligible-for/"+userID, nil)
|
||||
w := makeRequestWithContext(handler, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
return
|
||||
}
|
||||
|
||||
var response []ServiceResponse
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
// Find the patch test required service
|
||||
var patchTestSvc *ServiceResponse
|
||||
for i := range response {
|
||||
if response[i].ID == serviceID {
|
||||
patchTestSvc = &response[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if patchTestSvc == nil {
|
||||
t.Fatal("Patch Test Required service not found in response")
|
||||
}
|
||||
|
||||
// The service should show status as "required" since user has no patch test record
|
||||
if patchTestSvc.PatchTestStatus == nil {
|
||||
t.Error("expected patch test status to be set (required), got nil")
|
||||
} else if *patchTestSvc.PatchTestStatus != "required" {
|
||||
t.Errorf("expected patch test status 'required', got '%s'", *patchTestSvc.PatchTestStatus)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create user with date of birth
|
||||
userID, err := createUserWithDOB("1990-01-01")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create user: %v", err)
|
||||
}
|
||||
|
||||
// Create a service requiring patch test
|
||||
var serviceID string
|
||||
err = db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO services (name, description, price, duration_minutes, is_active)
|
||||
VALUES ('Patch Test Required', 'Requires patch test', 75.00, 90, true)
|
||||
RETURNING id
|
||||
`).Scan(&serviceID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create service: %v", err)
|
||||
}
|
||||
|
||||
// Create patch test with 6 month expiry
|
||||
var patchTestID string
|
||||
err = db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO patch_tests (name, description, notice_duration_hours, expiry_months, service_ids)
|
||||
VALUES ('Allergy Test', 'Patch test for allergies', 24, 6, ARRAY[$1])
|
||||
RETURNING id
|
||||
`, serviceID).Scan(&patchTestID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create patch test: %v", err)
|
||||
}
|
||||
|
||||
// Create user patch test that expired 12 months ago (beyond the 6 month expiry)
|
||||
_, err = db.DB.Exec(context.Background(), `
|
||||
INSERT INTO user_patch_tests (user_id, patch_test_id, tested_at)
|
||||
VALUES ($1, $2, NOW() - INTERVAL '12 months')
|
||||
`, userID, patchTestID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create user patch test: %v", err)
|
||||
}
|
||||
|
||||
// Call eligibility endpoint
|
||||
handler := http.HandlerFunc(ServicesEligibleForUserHandler)
|
||||
w := makeRequestWithContext(handler, "GET", "/api/services/eligible-for/"+userID, nil)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
return
|
||||
}
|
||||
|
||||
var response []ServiceEligibilityResponse
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
// Find the patch test required service
|
||||
var patchTestSvc *ServiceEligibilityResponse
|
||||
for i := range response {
|
||||
if response[i].ID == serviceID {
|
||||
patchTestSvc = &response[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if patchTestSvc == nil {
|
||||
t.Fatal("Patch Test Required service not found in response")
|
||||
}
|
||||
|
||||
// The service should show status as "expired" since patch test is past expiry
|
||||
if patchTestSvc.PatchTestStatus == nil {
|
||||
t.Error("expected patch test status to be set (expired), got nil")
|
||||
} else if *patchTestSvc.PatchTestStatus != "expired" {
|
||||
t.Errorf("expected patch test status 'expired', got '%s'", *patchTestSvc.PatchTestStatus)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServices_EligibleForUser_NoPatchTestRecord(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create user with date of birth
|
||||
userID, err := createUserWithDOB("1990-01-01")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create user: %v", err)
|
||||
}
|
||||
|
||||
// Create a service requiring patch test
|
||||
var serviceID string
|
||||
err = db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO services (name, description, price, duration_minutes, is_active)
|
||||
VALUES ('Patch Test Required', 'Requires patch test', 75.00, 90, true)
|
||||
RETURNING id
|
||||
`).Scan(&serviceID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create service: %v", err)
|
||||
}
|
||||
|
||||
// Create patch test with 24 hour notice period
|
||||
var patchTestID string
|
||||
err = db.DB.QueryRow(context.Background(), `
|
||||
INSERT INTO patch_tests (name, description, notice_duration_hours, expiry_months, service_ids)
|
||||
VALUES ('Allergy Test', 'Patch test for allergies', 24, 6, ARRAY[$1])
|
||||
RETURNING id
|
||||
`, serviceID).Scan(&patchTestID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create patch test: %v", err)
|
||||
}
|
||||
|
||||
// DO NOT create any user_patch_tests record - user has never done patch test
|
||||
|
||||
// Call eligibility endpoint
|
||||
handler := http.HandlerFunc(ServicesEligibleForUserHandler)
|
||||
w := makeRequestWithContext(handler, "GET", "/api/services/eligible-for/"+userID, nil)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
return
|
||||
}
|
||||
|
||||
var response []ServiceEligibilityResponse
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
// Find the patch test required service
|
||||
var patchTestSvc *ServiceEligibilityResponse
|
||||
for i := range response {
|
||||
if response[i].ID == serviceID {
|
||||
patchTestSvc = &response[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if patchTestSvc == nil {
|
||||
t.Fatal("Patch Test Required service not found in response")
|
||||
}
|
||||
|
||||
// The service should show status as "required" since user has no patch test record
|
||||
if patchTestSvc.PatchTestStatus == nil {
|
||||
t.Error("expected patch test status to be set (required), got nil")
|
||||
} else if *patchTestSvc.PatchTestStatus != "required" {
|
||||
t.Errorf("expected patch test status 'required', got '%s'", *patchTestSvc.PatchTestStatus)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user