payit/internal/web/handlers_test.go

127 lines
3.5 KiB
Go

package web
import (
"bytes"
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/rjNemo/payit/internal/payments"
)
type fakeCheckoutService struct {
result payments.CheckoutSessionResult
err error
req payments.CheckoutSessionRequest
}
func (f *fakeCheckoutService) CreateSession(ctx context.Context, req payments.CheckoutSessionRequest) (payments.CheckoutSessionResult, error) {
f.req = req
if f.err != nil {
return payments.CheckoutSessionResult{}, f.err
}
return f.result, nil
}
func TestCreateCheckoutSessionSuccess(t *testing.T) {
handler := &Handler{
checkout: &fakeCheckoutService{
result: payments.CheckoutSessionResult{ID: "cs_test_1", URL: "https://stripe.test/checkout"},
},
}
body, _ := json.Marshal(map[string]int{"quantity": 2})
req := httptest.NewRequest(http.MethodPost, "/api/checkout", bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.createCheckoutSession(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("expected status 200, got %d", rec.Code)
}
if ct := rec.Header().Get("Content-Type"); ct != "application/json" {
t.Fatalf("expected json content type, got %s", ct)
}
var payload payments.CheckoutSessionResult
if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil {
t.Fatalf("expected valid json response: %v", err)
}
if payload.ID != "cs_test_1" || payload.URL == "" {
t.Fatalf("unexpected payload: %#v", payload)
}
svc := handler.checkout.(*fakeCheckoutService)
if svc.req.Quantity != 2 {
t.Fatalf("expected quantity 2, got %d", svc.req.Quantity)
}
}
func TestCreateCheckoutSessionDefaultsQuantity(t *testing.T) {
fakeSvc := &fakeCheckoutService{
result: payments.CheckoutSessionResult{ID: "cs_test_1"},
}
handler := &Handler{checkout: fakeSvc}
req := httptest.NewRequest(http.MethodPost, "/api/checkout", http.NoBody)
rec := httptest.NewRecorder()
handler.createCheckoutSession(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("expected status 200, got %d", rec.Code)
}
if fakeSvc.req.Quantity != 0 {
t.Fatalf("expected zero quantity in request, got %d", fakeSvc.req.Quantity)
}
}
func TestCreateCheckoutSessionRejectsInvalidJSON(t *testing.T) {
handler := &Handler{checkout: &fakeCheckoutService{}}
req := httptest.NewRequest(http.MethodPost, "/api/checkout", bytes.NewBufferString("{"))
rec := httptest.NewRecorder()
handler.createCheckoutSession(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("expected status 400, got %d", rec.Code)
}
}
func TestCreateCheckoutSessionStripeFailure(t *testing.T) {
handler := &Handler{
checkout: &fakeCheckoutService{err: errors.New("stripe failure")},
}
req := httptest.NewRequest(http.MethodPost, "/api/checkout", http.NoBody)
rec := httptest.NewRecorder()
handler.createCheckoutSession(rec, req)
if rec.Code != http.StatusInternalServerError {
t.Fatalf("expected status 500, got %d", rec.Code)
}
}
func TestCreateCheckoutSessionMethodNotAllowed(t *testing.T) {
handler := &Handler{checkout: &fakeCheckoutService{}}
mux := http.NewServeMux()
mux.HandleFunc("POST /api/checkout", handler.createCheckoutSession)
req := httptest.NewRequest(http.MethodGet, "/api/checkout", http.NoBody)
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, req)
if rec.Code != http.StatusMethodNotAllowed {
t.Fatalf("expected status 405, got %d", rec.Code)
}
if allow := rec.Header().Get("Allow"); allow != http.MethodPost {
t.Fatalf("expected Allow header to be POST, got %s", allow)
}
}