rentease/internal/server/handle_stripe_webhook_test.go
2025-11-02 21:45:37 +01:00

134 lines
3.5 KiB
Go

package server
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/stripe/stripe-go/v83"
)
type stubStripeEventService struct {
intentCalled bool
chargeCalled bool
err error
}
func (s *stubStripeEventService) HandlePaymentIntentSucceeded(ctx context.Context, pi *stripe.PaymentIntent) error {
s.intentCalled = true
return s.err
}
func (s *stubStripeEventService) HandleChargeRefunded(ctx context.Context, ch *stripe.Charge) error {
s.chargeCalled = true
return s.err
}
func TestHandleStripeWebhookPaymentIntent(t *testing.T) {
secret := "whsec_test"
payload := map[string]any{
"id": "evt_test",
"type": "payment_intent.succeeded",
"api_version": stripe.APIVersion,
"data": map[string]any{
"object": map[string]any{
"id": "pi_123",
"amount": 10000,
"amount_received": 10000,
"currency": "eur",
"status": "succeeded",
"metadata": map[string]string{"booking_id": "42"},
"payment_method_types": []string{"card"},
},
},
}
payloadBytes, err := json.Marshal(payload)
if err != nil {
t.Fatalf("failed to marshal payload: %v", err)
}
restore := stubConstructEvent(stripe.EventTypePaymentIntentSucceeded, payloadBytes)
defer restore()
service := &stubStripeEventService{}
handler := handleStripeWebhook(service, secret)
req := httptest.NewRequest(http.MethodPost, "/webhooks/stripe", strings.NewReader(string(payloadBytes)))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Stripe-Signature", "test")
rec := httptest.NewRecorder()
handler(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", rec.Code)
}
if !service.intentCalled {
t.Fatalf("expected payment intent handler to be called")
}
}
func TestHandleStripeWebhookChargeRefunded(t *testing.T) {
secret := "whsec_test"
payload := map[string]any{
"id": "evt_charge",
"type": "charge.refunded",
"api_version": stripe.APIVersion,
"data": map[string]any{
"object": map[string]any{
"id": "ch_123",
"amount": 5000,
"amount_refunded": 5000,
"payment_intent": map[string]any{
"id": "pi_123",
},
},
},
}
payloadBytes, _ := json.Marshal(payload)
restore := stubConstructEvent(stripe.EventTypeChargeRefunded, payloadBytes)
defer restore()
service := &stubStripeEventService{}
handler := handleStripeWebhook(service, secret)
req := httptest.NewRequest(http.MethodPost, "/webhooks/stripe", strings.NewReader(string(payloadBytes)))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Stripe-Signature", "test")
rec := httptest.NewRecorder()
handler(rec, req)
if !service.chargeCalled {
t.Fatalf("expected charge handler to be called")
}
}
func TestHandleStripeWebhookInvalidSignature(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/webhooks/stripe", strings.NewReader("{}"))
req.Header.Set("Stripe-Signature", "invalid")
rec := httptest.NewRecorder()
handler := handleStripeWebhook(&stubStripeEventService{}, "secret")
handler(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("expected 400 status, got %d", rec.Code)
}
}
func stubConstructEvent(eventType stripe.EventType, payload []byte) func() {
original := constructEvent
constructEvent = func(_ []byte, _ string, _ string) (stripe.Event, error) {
event := stripe.Event{Type: eventType}
event.Data = &stripe.EventData{Raw: payload}
return event, nil
}
return func() { constructEvent = original }
}