saveinmed/backend/internal/payments/payments_test.go
Tiago Yamamoto c53cd5a4dd test: add Stripe and Mock gateway tests (+79% payments coverage)
Added 12 new tests for payment gateways:
- TestNewStripeGateway, TestStripeCreatePreference, TestStripeCreatePaymentIntent
- TestNewMockGateway, TestMockCreatePreference, TestMockConfirmPayment, TestMockRefundPayment
- Context cancellation tests for all gateways

Coverage increases:
- Payments: 11.8% → 91.4% (+79.6%)
- Handler: 32.6% → 36.9%
- Middleware: 90.8%
- Config: 85.7%
- Server: 69.1%

Frontend: 95 tests passing
2025-12-26 23:42:38 -03:00

331 lines
8.7 KiB
Go

package payments
import (
"context"
"testing"
"time"
"github.com/gofrs/uuid/v5"
"github.com/saveinmed/backend-go/internal/domain"
)
func TestNewMercadoPagoGateway(t *testing.T) {
gateway := NewMercadoPagoGateway("https://api.mercadopago.com", 2.5)
if gateway.BaseURL != "https://api.mercadopago.com" {
t.Errorf("expected BaseURL 'https://api.mercadopago.com', got '%s'", gateway.BaseURL)
}
if gateway.MarketplaceCommission != 2.5 {
t.Errorf("expected commission 2.5, got %f", gateway.MarketplaceCommission)
}
}
func TestCreatePreference(t *testing.T) {
gateway := NewMercadoPagoGateway("https://api.mercadopago.com", 2.5)
order := &domain.Order{
ID: uuid.Must(uuid.NewV7()),
BuyerID: uuid.Must(uuid.NewV7()),
SellerID: uuid.Must(uuid.NewV7()),
TotalCents: 10000, // R$100
}
ctx := context.Background()
pref, err := gateway.CreatePreference(ctx, order)
if err != nil {
t.Fatalf("failed to create preference: %v", err)
}
if pref.OrderID != order.ID {
t.Errorf("expected order ID %s, got %s", order.ID, pref.OrderID)
}
if pref.Gateway != "mercadopago" {
t.Errorf("expected gateway 'mercadopago', got '%s'", pref.Gateway)
}
if pref.CommissionPct != 2.5 {
t.Errorf("expected commission 2.5, got %f", pref.CommissionPct)
}
// Test marketplace fee calculation (2.5% of 10000 = 250)
expectedFee := int64(250)
if pref.MarketplaceFee != expectedFee {
t.Errorf("expected marketplace fee %d, got %d", expectedFee, pref.MarketplaceFee)
}
// Test seller receivable calculation (10000 - 250 = 9750)
expectedReceivable := int64(9750)
if pref.SellerReceivable != expectedReceivable {
t.Errorf("expected seller receivable %d, got %d", expectedReceivable, pref.SellerReceivable)
}
// Test payment URL format
expectedURL := "https://api.mercadopago.com/checkout/v1/redirect?order_id=" + order.ID.String()
if pref.PaymentURL != expectedURL {
t.Errorf("expected URL '%s', got '%s'", expectedURL, pref.PaymentURL)
}
}
func TestCreatePreferenceWithDifferentCommissions(t *testing.T) {
testCases := []struct {
name string
commission float64
totalCents int64
expectedFee int64
expectedSeller int64
}{
{"5% commission", 5.0, 10000, 500, 9500},
{"10% commission", 10.0, 10000, 1000, 9000},
{"0% commission", 0.0, 10000, 0, 10000},
{"2.5% on large order", 2.5, 100000, 2500, 97500},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
gateway := NewMercadoPagoGateway("https://test.com", tc.commission)
order := &domain.Order{
ID: uuid.Must(uuid.NewV7()),
TotalCents: tc.totalCents,
}
pref, err := gateway.CreatePreference(context.Background(), order)
if err != nil {
t.Fatalf("failed to create preference: %v", err)
}
if pref.MarketplaceFee != tc.expectedFee {
t.Errorf("expected fee %d, got %d", tc.expectedFee, pref.MarketplaceFee)
}
if pref.SellerReceivable != tc.expectedSeller {
t.Errorf("expected seller receivable %d, got %d", tc.expectedSeller, pref.SellerReceivable)
}
})
}
}
func TestCreatePreferenceWithCancelledContext(t *testing.T) {
gateway := NewMercadoPagoGateway("https://api.mercadopago.com", 2.5)
order := &domain.Order{
ID: uuid.Must(uuid.NewV7()),
TotalCents: 10000,
}
ctx, cancel := context.WithCancel(context.Background())
cancel() // Cancel immediately
_, err := gateway.CreatePreference(ctx, order)
if err == nil {
t.Error("expected error for cancelled context")
}
}
func TestCreatePreferenceWithTimeout(t *testing.T) {
gateway := NewMercadoPagoGateway("https://api.mercadopago.com", 2.5)
order := &domain.Order{
ID: uuid.Must(uuid.NewV7()),
TotalCents: 10000,
}
// Create a context that will timeout after a very short duration
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
defer cancel()
// Wait for context to expire
time.Sleep(10 * time.Millisecond)
_, err := gateway.CreatePreference(ctx, order)
if err == nil {
t.Error("expected error for timed out context")
}
}
func TestCreatePreferenceWithZeroTotal(t *testing.T) {
gateway := NewMercadoPagoGateway("https://api.mercadopago.com", 2.5)
order := &domain.Order{
ID: uuid.Must(uuid.NewV7()),
TotalCents: 0,
}
pref, err := gateway.CreatePreference(context.Background(), order)
if err != nil {
t.Fatalf("failed to create preference: %v", err)
}
if pref.MarketplaceFee != 0 {
t.Errorf("expected fee 0, got %d", pref.MarketplaceFee)
}
if pref.SellerReceivable != 0 {
t.Errorf("expected seller receivable 0, got %d", pref.SellerReceivable)
}
}
// Stripe Gateway Tests
func TestNewStripeGateway(t *testing.T) {
gateway := NewStripeGateway("sk_test_xxx", 12.0)
if gateway.APIKey != "sk_test_xxx" {
t.Errorf("expected APIKey 'sk_test_xxx', got '%s'", gateway.APIKey)
}
if gateway.MarketplaceCommission != 12.0 {
t.Errorf("expected commission 12.0, got %f", gateway.MarketplaceCommission)
}
}
func TestStripeCreatePreference(t *testing.T) {
gateway := NewStripeGateway("sk_test_xxx", 12.0)
order := &domain.Order{
ID: uuid.Must(uuid.NewV7()),
BuyerID: uuid.Must(uuid.NewV7()),
SellerID: uuid.Must(uuid.NewV7()),
TotalCents: 10000,
}
ctx := context.Background()
pref, err := gateway.CreatePreference(ctx, order)
if err != nil {
t.Fatalf("failed to create preference: %v", err)
}
if pref.Gateway != "stripe" {
t.Errorf("expected gateway 'stripe', got '%s'", pref.Gateway)
}
if pref.MarketplaceFee != 1200 { // 12%
t.Errorf("expected fee 1200, got %d", pref.MarketplaceFee)
}
if pref.SellerReceivable != 8800 {
t.Errorf("expected seller receivable 8800, got %d", pref.SellerReceivable)
}
}
func TestStripeCreatePaymentIntent(t *testing.T) {
gateway := NewStripeGateway("sk_test_xxx", 12.0)
order := &domain.Order{
ID: uuid.Must(uuid.NewV7()),
SellerID: uuid.Must(uuid.NewV7()),
TotalCents: 10000,
}
ctx := context.Background()
intent, err := gateway.CreatePaymentIntent(ctx, order)
if err != nil {
t.Fatalf("failed to create payment intent: %v", err)
}
if intent["currency"] != "brl" {
t.Errorf("expected currency 'brl', got %v", intent["currency"])
}
if intent["amount"].(int64) != 10000 {
t.Errorf("expected amount 10000, got %v", intent["amount"])
}
if intent["application_fee"].(int64) != 1200 {
t.Errorf("expected fee 1200, got %v", intent["application_fee"])
}
}
// Mock Gateway Tests
func TestNewMockGateway(t *testing.T) {
gateway := NewMockGateway(12.0, true)
if gateway.MarketplaceCommission != 12.0 {
t.Errorf("expected commission 12.0, got %f", gateway.MarketplaceCommission)
}
if !gateway.AutoApprove {
t.Error("expected AutoApprove true")
}
}
func TestMockCreatePreference(t *testing.T) {
gateway := NewMockGateway(12.0, true)
order := &domain.Order{
ID: uuid.Must(uuid.NewV7()),
TotalCents: 5000,
}
ctx := context.Background()
pref, err := gateway.CreatePreference(ctx, order)
if err != nil {
t.Fatalf("failed to create preference: %v", err)
}
if pref.Gateway != "mock" {
t.Errorf("expected gateway 'mock', got '%s'", pref.Gateway)
}
if pref.MarketplaceFee != 600 {
t.Errorf("expected fee 600, got %d", pref.MarketplaceFee)
}
}
func TestMockConfirmPayment(t *testing.T) {
gateway := NewMockGateway(12.0, true)
ctx := context.Background()
result, err := gateway.ConfirmPayment(ctx, "mock-payment-123")
if err != nil {
t.Fatalf("failed to confirm payment: %v", err)
}
if result.Status != "approved" {
t.Errorf("expected status 'approved', got '%s'", result.Status)
}
if result.Gateway != "mock" {
t.Errorf("expected gateway 'mock', got '%s'", result.Gateway)
}
}
func TestMockRefundPayment(t *testing.T) {
gateway := NewMockGateway(12.0, true)
ctx := context.Background()
result, err := gateway.RefundPayment(ctx, "mock-payment-123", 5000)
if err != nil {
t.Fatalf("failed to refund payment: %v", err)
}
if result.Status != "refunded" {
t.Errorf("expected status 'refunded', got '%s'", result.Status)
}
if result.AmountCents != 5000 {
t.Errorf("expected amount 5000, got %d", result.AmountCents)
}
}
func TestMockContextCancellation(t *testing.T) {
gateway := NewMockGateway(12.0, true)
order := &domain.Order{
ID: uuid.Must(uuid.NewV7()),
TotalCents: 5000,
}
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, err := gateway.CreatePreference(ctx, order)
if err == nil {
t.Error("expected error for cancelled context")
}
}
func TestStripeContextCancellation(t *testing.T) {
gateway := NewStripeGateway("sk_test_xxx", 12.0)
order := &domain.Order{
ID: uuid.Must(uuid.NewV7()),
TotalCents: 5000,
}
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, err := gateway.CreatePreference(ctx, order)
if err == nil {
t.Error("expected error for cancelled context")
}
}