package main import ( "net/http" "net/http/httptest" "testing" ) func TestParticipantsListCreateDelete(t *testing.T) { app := testApp(t) admin := testAdminUser(t, app) token := testToken(t, app, admin) mux := testMux(app) // Create req := testAuthRequest("POST", "/api/participants", map[string]string{"preferred_name": "Titania", "email": "titania@example.com"}, token) w := httptest.NewRecorder() mux.ServeHTTP(w, req) if w.Code != http.StatusCreated { t.Fatalf("create: status = %d\nbody: %s", w.Code, w.Body.String()) } created := parseJSON(t, w) id := created["id"].(float64) // List req = testAuthRequest("GET", "/api/participants", nil, token) w = httptest.NewRecorder() mux.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("list: status = %d", w.Code) } list := parseJSON(t, w) participants := list["participants"].([]any) if len(participants) != 1 { t.Errorf("list: got %d, want 1", len(participants)) } // Delete req = testAuthRequest("DELETE", "/api/participants/"+itoa(int(id)), nil, token) w = httptest.NewRecorder() mux.ServeHTTP(w, req) if w.Code != http.StatusNoContent { t.Errorf("delete: status = %d", w.Code) } // List again — should be empty req = testAuthRequest("GET", "/api/participants", nil, token) w = httptest.NewRecorder() mux.ServeHTTP(w, req) list = parseJSON(t, w) if ps, ok := list["participants"].([]any); ok && len(ps) != 0 { t.Errorf("after delete: got %d, want 0", len(ps)) } } func TestCheckInTicketHandler(t *testing.T) { app := testApp(t) admin := testAdminUser(t, app) token := testToken(t, app, admin) mux := testMux(app) p, _ := app.createParticipant(Participant{PreferredName: "Oberon", Email: "oberon@example.com"}) tk, _ := app.createTicket(Ticket{ParticipantID: &p.ID, Name: "Oberon", Source: "manual"}) req := testAuthRequest("POST", "/api/tickets/"+itoa(tk.ID)+"/checkin", nil, token) w := httptest.NewRecorder() mux.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("checkin: status = %d\nbody: %s", w.Code, w.Body.String()) } result := parseJSON(t, w) ticket := result["ticket"].(map[string]any) if ticket["checked_in_at"] == nil { t.Error("checked_in_at should be set after check-in") } } func TestGatekeeperRoleCanCheckIn(t *testing.T) { app := testApp(t) gate := testUserWithRole(t, app, "gateuser", "gatekeeper", []int{}) token := testToken(t, app, gate) mux := testMux(app) p, _ := app.createParticipant(Participant{PreferredName: "Puck", Email: "puck@example.com"}) tk, _ := app.createTicket(Ticket{ParticipantID: &p.ID, Name: "Puck", Source: "manual"}) req := testAuthRequest("POST", "/api/tickets/"+itoa(tk.ID)+"/checkin", nil, token) w := httptest.NewRecorder() mux.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("gatekeeper checkin: status = %d", w.Code) } } func TestGatekeeperRoleCannotDelete(t *testing.T) { app := testApp(t) gate := testUserWithRole(t, app, "gateuser", "gatekeeper", []int{}) token := testToken(t, app, gate) mux := testMux(app) p, _ := app.createParticipant(Participant{PreferredName: "Puck", Email: "puck@example.com"}) req := testAuthRequest("DELETE", "/api/participants/"+itoa(p.ID), nil, token) w := httptest.NewRecorder() mux.ServeHTTP(w, req) if w.Code != http.StatusForbidden { t.Errorf("gatekeeper delete: status = %d, want 403", w.Code) } }