testing update + docs

This commit is contained in:
2026-03-02 10:16:55 +00:00
parent 803aab7073
commit eac5dccc3c
14 changed files with 203 additions and 405 deletions
+22 -305
View File
@@ -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)
}
}