Fix nbtb, add tests
This commit is contained in:
@@ -3012,4 +3012,143 @@ func TestBookings_Edit_OpenDay_UserAllowed(t *testing.T) {
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200 for open day edit, got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Time Blocker Tests for User Bookings
|
||||
// =============================================================================
|
||||
|
||||
// TestBookings_Create_OverlappingBlocker_UserBlocked verifies that a regular user
|
||||
// CANNOT create a booking that overlaps with a time blocker. They receive 409 Conflict.
|
||||
func TestBookings_Create_OverlappingBlocker_UserBlocked(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
seedDefaultWorkingHours(t)
|
||||
|
||||
userID, err := fixtures.CreateTestUser(db.DB)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create test user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, userID)
|
||||
|
||||
// Set deposits_required=0 to avoid 48h advance booking requirement
|
||||
_, err = db.DB.Exec(context.Background(), "UPDATE users SET deposits_required = 0 WHERE id = $1", userID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set deposits_required: %v", err)
|
||||
}
|
||||
|
||||
serviceID, err := fixtures.CreateTestService(db.DB)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create test service: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteService(db.DB, serviceID)
|
||||
|
||||
// Create a time blocker for a specific time
|
||||
ukLocation, _ := time.LoadLocation("Europe/London")
|
||||
blockerTime := time.Date(2099, 12, 31, 10, 0, 0, 0, ukLocation)
|
||||
_, err = db.DB.Exec(context.Background(), `
|
||||
INSERT INTO time_blockers (start_time, duration_minutes, description, created_by)
|
||||
VALUES ($1, 60, 'Staff meeting', NULL)
|
||||
`, blockerTime)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create time blocker: %v", err)
|
||||
}
|
||||
|
||||
token := jwt.GenerateUserToken(userID)
|
||||
|
||||
// User tries to create booking overlapping the blocker
|
||||
req := CreateBookingRequest{
|
||||
StartTime: blockerTime,
|
||||
ServiceIDs: []string{serviceID},
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(CreateBookingHandler)
|
||||
w := makeRequest(handler, "POST", "/api/bookings", req, token)
|
||||
|
||||
// User should get 409 Conflict (not 201 Created)
|
||||
if w.Code != http.StatusConflict {
|
||||
t.Errorf("expected status 409, got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
// Verify error message mentions the blocker
|
||||
if !bytes.Contains(w.Body.Bytes(), []byte("blocked")) {
|
||||
t.Errorf("expected error message to mention 'blocked', got: %s", w.Body.String())
|
||||
}
|
||||
|
||||
// Verify NO booking was created
|
||||
var count int
|
||||
err = db.DB.QueryRow(context.Background(),
|
||||
"SELECT COUNT(*) FROM bookings WHERE user_id = $1", userID).Scan(&count)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to query bookings: %v", err)
|
||||
}
|
||||
if count != 0 {
|
||||
t.Errorf("expected 0 bookings (user should be blocked), got %d", count)
|
||||
}
|
||||
}
|
||||
|
||||
// TestBookings_Edit_OverlappingBlocker_UserBlocked verifies that a regular user
|
||||
// CANNOT edit a booking to a time that overlaps with a time blocker.
|
||||
func TestBookings_Edit_OverlappingBlocker_UserBlocked(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
seedDefaultWorkingHours(t)
|
||||
|
||||
userID, err := fixtures.CreateTestUser(db.DB)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create test user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, userID)
|
||||
|
||||
// Set deposits_required=0 to avoid 48h advance booking requirement
|
||||
_, err = db.DB.Exec(context.Background(), "UPDATE users SET deposits_required = 0 WHERE id = $1", userID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set deposits_required: %v", err)
|
||||
}
|
||||
|
||||
serviceID, err := fixtures.CreateTestService(db.DB)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create test service: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteService(db.DB, serviceID)
|
||||
|
||||
// Create a booking first
|
||||
bookingID, err := fixtures.CreateTestBooking(db.DB, userID, serviceID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create test booking: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteBooking(db.DB, bookingID)
|
||||
|
||||
// Create a time blocker for a specific time
|
||||
ukLocation, _ := time.LoadLocation("Europe/London")
|
||||
blockerTime := time.Date(2099, 12, 31, 10, 0, 0, 0, ukLocation)
|
||||
_, err = db.DB.Exec(context.Background(), `
|
||||
INSERT INTO time_blockers (start_time, duration_minutes, description, created_by)
|
||||
VALUES ($1, 60, 'Staff meeting', NULL)
|
||||
`, blockerTime)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create time blocker: %v", err)
|
||||
}
|
||||
|
||||
token := jwt.GenerateUserToken(userID)
|
||||
|
||||
// User tries to edit booking to overlap the blocker
|
||||
req := EditBookingRequest{
|
||||
StartTime: blockerTime,
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(EditBookingHandler)
|
||||
w := makeRequest(handler, "PUT", "/api/bookings/"+bookingID, req, token)
|
||||
|
||||
// User should get 409 Conflict
|
||||
if w.Code != http.StatusConflict {
|
||||
t.Errorf("expected status 409, got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
// Verify error message mentions the blocker
|
||||
if !bytes.Contains(w.Body.Bytes(), []byte("blocked")) {
|
||||
t.Errorf("expected error message to mention 'blocked', got: %s", w.Body.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user