diff --git a/spec/features/consumer/shopping/checkout_stripe_spec.rb b/spec/features/consumer/shopping/checkout_stripe_spec.rb index 49c9c27e4a..09d0444029 100644 --- a/spec/features/consumer/shopping/checkout_stripe_spec.rb +++ b/spec/features/consumer/shopping/checkout_stripe_spec.rb @@ -89,37 +89,75 @@ feature "Check out with Stripe", js: true do } let!(:shipping_method) { create(:shipping_method) } - before do - stub_payment_intents_post_request order: order - stub_payment_intent_get_request - stub_hub_payment_methods_request - stub_payment_intent_capture_request order: order - end - context "with guest checkout" do - it "completes checkout successfully" do - visit checkout_path + context "when the card is accepted" do + before do + stub_payment_intents_post_request order: order + stub_payment_intent_get_request + stub_hub_payment_methods_request + stub_successful_capture_request order: order + end - checkout_as_guest + it "completes checkout successfully" do + visit checkout_path - fill_out_form( - free_shipping.name, - stripe_sca_payment_method.name, - save_default_addresses: false - ) + checkout_as_guest - expect(page).to have_css("input[name='cardnumber']") + fill_out_form( + free_shipping.name, + stripe_sca_payment_method.name, + save_default_addresses: false + ) - fill_in 'Card number', with: '4242424242424242' - fill_in 'MM / YY', with: "01/#{DateTime.now.year + 1}" - fill_in 'CVC', with: '123' + expect(page).to have_css("input[name='cardnumber']") - place_order + fill_in 'Card number', with: '4242424242424242' + fill_in 'MM / YY', with: "01/#{DateTime.now.year + 1}" + fill_in 'CVC', with: '123' - expect(page).to have_content "Confirmed" + place_order - expect(order.reload.completed?).to eq true - expect(order.payments.first.state).to eq "completed" + expect(page).to have_content "Confirmed" + + expect(order.reload.completed?).to eq true + expect(order.payments.first.state).to eq "completed" + end + end + + context "when the card is rejected" do + let(:error_message) { "Card was declined: insufficient funds." } + + before do + stub_payment_intents_post_request order: order + stub_payment_intent_get_request + stub_hub_payment_methods_request + stub_failed_capture_request order: order, response: { message: error_message } + end + + it "shows an error message from the Stripe response" do + visit checkout_path + + checkout_as_guest + + fill_out_form( + free_shipping.name, + stripe_sca_payment_method.name, + save_default_addresses: false + ) + + expect(page).to have_css("input[name='cardnumber']") + + fill_in 'Card number', with: '4242424242424242' + fill_in 'MM / YY', with: "01/#{DateTime.now.year + 1}" + fill_in 'CVC', with: '123' + + place_order + + expect(page).to have_content error_message + + expect(order.reload.state).to eq "cart" + expect(order.payments.first.state).to eq "failed" + end end end end diff --git a/spec/support/request/stripe_helper.rb b/spec/support/request/stripe_helper.rb index 48463283d5..82b858a3da 100644 --- a/spec/support/request/stripe_helper.rb +++ b/spec/support/request/stripe_helper.rb @@ -26,11 +26,18 @@ module StripeHelper .to_return(hub_payment_method_response_mock(response)) end - def stub_payment_intent_capture_request(order:, response: {}) + def stub_successful_capture_request(order:, response: {}) stub_request(:post, "https://api.stripe.com/v1/payment_intents/pi_123/capture") .with(body: { amount_to_capture: Spree::Money.new(order.total).cents }, headers: { 'Stripe-Account' => 'abc123' }) - .to_return(payment_intent_response_mock(response)) + .to_return(payment_successful_capture_mock(response)) + end + + def stub_failed_capture_request(order:, response: {}) + stub_request(:post, "https://api.stripe.com/v1/payment_intents/pi_123/capture") + .with(body: { amount_to_capture: Spree::Money.new(order.total).cents }, + headers: { 'Stripe-Account' => 'abc123' }) + .to_return(payment_failed_capture_mock(response)) end private @@ -45,13 +52,19 @@ module StripeHelper charges: { data: [{ id: "ch_1234", amount: 2000 }] }) } end - def payment_intent_response_mock(options) + def payment_successful_capture_mock(options) { status: options[:code] || 200, body: JSON.generate(object: "payment_intent", amount: 2000, charges: { data: [{ id: "ch_1234", amount: 2000 }] }) } end + def payment_failed_capture_mock(options) + { status: options[:code] || 402, + body: JSON.generate(error: { message: + options[:message] || "payment-method-failure" }) } + end + def hub_payment_method_response_mock(options) { status: options[:code] || 200, body: JSON.generate(id: "pm_456", customer: "cus_A123") }