diff --git a/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb b/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb index 6216228619..594b9e2dbb 100644 --- a/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb +++ b/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe Spree::Admin::PaymentsController, type: :controller do + include StripeHelper + let!(:shop) { create(:enterprise) } let!(:user) { shop.owner } let!(:order) { create(:order, distributor: shop, state: 'complete') } @@ -152,19 +154,13 @@ describe Spree::Admin::PaymentsController, type: :controller do allow(Stripe).to receive(:api_key) { "sk_test_12345" } allow(StripeAccount).to receive(:find_by) { stripe_account } - # Retrieves payment intent info - stub_request(:get, "https://api.stripe.com/v1/payment_intents/pi_123") - .with(headers: { 'Stripe-Account' => 'abc123' }) - .to_return({ status: 200, body: JSON.generate( - amount_received: 2000, - charges: { data: [{ id: "ch_1a2b3c" }] } - ) }) + stub_payment_intent_get_request end context "where the request succeeds" do before do # Issues the refund - stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1234/refunds"). with(basic_auth: ["sk_test_12345", ""]). to_return(status: 200, body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') ) @@ -184,7 +180,7 @@ describe Spree::Admin::PaymentsController, type: :controller do context "where the request fails" do before do - stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1234/refunds"). with(basic_auth: ["sk_test_12345", ""]). to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) ) end @@ -220,17 +216,12 @@ describe Spree::Admin::PaymentsController, type: :controller do before do allow(Stripe).to receive(:api_key) { "sk_test_12345" } - # Retrieves payment intent info - stub_request(:get, "https://api.stripe.com/v1/payment_intents/pi_123") - .to_return({ status: 200, body: JSON.generate( - amount_received: 2000, - charges: { data: [{ id: "ch_1a2b3c" }] } - ) }) + stub_payment_intent_get_request stripe_account_header: false end context "where the request succeeds" do before do - stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1234/refunds"). with(basic_auth: ["sk_test_12345", ""]). to_return(status: 200, body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') ) @@ -250,7 +241,7 @@ describe Spree::Admin::PaymentsController, type: :controller do context "where the request fails" do before do - stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1234/refunds"). with(basic_auth: ["sk_test_12345", ""]). to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) ) end diff --git a/spec/features/consumer/shopping/checkout_stripe_spec.rb b/spec/features/consumer/shopping/checkout_stripe_spec.rb index e9b5e65230..40543e164f 100644 --- a/spec/features/consumer/shopping/checkout_stripe_spec.rb +++ b/spec/features/consumer/shopping/checkout_stripe_spec.rb @@ -90,31 +90,21 @@ feature "Check out with Stripe", js: true do let!(:shipping_method) { create(:shipping_method) } context "with guest checkout" do + before do + stub_payment_intent_get_request + stub_hub_payment_methods_request + end + 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 it "completes checkout successfully" do - visit checkout_path - - checkout_as_guest - - fill_out_form( - free_shipping.name, - stripe_sca_payment_method.name, - save_default_addresses: false - ) - - fill_out_card_details - - place_order + checkout_with_stripe expect(page).to have_content "Confirmed" - expect(order.reload.completed?).to eq true expect(order.payments.first.state).to eq "completed" end @@ -125,32 +115,72 @@ feature "Check out with Stripe", js: true do 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 - ) - - fill_out_card_details - - place_order + checkout_with_stripe expect(page).to have_content error_message - expect(order.reload.state).to eq "cart" expect(order.payments.first.state).to eq "failed" end end + + context "when the card needs extra SCA authorization", js: true do + let(:stripe_redirect_url) { checkout_path(payment_intent: "pi_123") } + let(:payment_intent_authorize_response) do + { status: 200, body: JSON.generate(id: "pi_123", + object: "payment_intent", + next_source_action: { + type: "authorize_with_url", + authorize_with_url: { url: stripe_redirect_url } + }, + status: "requires_source_action") } + end + + before do + stub_request(:post, "https://api.stripe.com/v1/payment_intents") + .with(basic_auth: ["sk_test_12345", ""], body: /.*#{order.number}/) + .to_return(payment_intent_authorize_response) + end + + describe "and the authorization succeeds" do + before do + stub_successful_capture_request order: order + end + + it "completes checkout successfully" do + checkout_with_stripe + + # We make stripe return stripe_redirect_url (which is already sending the user back to the checkout) as if the authorization was done + # We can then control the actual authorization or failure of the payment through the mock stub_successful_capture_request + + expect(page).to have_content "Confirmed" + expect(order.reload.completed?).to eq true + expect(order.payments.first.state).to eq "completed" + end + end + + describe "and the authorization fails" do + let(:error_message) { "Card was declined: insufficient funds." } + + before do + stub_failed_capture_request order: order, response: { message: error_message } + end + + it "shows an error message from the Stripe response" do + checkout_with_stripe + + # We make stripe return stripe_redirect_url (which is already sending the user back to the checkout) as if the authorization was done + # We can then control the actual authorization or failure of the payment through the mock stub_failed_capture_request + + 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 end end diff --git a/spec/support/request/stripe_helper.rb b/spec/support/request/stripe_helper.rb index ce981a06dc..120b5c8bfc 100644 --- a/spec/support/request/stripe_helper.rb +++ b/spec/support/request/stripe_helper.rb @@ -1,6 +1,19 @@ # frozen_string_literal: true module StripeHelper + def checkout_with_stripe + visit checkout_path + checkout_as_guest + + fill_out_form( + free_shipping.name, + stripe_sca_payment_method.name, + save_default_addresses: false + ) + fill_out_card_details + place_order + end + def fill_out_card_details expect(page).to have_css("input[name='cardnumber']") fill_in 'Card number', with: '4242424242424242' @@ -20,10 +33,10 @@ module StripeHelper .to_return(payment_intent_authorize_response_mock(response)) end - def stub_payment_intent_get_request(response: {}) - stub_request(:get, "https://api.stripe.com/v1/payment_intents/pi_123") - .with(headers: { 'Stripe-Account' => 'abc123' }) - .to_return(payment_intent_authorize_response_mock(response)) + def stub_payment_intent_get_request(response: {}, stripe_account_header: true) + stub = stub_request(:get, "https://api.stripe.com/v1/payment_intents/pi_123") + stub = stub.with(headers: { 'Stripe-Account' => 'abc123' }) if stripe_account_header + stub.to_return(payment_intent_authorize_response_mock(response)) end def stub_hub_payment_methods_request(response: {}) @@ -55,6 +68,7 @@ module StripeHelper body: JSON.generate(id: "pi_123", object: "payment_intent", amount: 2000, + amount_received: 2000, status: options[:intent_status] || "requires_capture", last_payment_error: nil, charges: { data: [{ id: "ch_1234", amount: 2000 }] }) }