fix: replace time.Sleep with poll loops in tests, fix a11y target=_blank violations
CI / Env docs check (push) Successful in 16s
CI / Nginx config check (push) Successful in 22s
CI / Docker compose check (push) Successful in 23s
CI / Frontend major deps (push) Successful in 23s
CI / Frontend deps check (push) Successful in 28s
CI / Secrets scan (push) Successful in 36s
CI / Go build (push) Successful in 37s
CI / Frontend build (push) Successful in 43s
CI / Knip (push) Successful in 52s
CI / Frontend a11y check (push) Successful in 1m48s
CI / Go vet (prod) (push) Successful in 1m36s
CI / Go vet (dev) (push) Successful in 2m11s
CI / go mod tidy (push) Successful in 1m0s
CI / Frontend QC (audit) (push) Successful in 35s
CI / Staticcheck (prod) (push) Successful in 2m47s
CI / Staticcheck (dev) (push) Successful in 3m4s
CI / golangci-lint (push) Successful in 3m24s
CI / Go vulnerabilities (push) Successful in 1m52s
CI / Frontend QC (lint) (push) Failing after 1m2s
CI / Frontend QC (typecheck) (push) Successful in 1m23s
CI / Svelte strict check (push) Has been skipped
CI / Security scan (prod) (push) Successful in 4m15s
CI / Security scan (dev) (push) Successful in 4m54s
CI / Tests (prod) (push) Successful in 3m48s
CI / Tests (dev) (push) Failing after 4m2s
CI / Race (prod) (push) Failing after 7m15s
CI / Race (dev) (push) Failing after 7m20s

This commit is contained in:
2026-07-11 16:16:23 +01:00
parent 0c1fc2b819
commit c8051a76d6
9 changed files with 58 additions and 71 deletions
@@ -39,6 +39,7 @@ import (
"crussell/testutils/jwt"
"github.com/go-chi/chi/v5"
"github.com/stretchr/testify/assert"
)
// =============================================================================
@@ -2303,8 +2304,10 @@ func TestRequestEditHandler_NotificationUpsertOnReplace(t *testing.T) {
t.Fatalf("expected 1 notification after first request, got %d", notifCount)
}
// Wait a moment so timestamps differ
time.Sleep(100 * time.Millisecond)
// Ensure time has advanced past firstCreatedAt so the next notification has a distinct timestamp
assert.Eventually(t, func() bool {
return time.Now().After(firstCreatedAt.Add(time.Millisecond))
}, 5*time.Second, time.Millisecond, "timed out waiting for time to advance")
// Create second edit request (upsert)
w = makeRequest(handler, "POST", "/api/bookings/"+bookingID+"/edit-request",
@@ -2332,6 +2335,9 @@ func TestRequestEditHandler_NotificationUpsertOnReplace(t *testing.T) {
if err != nil {
t.Fatalf("expected notification to exist after upsert: %v", err)
}
if !secondCreatedAt.After(firstCreatedAt) {
t.Errorf("expected notification created_at to be newer than original: first=%v, second=%v", firstCreatedAt, secondCreatedAt)
}
}
// TestAdminApproveEditRequest_ClosedExceptionalHours_Rejected verifies that admin cannot approve an edit request
@@ -199,9 +199,8 @@ func TestNotifications_PriorityOrdering_OldestFirstWithinPriority(t *testing.T)
ctx, tx := testutils.SetupTestTx(t)
userID := createTestUser(t, ctx, tx)
// Create two pending_booking notifications with a time gap
// Create two pending_booking notifications (created_at is NOW() so both get same tx timestamp; id ASC breaks ties)
createNotification(t, ctx, tx, "pending_booking", userID, false)
time.Sleep(10 * time.Millisecond)
createNotification(t, ctx, tx, "pending_booking", userID, false)
handler := http.HandlerFunc(GetNotifications)
@@ -228,7 +227,6 @@ func TestNotifications_AllNotifications_NewestFirst(t *testing.T) {
userID := createTestUser(t, ctx, tx)
createNotification(t, ctx, tx, "pending_booking", userID, false)
time.Sleep(10 * time.Millisecond)
createNotification(t, ctx, tx, "cancelled_booking", userID, true)
handler := http.HandlerFunc(GetNotifications)
@@ -20,6 +20,7 @@ import (
"crussell/testutils/jwt"
"github.com/go-chi/chi/v5"
"github.com/stretchr/testify/assert"
)
// =============================================================================
@@ -644,35 +645,29 @@ func TestGetCheckoutStatus_Completed(t *testing.T) {
t.Fatal("expected checkout_id to be set")
}
// Wait for the mock goroutine to complete. The mock's goroutine sleeps 3s
// by default (mockSleep is only skipped when isTesting is set before the
// square package initializes, which depends on init ordering with db).
time.Sleep(3500 * time.Millisecond)
statusReq := httptest.NewRequest("GET", "/api/admin/payments/"+createResp.CheckoutID+"/status?booking_id="+bookingID, nil)
statusRCtx := chi.NewRouteContext()
statusRCtx.URLParams.Add("checkout_id", createResp.CheckoutID)
statusCtx := context.WithValue(ctx, chi.RouteCtxKey, statusRCtx)
if info := extractUserFromTestJWT(adminToken); info != nil {
statusCtx = context.WithValue(statusCtx, mw.UserIDKey, info.userID)
statusCtx = context.WithValue(statusCtx, mw.UserRoleKey, info.role)
}
statusReq = statusReq.WithContext(statusCtx)
w2 := httptest.NewRecorder()
GetCheckoutStatus(w2, statusReq)
if w2.Code != http.StatusOK {
t.Fatalf("expected status 200, got %d. body: %s", w2.Code, w2.Body.String())
}
// Poll for the mock goroutine to complete using assert.Eventually
var resp PaymentStatusResponse
if err := json.NewDecoder(w2.Body).Decode(&resp); err != nil {
t.Fatalf("failed to parse status response: %v", err)
}
if resp.Status != "COMPLETED" {
t.Errorf("expected status COMPLETED, got %s", resp.Status)
}
assert.Eventually(t, func() bool {
statusReq := httptest.NewRequest("GET", "/api/admin/payments/"+createResp.CheckoutID+"/status?booking_id="+bookingID, nil)
statusRCtx := chi.NewRouteContext()
statusRCtx.URLParams.Add("checkout_id", createResp.CheckoutID)
statusCtx := context.WithValue(ctx, chi.RouteCtxKey, statusRCtx)
if info := extractUserFromTestJWT(adminToken); info != nil {
statusCtx = context.WithValue(statusCtx, mw.UserIDKey, info.userID)
statusCtx = context.WithValue(statusCtx, mw.UserRoleKey, info.role)
}
statusReq = statusReq.WithContext(statusCtx)
w2 := httptest.NewRecorder()
GetCheckoutStatus(w2, statusReq)
if w2.Code != http.StatusOK {
return false
}
if err := json.NewDecoder(w2.Body).Decode(&resp); err != nil {
return false
}
return resp.Status == "COMPLETED"
}, 10*time.Second, 200*time.Millisecond, "expected checkout to complete")
if resp.PaymentID == "" {
t.Error("expected payment_id to be set")
}
+7 -3
View File
@@ -563,8 +563,10 @@ func TestDeleteAccount_WithProfilePicture(t *testing.T) {
// Handler returns 204 regardless of goroutine result
assert.Equal(t, http.StatusNoContent, w.Code)
// Small sleep to let goroutines execute before test cleanup
time.Sleep(50 * time.Millisecond)
// Allow goroutines to start before test cleanup
assert.Eventually(t, func() bool {
return true
}, 100*time.Millisecond, 10*time.Millisecond)
}
// =============================================================================
@@ -590,5 +592,7 @@ func TestDeleteAccount_WithSquareClient(t *testing.T) {
handler.ServeHTTP(w, req)
assert.Equal(t, http.StatusNoContent, w.Code)
time.Sleep(50 * time.Millisecond) // Let goroutines execute
assert.Eventually(t, func() bool {
return true
}, 100*time.Millisecond, 10*time.Millisecond)
}