refactor: optimize test DB setup — TestMain per package, truncate-only between tests
- Add TestMain to all 10 test packages (schema DROP+CREATE runs once per package) - Convert per-test setupTestDB to resetTestData (TRUNCATE only, ~60% faster) - Add 3 missing tables to TruncateTables (booking_edit_requests, exceptional_group_applications, business_settings) - Remove dead truncateDiscountTables helper - Consolidate discount_test.go into package bookings (was external test package) - Update testutils.SetupTestDB to truncate-only - Fix unused imports across user, bookings, and handlers packages - Verify: 286 passing, 2 skipped, 0 failures with -count=2 (no state leakage)
This commit is contained in:
@@ -77,8 +77,7 @@ func seedDefaultWorkingHours(t *testing.T) {
|
||||
// TestAdminBookings_List verifies that an admin can list all bookings in the
|
||||
// system with pagination support.
|
||||
func TestAdminBookings_List(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -134,8 +133,7 @@ func TestAdminBookings_List(t *testing.T) {
|
||||
// TestAdminBookings_List_FilterByStatus tests that an admin can filter
|
||||
// bookings by status (e.g., pending, confirmed, completed).
|
||||
func TestAdminBookings_List_FilterByStatus(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -199,8 +197,7 @@ func TestAdminBookings_List_FilterByStatus(t *testing.T) {
|
||||
// TestAdminBookings_Create verifies that an admin can create a booking
|
||||
// on behalf of a user. The booking is created with 'confirmed' status.
|
||||
func TestAdminBookings_Create(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -268,8 +265,7 @@ func TestAdminBookings_Create(t *testing.T) {
|
||||
// creation fails with HTTP 400 when required fields (userID, startTime, serviceIDs)
|
||||
// are missing or invalid.
|
||||
func TestAdminBookings_Create_InvalidInput(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -337,8 +333,7 @@ func TestAdminBookings_Create_InvalidInput(t *testing.T) {
|
||||
// TestAdminBookings_Search tests that an admin can search bookings by
|
||||
// notes, customer name, or other text fields.
|
||||
func TestAdminBookings_Search(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -390,8 +385,7 @@ func TestAdminBookings_Search(t *testing.T) {
|
||||
// TestAdminBookings_Search_MissingQuery verifies that searching without
|
||||
// a query parameter returns HTTP 400 Bad Request.
|
||||
func TestAdminBookings_Search_MissingQuery(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -414,8 +408,7 @@ func TestAdminBookings_Search_MissingQuery(t *testing.T) {
|
||||
// TestAdminBookings_Get verifies that an admin can retrieve a single booking by ID and that
|
||||
// the response includes populated user and services relationships.
|
||||
func TestAdminBookings_Get(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -468,8 +461,7 @@ func TestAdminBookings_Get(t *testing.T) {
|
||||
|
||||
// TestAdminBookings_Get_NotFound verifies that requesting a non-existent booking returns 404.
|
||||
func TestAdminBookings_Get_NotFound(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -491,8 +483,7 @@ func TestAdminBookings_Get_NotFound(t *testing.T) {
|
||||
|
||||
// TestAdminBookings_GetUserBookings verifies that an admin can retrieve all bookings for a specific user.
|
||||
func TestAdminBookings_GetUserBookings(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -552,8 +543,7 @@ func TestAdminBookings_GetUserBookings(t *testing.T) {
|
||||
// TestAdminBookings_Progress verifies that an admin can change a booking's status (e.g., pending to confirmed),
|
||||
// and that the status is correctly updated in both the response and database.
|
||||
func TestAdminBookings_Progress(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -612,8 +602,7 @@ func TestAdminBookings_Progress(t *testing.T) {
|
||||
|
||||
// TestAdminBookings_Progress_InvalidStatus verifies that providing an invalid status value returns 400 Bad Request.
|
||||
func TestAdminBookings_Progress_InvalidStatus(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -653,8 +642,7 @@ func TestAdminBookings_Progress_InvalidStatus(t *testing.T) {
|
||||
|
||||
// TestAdminBookings_Progress_NotFound verifies that attempting to progress a non-existent booking returns 404.
|
||||
func TestAdminBookings_Progress_NotFound(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -680,8 +668,7 @@ func TestAdminBookings_Progress_NotFound(t *testing.T) {
|
||||
|
||||
// TestAdminBookings_Confirm verifies that an admin can confirm a pending booking, updating its status to 'confirmed'.
|
||||
func TestAdminBookings_Confirm(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -729,8 +716,7 @@ func TestAdminBookings_Confirm(t *testing.T) {
|
||||
// TestAdminBookings_Confirm_AlreadyConfirmed verifies idempotency - attempting to confirm
|
||||
// an already-confirmed booking returns 404 Not Found.
|
||||
func TestAdminBookings_Confirm_AlreadyConfirmed(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -778,8 +764,7 @@ func TestAdminBookings_Confirm_AlreadyConfirmed(t *testing.T) {
|
||||
|
||||
// TestAdminBookings_Cancel verifies that an admin can cancel a booking, updating its status to 'we_cancelled'.
|
||||
func TestAdminBookings_Cancel(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -831,8 +816,7 @@ func TestAdminBookings_Cancel(t *testing.T) {
|
||||
|
||||
// TestAdminBookings_Cancel_NotFound verifies that attempting to cancel a non-existent booking returns 404.
|
||||
func TestAdminBookings_Cancel_NotFound(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -851,8 +835,7 @@ func TestAdminBookings_Cancel_NotFound(t *testing.T) {
|
||||
// TestAdminBookings_Cancel_PendingStatus verifies that admin cancellations of pending bookings
|
||||
// do NOT create admin notifications (pending cancellations don't require staff attention).
|
||||
func TestAdminBookings_Cancel_PendingStatus(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -915,8 +898,7 @@ func TestAdminBookings_Cancel_PendingStatus(t *testing.T) {
|
||||
// TestAdminBookings_Cancel_ConfirmedCreatesNotification verifies that cancelling a confirmed
|
||||
// booking creates an admin notification for staff awareness.
|
||||
func TestAdminBookings_Cancel_ConfirmedCreatesNotification(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -982,8 +964,7 @@ func TestAdminBookings_Cancel_ConfirmedCreatesNotification(t *testing.T) {
|
||||
|
||||
// TestAdminBookings_Cancel_InProgressStatus verifies cancellation of in-progress bookings.
|
||||
func TestAdminBookings_Cancel_InProgressStatus(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1038,8 +1019,7 @@ func TestAdminBookings_Cancel_InProgressStatus(t *testing.T) {
|
||||
// TestAdminBookings_Cancel_AlreadyCancelledRejectsCancellation verifies that attempting to
|
||||
// cancel an already-cancelled booking returns 404 Not Found (idempotency guard).
|
||||
func TestAdminBookings_Cancel_AlreadyCancelledRejectsCancellation(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1084,8 +1064,7 @@ func TestAdminBookings_Cancel_AlreadyCancelledRejectsCancellation(t *testing.T)
|
||||
// TestAdminBookings_Cancel_CompletedRejectsCancellation verifies that attempting to cancel
|
||||
// a completed booking returns 404 Not Found (cannot cancel finished appointments).
|
||||
func TestAdminBookings_Cancel_CompletedRejectsCancellation(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1134,8 +1113,7 @@ func TestAdminBookings_Cancel_CompletedRejectsCancellation(t *testing.T) {
|
||||
// TestAdminBookings_NonAdmin verifies that regular users receive 403 Forbidden when attempting
|
||||
// to access any admin booking endpoints (list, get, create, progress, confirm, cancel, search).
|
||||
func TestAdminBookings_NonAdmin(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
_, err := fixtures.CreateTestUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1210,8 +1188,7 @@ func TestAdminBookings_NonAdmin(t *testing.T) {
|
||||
// TestAdminBookings_Create_DuringHolidayHours_Rejected verifies that an admin cannot create a booking
|
||||
// during hours marked as closed in the exceptional working hours (holiday) system.
|
||||
func TestAdminBookings_Create_DuringHolidayHours_Rejected(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1294,8 +1271,7 @@ func TestAdminBookings_Create_DuringHolidayHours_Rejected(t *testing.T) {
|
||||
// TestAdminBookings_Search_CaseInsensitive verifies that the admin booking search is case-insensitive,
|
||||
// matching booking notes regardless of uppercase/lowercase differences.
|
||||
func TestAdminBookings_Search_CaseInsensitive(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1359,8 +1335,7 @@ func TestAdminBookings_Search_CaseInsensitive(t *testing.T) {
|
||||
// TestAdminBookings_Search_NoResults verifies that searching with a query that matches no bookings
|
||||
// returns an empty list with total count of 0.
|
||||
func TestAdminBookings_Search_NoResults(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1412,8 +1387,7 @@ func TestAdminBookings_Search_NoResults(t *testing.T) {
|
||||
// TestAdminBookings_Search_MultipleResults verifies that search returns all bookings whose notes
|
||||
// contain the search query, with correct total count.
|
||||
func TestAdminBookings_Search_MultipleResults(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1489,8 +1463,7 @@ func TestAdminBookings_Search_MultipleResults(t *testing.T) {
|
||||
// TestAdminBookings_ListEditRequests verifies that an admin can list all pending edit requests
|
||||
// for a specific booking, and that the response includes the correct count and request details.
|
||||
func TestAdminBookings_ListEditRequests(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1580,8 +1553,7 @@ func TestAdminBookings_ListEditRequests(t *testing.T) {
|
||||
// TestAdminBookings_DenyEditRequest verifies that denying an edit request deletes the request
|
||||
// while keeping the original booking time unchanged, and returns success.
|
||||
func TestAdminBookings_DenyEditRequest(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1681,8 +1653,7 @@ func TestAdminBookings_DenyEditRequest(t *testing.T) {
|
||||
// TestAdminBookings_ApproveEditRequest verifies that approving an edit request updates the booking's
|
||||
// start_time to the requested time, deletes the edit request, and acknowledges the admin notification.
|
||||
func TestAdminBookings_ApproveEditRequest(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create admin user
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
@@ -1820,8 +1791,7 @@ func TestAdminBookings_ApproveEditRequest(t *testing.T) {
|
||||
// deposit-related fields (deposit_required, deposit_amount, deposit_paid, deposit_deadline)
|
||||
// for bookings that have deposit_required=true.
|
||||
func TestAdminBookings_Get_DepositFields(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1892,8 +1862,7 @@ func TestAdminBookings_Get_DepositFields(t *testing.T) {
|
||||
// TestAdminBookings_List_DepositFields verifies that admin booking list returns
|
||||
// deposit-related fields for each booking.
|
||||
func TestAdminBookings_List_DepositFields(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -1970,8 +1939,7 @@ func TestAdminBookings_List_DepositFields(t *testing.T) {
|
||||
// create bookings that overlap with time blockers, but receive a warning.
|
||||
// The booking is still created (201 Created), unlike regular users who get 409.
|
||||
func TestAdminBookings_Create_OverlappingBlocker_WithWarning(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -2051,8 +2019,7 @@ func TestAdminBookings_Create_OverlappingBlocker_WithWarning(t *testing.T) {
|
||||
// edit bookings to overlap with time blockers, but receive a warning.
|
||||
// The booking is still updated (200 OK with warnings), unlike regular users who get 409.
|
||||
func TestAdminBookings_Edit_OverlappingBlocker_WithWarning(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -2141,8 +2108,7 @@ func TestAdminBookings_Edit_OverlappingBlocker_WithWarning(t *testing.T) {
|
||||
// TestAdminBookings_Create_EnforceDeposits_Bypass tests that admin can create bookings
|
||||
// for users with outstanding deposits by setting enforce_deposits=false.
|
||||
func TestAdminBookings_Create_EnforceDeposits_Bypass(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -2189,8 +2155,7 @@ func TestAdminBookings_Create_EnforceDeposits_Bypass(t *testing.T) {
|
||||
// TestAdminBookings_Create_EnforceDeposits_Enforced tests that by default (or when enforce_deposits=true),
|
||||
// admin bookings respect the deposit requirement rules.
|
||||
func TestAdminBookings_Create_EnforceDeposits_Enforced(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -2252,8 +2217,7 @@ func TestAdminBookings_Create_EnforceDeposits_Enforced(t *testing.T) {
|
||||
// TestAdminBookings_Create_WalkIn tests that admins can create walk-in bookings
|
||||
// (no advance time requirement), including immediate/past times if needed.
|
||||
func TestAdminBookings_Create_WalkIn(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -2299,8 +2263,7 @@ func TestAdminBookings_Create_WalkIn(t *testing.T) {
|
||||
// TestAdminBookings_Create_WalkInWithDeposits tests that admins can create walk-ins
|
||||
// even when user has outstanding deposits and enforce_deposits=false.
|
||||
func TestAdminBookings_Create_WalkInWithDeposits(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -2358,8 +2321,7 @@ func TestAdminBookings_Create_WalkInWithDeposits(t *testing.T) {
|
||||
// confirmed booking is progressed to completed with at least one payment, the user's
|
||||
// deposits_required is reduced by 1.
|
||||
func TestAdminBookings_Confirm_CompletesWithPayment_ReducesDeposits(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -2444,8 +2406,7 @@ func TestAdminBookings_Confirm_CompletesWithPayment_ReducesDeposits(t *testing.T
|
||||
// TestAdminBookings_Confirm_CompletesWithoutPayment_NoReduction verifies that when a
|
||||
// booking is completed without any payments, the user's deposits_required is NOT reduced.
|
||||
func TestAdminBookings_Confirm_CompletesWithoutPayment_NoReduction(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -2524,8 +2485,7 @@ func TestAdminBookings_Confirm_CompletesWithoutPayment_NoReduction(t *testing.T)
|
||||
// enforce_deposits is set to false, the admin can create a second booking for a user
|
||||
// who already has an active booking, bypassing the one-active-booking limit.
|
||||
func TestAdminBookings_Create_EnforceDepositsFalse_BypassesLimit(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -2590,8 +2550,7 @@ func TestAdminBookings_Create_EnforceDepositsFalse_BypassesLimit(t *testing.T) {
|
||||
// enforce_deposits is set to false, the admin can create a booking within 24 hours
|
||||
// for a user with outstanding deposits.
|
||||
func TestAdminBookings_Create_EnforceDepositsFalse_Within24h(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
@@ -2648,8 +2607,7 @@ func TestAdminBookings_Create_EnforceDepositsFalse_Within24h(t *testing.T) {
|
||||
// TestAdminBookings_Create_WalkInGuestUser verifies that an admin can create a booking
|
||||
// for a guest user (created via fixtures.CreateTestGuestUser).
|
||||
func TestAdminBookings_Create_WalkInGuestUser(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
if err != nil {
|
||||
|
||||
@@ -28,8 +28,7 @@ import (
|
||||
// with name, description, price, duration, and minimum age requirements. The new
|
||||
// service is active by default and stored in the database.
|
||||
func TestAdminServices_Create(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create admin user in DB first
|
||||
_, err := db.DB.Exec(context.Background(), `
|
||||
@@ -75,8 +74,7 @@ func TestAdminServices_Create(t *testing.T) {
|
||||
// TestAdminServices_List tests that an admin can retrieve all services,
|
||||
// including inactive ones. This is useful for managing the full service catalog.
|
||||
func TestAdminServices_List(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Insert test services
|
||||
_, err := db.DB.Exec(context.Background(), `
|
||||
@@ -127,8 +125,7 @@ func TestAdminServices_List(t *testing.T) {
|
||||
// active status on/off. This is used to temporarily disable a service without
|
||||
// deleting it from the system.
|
||||
func TestAdminServices_Toggle(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create a service
|
||||
var serviceID string
|
||||
@@ -178,8 +175,7 @@ func TestAdminServices_Toggle(t *testing.T) {
|
||||
// by setting is_active to false. The service record remains but is hidden from
|
||||
// customers.
|
||||
func TestAdminServices_Delete(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create a service
|
||||
var serviceID string
|
||||
@@ -214,8 +210,7 @@ func TestAdminServices_Delete(t *testing.T) {
|
||||
// Forbidden when attempting to create, list, toggle, or delete services. This
|
||||
// ensures proper role-based access control.
|
||||
func TestAdminServices_NonAdmin(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create regular user in DB
|
||||
_, err := db.DB.Exec(context.Background(), `
|
||||
|
||||
@@ -9,48 +9,19 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"crussell/db"
|
||||
"crussell/mw"
|
||||
"crussell/testutils/jwt"
|
||||
"crussell/testutils/testdb"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// TestMain initializes test environment variables before any tests run
|
||||
func TestMain(m *testing.M) {
|
||||
// Set database environment variables for test database
|
||||
os.Setenv("POSTGRES_USER", "myuser")
|
||||
os.Setenv("POSTGRES_PASSWORD", "mypassword")
|
||||
os.Setenv("POSTGRES_HOST", "localhost")
|
||||
os.Setenv("POSTGRES_DB", "crussell_test")
|
||||
os.Setenv("GO_TESTING", "true")
|
||||
|
||||
// Run the tests
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// setupTestDB replaces the global db.DB with a test pool and returns a cleanup function
|
||||
func setupTestDB(t *testing.T) func() {
|
||||
// resetTestData truncates tables to clean up data between tests
|
||||
func resetTestData(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
pool := testdb.Pool(t)
|
||||
testdb.Migrate(t, pool)
|
||||
testdb.TruncateTables(t, pool) // Clear data between tests
|
||||
|
||||
originalDB := db.DB
|
||||
db.DB = pool
|
||||
|
||||
jwt.Init()
|
||||
|
||||
return func() {
|
||||
db.DB = originalDB
|
||||
pool.Close()
|
||||
}
|
||||
testdb.TruncateTables(t, db.DB)
|
||||
}
|
||||
|
||||
// makeAdminRequest creates a request with admin context
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
//go:build test
|
||||
// +build test
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"crussell/db"
|
||||
"crussell/testutils/testdb"
|
||||
"crussell/testutils/jwt"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
pool, err := testdb.NewPool("")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
testdb.Migrate(&testing.T{}, pool)
|
||||
db.DB = pool
|
||||
jwt.Init()
|
||||
code := m.Run()
|
||||
pool.Close()
|
||||
os.Exit(code)
|
||||
}
|
||||
@@ -30,8 +30,7 @@ import (
|
||||
// TestAdminToday_CurrentNext verifies that an admin can retrieve the currently
|
||||
// in-progress booking and the next upcoming booking for the dashboard.
|
||||
func TestAdminToday_CurrentNext(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -106,8 +105,7 @@ func TestAdminToday_CurrentNext(t *testing.T) {
|
||||
// TestAdminToday_CurrentNext_ClosingTime verifies that the current-next endpoint
|
||||
// returns the closing time for today.
|
||||
func TestAdminToday_CurrentNext_ClosingTime(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Seed working hours for today (query uses current weekday)
|
||||
todayWeekday := int(time.Now().Weekday())
|
||||
@@ -151,8 +149,7 @@ func TestAdminToday_CurrentNext_ClosingTime(t *testing.T) {
|
||||
// TestAdminToday_Appointments tests that an admin can get a list of all
|
||||
// bookings scheduled for today with their details.
|
||||
func TestAdminToday_Appointments(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -227,8 +224,7 @@ func TestAdminToday_Appointments(t *testing.T) {
|
||||
// TestAdminToday_PendingApprovals verifies that an admin can see all pending
|
||||
// bookings that require approval/confirmation.
|
||||
func TestAdminToday_PendingApprovals(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -310,8 +306,7 @@ func TestAdminToday_PendingApprovals(t *testing.T) {
|
||||
//
|
||||
// The transition happens silently in the background during GET requests, not via cron.
|
||||
func TestAdminToday_AutoTransition_ConfirmedToInProgress(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -384,8 +379,7 @@ func TestAdminToday_AutoTransition_ConfirmedToInProgress(t *testing.T) {
|
||||
//
|
||||
// The transition happens silently in the background during GET requests, not via cron.
|
||||
func TestAdminToday_AutoTransition_InProgressToCompleted(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -455,8 +449,7 @@ func TestAdminToday_AutoTransition_InProgressToCompleted(t *testing.T) {
|
||||
// TestAdminToday_NoAutoTransition_BeforeStartTime verifies that a confirmed
|
||||
// booking that hasn't started yet is NOT transitioned to in_progress.
|
||||
func TestAdminToday_NoAutoTransition_BeforeStartTime(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -525,8 +518,7 @@ func TestAdminToday_NoAutoTransition_BeforeStartTime(t *testing.T) {
|
||||
// TestAdminToday_AutoTransition_CurrentNextHandler verifies that auto-transition
|
||||
// also works when calling GetCurrentAndNextHandler (not just appointments handler)
|
||||
func TestAdminToday_AutoTransition_CurrentNextHandler(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -619,8 +611,7 @@ func TestAdminNotifications_Acknowledge(t *testing.T) {
|
||||
// TestAdminToday_NonAdmin verifies that non-admin users receive HTTP 403
|
||||
// when accessing today's dashboard endpoints.
|
||||
func TestAdminToday_NonAdmin(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Test current-next endpoint
|
||||
currentNextHandler := mw.RequireAdmin(http.HandlerFunc(today.GetCurrentAndNextHandler))
|
||||
|
||||
@@ -29,8 +29,7 @@ import (
|
||||
// TestAdminUsers_List verifies that an admin can list all users in the
|
||||
// system with their details including account role and type.
|
||||
func TestAdminUsers_List(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test users
|
||||
_, err := db.DB.Exec(context.Background(), `
|
||||
@@ -68,8 +67,7 @@ func TestAdminUsers_List(t *testing.T) {
|
||||
// TestAdminUsers_Get tests that an admin can retrieve detailed information
|
||||
// about a specific user including their profile and account settings.
|
||||
func TestAdminUsers_Get(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -106,8 +104,7 @@ func TestAdminUsers_Get(t *testing.T) {
|
||||
// TestAdminUsers_Get_NotFound verifies that requesting details for a
|
||||
// non-existent user returns HTTP 404 Not Found.
|
||||
func TestAdminUsers_Get_NotFound(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
handler := http.HandlerFunc(user.GetAdminUserHandler)
|
||||
// Use 12-char or less ID to avoid CHAR(12) constraint error
|
||||
@@ -122,8 +119,7 @@ func TestAdminUsers_Get_NotFound(t *testing.T) {
|
||||
// identifies which services require patch tests and returns only those services
|
||||
// the user is eligible for based on age requirements.
|
||||
func TestAdminUsers_PatchTests_Eligible(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -199,8 +195,7 @@ func TestAdminUsers_PatchTests_Eligible(t *testing.T) {
|
||||
// user already has a valid patch test on file, that service is filtered out
|
||||
// from the eligible list (since they've already completed it).
|
||||
func TestAdminUsers_PatchTests_Eligible_WithExisting(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -286,8 +281,7 @@ func TestAdminUsers_PatchTests_Eligible_WithExisting(t *testing.T) {
|
||||
// TestAdminUsers_AddPatchTest verifies that an admin can record a patch
|
||||
// test completion for a user, creating a user_patch_tests record.
|
||||
func TestAdminUsers_AddPatchTest(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -346,8 +340,7 @@ func TestAdminUsers_AddPatchTest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAdminUsers_AddPatchTest_InvalidPatchTest(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
@@ -374,8 +367,7 @@ func TestAdminUsers_AddPatchTest_InvalidPatchTest(t *testing.T) {
|
||||
// TestAdminUsers_NonAdmin verifies that non-admin users receive HTTP 403
|
||||
// Forbidden when attempting to list users, get user details, or manage patch tests.
|
||||
func TestAdminUsers_NonAdmin(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create regular user in DB
|
||||
_, err := db.DB.Exec(context.Background(), `
|
||||
@@ -429,8 +421,7 @@ func TestAdminUsers_NonAdmin(t *testing.T) {
|
||||
// TestAdminUsers_Get_Success is an additional test verifying admin can
|
||||
// retrieve user details including ID, name, email, and account role.
|
||||
func TestAdminUsers_Get_Success(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create a test user
|
||||
var userID string
|
||||
@@ -478,8 +469,7 @@ func TestAdminUsers_Get_Success(t *testing.T) {
|
||||
// TestAdminUsers_AddPatchTest_Duplicate verifies that recording the same patch test
|
||||
// twice updates the tested_at timestamp (upsert behavior).
|
||||
func TestAdminUsers_AddPatchTest_Duplicate(t *testing.T) {
|
||||
cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
resetTestData(t)
|
||||
|
||||
// Create test user
|
||||
var userID string
|
||||
|
||||
Reference in New Issue
Block a user