flamingo.me/flamingo-commerce/v3@v3.11.0/checkout/domain/placeorder/states/create_payment_test.go (about)

     1  package states_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net/url"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/mock"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	cartDomain "flamingo.me/flamingo-commerce/v3/cart/domain/cart"
    14  	"flamingo.me/flamingo-commerce/v3/cart/domain/placeorder"
    15  	"flamingo.me/flamingo-commerce/v3/checkout/domain/placeorder/process"
    16  	"flamingo.me/flamingo-commerce/v3/checkout/domain/placeorder/states"
    17  	"flamingo.me/flamingo-commerce/v3/payment/application"
    18  	"flamingo.me/flamingo-commerce/v3/payment/domain"
    19  	"flamingo.me/flamingo-commerce/v3/payment/interfaces"
    20  	"flamingo.me/flamingo-commerce/v3/payment/interfaces/mocks"
    21  	price "flamingo.me/flamingo-commerce/v3/price/domain"
    22  )
    23  
    24  type rawTransactionData struct{}
    25  
    26  func TestCreatePayment_Run(t *testing.T) {
    27  	t.Run("happy path", func(t *testing.T) {
    28  		factory := provideProcessFactory(t)
    29  
    30  		cart := provideCartWithPaymentSelection(t)
    31  		p, _ := factory.New(&url.URL{}, cart)
    32  
    33  		state := states.CreatePayment{}
    34  
    35  		expectedPayment := &placeorder.Payment{Gateway: "test", RawTransactionData: &rawTransactionData{}}
    36  		gateway := mocks.NewWebCartPaymentGateway(t)
    37  		gateway.EXPECT().StartFlow(mock.Anything, mock.Anything, p.Context().UUID, p.Context().ReturnURL).Return(&domain.FlowResult{EarlyPlaceOrder: true}, nil).Once()
    38  		gateway.EXPECT().OrderPaymentFromFlow(mock.Anything, mock.Anything, p.Context().UUID).Return(expectedPayment, nil).Once()
    39  		paymentService := paymentServiceHelper(t, gateway)
    40  
    41  		state.Inject(paymentService)
    42  
    43  		expectedResult := process.RunResult{
    44  			RollbackData: states.CreatePaymentRollbackData{
    45  				Gateway:            expectedPayment.Gateway,
    46  				PaymentID:          expectedPayment.PaymentID,
    47  				RawTransactionData: &rawTransactionData{},
    48  			},
    49  		}
    50  		result := state.Run(context.Background(), p)
    51  		assert.Equal(t, result, expectedResult)
    52  		assert.Equal(t, p.Context().CurrentStateName, states.CompleteCart{}.Name())
    53  		gateway.AssertExpectations(t)
    54  	})
    55  
    56  	t.Run("error missing payment selection", func(t *testing.T) {
    57  		factory := provideProcessFactory(t)
    58  
    59  		cart := cartDomain.Cart{}
    60  
    61  		p, _ := factory.New(&url.URL{}, cart)
    62  
    63  		state := states.CreatePayment{}
    64  
    65  		paymentService := paymentServiceHelper(t, nil)
    66  
    67  		state.Inject(paymentService)
    68  
    69  		result := state.Run(context.Background(), p)
    70  		assert.NotNil(t, result.Failed, "Missing PaymentSelection in cart should lead to an error")
    71  	})
    72  
    73  	t.Run("error during gateway.StartFlow", func(t *testing.T) {
    74  		factory := provideProcessFactory(t)
    75  
    76  		cart := provideCartWithPaymentSelection(t)
    77  
    78  		p, _ := factory.New(&url.URL{}, cart)
    79  
    80  		state := states.CreatePayment{}
    81  
    82  		expectedError := errors.New("StartFlow payment error")
    83  
    84  		gateway := mocks.NewWebCartPaymentGateway(t)
    85  		gateway.EXPECT().StartFlow(mock.Anything, mock.Anything, p.Context().UUID, p.Context().ReturnURL).Return(nil, expectedError).Once()
    86  		paymentService := paymentServiceHelper(t, gateway)
    87  		state.Inject(paymentService)
    88  
    89  		expectedResult := process.RunResult{
    90  			Failed: process.PaymentErrorOccurredReason{Error: expectedError.Error()},
    91  		}
    92  		assert.Equal(t, state.Run(context.Background(), p), expectedResult)
    93  		gateway.AssertExpectations(t)
    94  	})
    95  
    96  	t.Run("error during gateway.OrderPaymentFromFlow", func(t *testing.T) {
    97  		factory := provideProcessFactory(t)
    98  
    99  		cart := provideCartWithPaymentSelection(t)
   100  
   101  		p, _ := factory.New(&url.URL{}, cart)
   102  
   103  		state := states.CreatePayment{}
   104  
   105  		expectedError := errors.New("OrderPaymentFromFlow payment error")
   106  
   107  		gateway := mocks.NewWebCartPaymentGateway(t)
   108  		gateway.EXPECT().StartFlow(mock.Anything, mock.Anything, p.Context().UUID, p.Context().ReturnURL).Return(&domain.FlowResult{}, nil).Once()
   109  		gateway.EXPECT().OrderPaymentFromFlow(mock.Anything, mock.Anything, p.Context().UUID).Return(nil, expectedError).Once()
   110  
   111  		paymentService := paymentServiceHelper(t, gateway)
   112  		state.Inject(paymentService)
   113  
   114  		expectedResult := process.RunResult{
   115  			Failed: process.PaymentErrorOccurredReason{Error: expectedError.Error()},
   116  		}
   117  		assert.Equal(t, state.Run(context.Background(), p), expectedResult)
   118  		gateway.AssertExpectations(t)
   119  	})
   120  }
   121  
   122  func provideProcessFactory(t *testing.T) *process.Factory {
   123  	t.Helper()
   124  	factory := &process.Factory{}
   125  	factory.Inject(
   126  		func() *process.Process {
   127  			return &process.Process{}
   128  		},
   129  		&struct {
   130  			StartState  process.State `inject:"startState"`
   131  			FailedState process.State `inject:"failedState"`
   132  		}{
   133  			StartState: &states.New{},
   134  		},
   135  	)
   136  	return factory
   137  }
   138  
   139  func provideCartWithPaymentSelection(t *testing.T) cartDomain.Cart {
   140  	t.Helper()
   141  	cart := cartDomain.Cart{}
   142  	paymentSelection, err := cartDomain.NewDefaultPaymentSelection("test", map[string]string{price.ChargeTypeMain: "main"}, cart)
   143  	require.NoError(t, err)
   144  	cart.PaymentSelection = paymentSelection
   145  	return cart
   146  }
   147  
   148  func paymentServiceHelper(t *testing.T, gateway interfaces.WebCartPaymentGateway) *application.PaymentService {
   149  	t.Helper()
   150  	paymentService := &application.PaymentService{}
   151  
   152  	paymentService.Inject(func() map[string]interfaces.WebCartPaymentGateway {
   153  		return map[string]interfaces.WebCartPaymentGateway{
   154  			"test": gateway,
   155  		}
   156  	})
   157  	return paymentService
   158  }
   159  
   160  func TestCreatePayment_IsFinal(t *testing.T) {
   161  	state := states.CreatePayment{}
   162  	assert.False(t, state.IsFinal())
   163  }
   164  
   165  func TestCreatePayment_Rollback(t *testing.T) {
   166  	t.Run("happy path", func(t *testing.T) {
   167  		state := states.CreatePayment{}
   168  
   169  		var data interface{}
   170  
   171  		payment := &placeorder.Payment{
   172  			Gateway:            "test",
   173  			Transactions:       nil,
   174  			RawTransactionData: &rawTransactionData{},
   175  			PaymentID:          "1234",
   176  		}
   177  
   178  		data = states.CreatePaymentRollbackData{
   179  			Gateway:            payment.Gateway,
   180  			PaymentID:          payment.PaymentID,
   181  			RawTransactionData: payment.RawTransactionData,
   182  		}
   183  
   184  		gateway := mocks.NewWebCartPaymentGateway(t)
   185  		gateway.EXPECT().CancelOrderPayment(mock.Anything, payment).Return(nil).Once()
   186  		paymentService := paymentServiceHelper(t, gateway)
   187  		state.Inject(paymentService)
   188  
   189  		result := state.Rollback(context.Background(), data)
   190  		assert.Nil(t, result)
   191  		gateway.AssertExpectations(t)
   192  	})
   193  
   194  	t.Run("RollbackData not of type", func(t *testing.T) {
   195  		state := states.CreatePayment{}
   196  
   197  		assert.Error(t, state.Rollback(context.Background(), "string"))
   198  	})
   199  
   200  	t.Run("Error during payment selection", func(t *testing.T) {
   201  		state := states.CreatePayment{}
   202  
   203  		var data interface{}
   204  
   205  		payment := &placeorder.Payment{
   206  			Gateway:            "non-existing",
   207  			RawTransactionData: &rawTransactionData{},
   208  		}
   209  
   210  		data = states.CreatePaymentRollbackData{
   211  			Gateway: payment.Gateway, PaymentID: payment.PaymentID, RawTransactionData: payment.RawTransactionData}
   212  
   213  		paymentService := paymentServiceHelper(t, nil)
   214  		state.Inject(paymentService)
   215  		assert.Error(t, state.Rollback(context.Background(), data), "Missing payment selection / gateway should lead to an error")
   216  	})
   217  
   218  	t.Run("Error during CancelOrderPayment", func(t *testing.T) {
   219  		state := states.CreatePayment{}
   220  
   221  		var data interface{}
   222  
   223  		payment := &placeorder.Payment{
   224  			Gateway:            "test",
   225  			Transactions:       nil,
   226  			RawTransactionData: &rawTransactionData{},
   227  			PaymentID:          "1234",
   228  		}
   229  
   230  		data = states.CreatePaymentRollbackData{
   231  			Gateway:            payment.Gateway,
   232  			PaymentID:          payment.PaymentID,
   233  			RawTransactionData: payment.RawTransactionData,
   234  		}
   235  
   236  		expectedError := errors.New("generic payment error")
   237  		gateway := mocks.NewWebCartPaymentGateway(t)
   238  		gateway.EXPECT().CancelOrderPayment(mock.Anything, payment).Return(expectedError).Once()
   239  		paymentService := paymentServiceHelper(t, gateway)
   240  		state.Inject(paymentService)
   241  		assert.EqualError(t, state.Rollback(context.Background(), data), expectedError.Error())
   242  		gateway.AssertExpectations(t)
   243  	})
   244  
   245  }