From 6bb04f6cc6992ad40169ed22d4b19ca9909f4928 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 15 Jan 2020 12:43:27 +0000 Subject: [PATCH] Adapt stripe_sca_spec to actual stripe SCA API --- .../gateways/stripe_payment_intents.rb | 3 + spec/requests/checkout/stripe_sca_spec.rb | 145 +++++++----------- 2 files changed, 62 insertions(+), 86 deletions(-) diff --git a/lib/active_merchant/billing/gateways/stripe_payment_intents.rb b/lib/active_merchant/billing/gateways/stripe_payment_intents.rb index 3326d700c1..9c5c602c7a 100644 --- a/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +++ b/lib/active_merchant/billing/gateways/stripe_payment_intents.rb @@ -140,6 +140,9 @@ module ActiveMerchant #:nodoc: post[:email] = options[:email] if options[:email] customer = commit(:post, 'customers', post, options) customer_id = customer.params['id'] + + # return the stripe response if expected customer id is not present + return customer if customer_id.nil? end commit(:post, "payment_methods/#{params[:payment_method]}/attach", diff --git a/spec/requests/checkout/stripe_sca_spec.rb b/spec/requests/checkout/stripe_sca_spec.rb index f86568b5b4..33bf6fba27 100644 --- a/spec/requests/checkout/stripe_sca_spec.rb +++ b/spec/requests/checkout/stripe_sca_spec.rb @@ -29,15 +29,14 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques let!(:line_item) { create(:line_item, price: 12.34) } let!(:order) { line_item.order } let(:address) { create(:address) } - let(:token) { "token123" } - let(:new_token) { "newtoken123" } - let(:card_id) { "card_XyZ456" } + let(:stripe_payment_method) { "pm_123" } + let(:new_stripe_payment_method) { "new_pm_123" } let(:customer_id) { "cus_A123" } let(:payments_attributes) do { payment_method_id: payment_method.id, source_attributes: { - gateway_payment_profile_id: token, + gateway_payment_profile_id: stripe_payment_method, cc_type: "visa", last_digits: "4242", month: 10, @@ -70,6 +69,9 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques } } end + let(:payment_intent_response_mock) do + { status: 200, body: JSON.generate(object: "payment_intent", amount: 2000, charges: { data: [{ id: "ch_1234", amount: 2000 }]}) } + end before do order_cycle_distributed_variants = double(:order_cycle_distributed_variants) @@ -83,32 +85,15 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques end context "when a new card is submitted" do - let(:store_response_mock) do - { - status: 200, - body: JSON.generate( - id: customer_id, - default_card: card_id, - sources: { data: [{ id: "1" }] } - ) - } - end - let(:token_response_mock) do - { status: 200, body: JSON.generate(id: new_token) } - end - let(:charge_response_mock) do - { status: 200, body: JSON.generate(id: "ch_1234", object: "charge", amount: 2000) } - end - context "and the user doesn't request that the card is saved for later" do before do # Charges the card stub_request(:post, "https://api.stripe.com/v1/payment_intents") - .with(basic_auth: ["sk_test_12345", ""], body: /#{token}.*#{order.number}/) - .to_return(charge_response_mock) + .with(basic_auth: ["sk_test_12345", ""], body: /#{stripe_payment_method}.*#{order.number}/) + .to_return(payment_intent_response_mock) end - context "and the charge request is successful" do + context "and the paymeent intent request is successful" do it "should process the payment without storing card details" do put update_checkout_path, params @@ -118,7 +103,7 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques card = order.payments.completed.first.source expect(card.gateway_customer_profile_id).to eq nil - expect(card.gateway_payment_profile_id).to eq token + expect(card.gateway_payment_profile_id).to eq stripe_payment_method expect(card.cc_type).to eq "visa" expect(card.last_digits).to eq "4242" expect(card.first_name).to eq "Jill" @@ -126,9 +111,9 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques end end - context "when the charge request returns an error message" do - let(:charge_response_mock) do - { status: 402, body: JSON.generate(error: { message: "charge-failure" }) } + context "when the payment intent request returns an error message" do + let(:payment_intent_response_mock) do + { status: 402, body: JSON.generate(error: { message: "payment-intent-failure" }) } end it "should not process the payment" do @@ -136,36 +121,50 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques expect(response.status).to be 400 - expect(json_response["flash"]["error"]).to eq "charge-failure" + expect(json_response["flash"]["error"]).to eq "payment-intent-failure" expect(order.payments.completed.count).to be 0 end end end context "and the customer requests that the card is saved for later" do + let(:payment_method_response_mock) do + { + status: 200, + body: JSON.generate(id: new_stripe_payment_method, customer: customer_id) + } + end + + let(:customer_response_mock) do + { + status: 200, + body: JSON.generate(id: customer_id, sources: { data: [{ id: "1" }] }) + } + end + before do source_attributes = params[:order][:payments_attributes][0][:source_attributes] source_attributes[:save_requested_by_customer] = '1' # Saves the card against the user stub_request(:post, "https://api.stripe.com/v1/customers") - .with(basic_auth: ["sk_test_12345", ""], body: { card: token, email: order.email }) - .to_return(store_response_mock) + .with(basic_auth: ["sk_test_12345", ""], body: { email: order.email }) + .to_return(customer_response_mock) - # Requests a token from the newly saved card - stub_request(:post, "https://api.stripe.com/v1/tokens") - .with(body: { card: card_id, customer: customer_id }) - .to_return(token_response_mock) + # Requests a payment method from the newly saved card + stub_request(:post, "https://api.stripe.com/v1/payment_methods/#{stripe_payment_method}/attach") + .with(body: { customer: customer_id }) + .to_return(payment_method_response_mock) # Charges the card stub_request(:post, "https://api.stripe.com/v1/payment_intents") .with( basic_auth: ["sk_test_12345", ""], - body: /#{token}.*#{order.number}/ - ).to_return(charge_response_mock) + body: /.*#{order.number}/ + ).to_return(payment_intent_response_mock) end - context "and the store, token and charge requests are successful" do + context "and the customer, payment_method and payment_intent requests are successful" do it "should process the payment, and stores the card/customer details" do put update_checkout_path, params @@ -175,7 +174,7 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques card = order.payments.completed.first.source expect(card.gateway_customer_profile_id).to eq customer_id - expect(card.gateway_payment_profile_id).to eq card_id + expect(card.gateway_payment_profile_id).to eq new_stripe_payment_method expect(card.cc_type).to eq "visa" expect(card.last_digits).to eq "4242" expect(card.first_name).to eq "Jill" @@ -183,9 +182,9 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques end end - context "when the store request returns an error message" do - let(:store_response_mock) do - { status: 402, body: JSON.generate(error: { message: "store-failure" }) } + context "when the customer request returns an error message" do + let(:customer_response_mock) do + { status: 402, body: JSON.generate(error: { message: "customer-store-failure" }) } end it "should not process the payment" do @@ -194,14 +193,14 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques expect(response.status).to be 400 expect(json_response["flash"]["error"]) - .to eq(I18n.t(:spree_gateway_error_flash_for_checkout, error: 'store-failure')) + .to eq(I18n.t(:spree_gateway_error_flash_for_checkout, error: 'customer-store-failure')) expect(order.payments.completed.count).to be 0 end end - context "when the charge request returns an error message" do - let(:charge_response_mock) do - { status: 402, body: JSON.generate(error: { message: "charge-failure" }) } + context "when the payment intent request returns an error message" do + let(:payment_intent_response_mock) do + { status: 402, body: JSON.generate(error: { message: "payment-intent-failure" }) } end it "should not process the payment" do @@ -209,23 +208,22 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques expect(response.status).to be 400 - expect(json_response["flash"]["error"]).to eq "charge-failure" + expect(json_response["flash"]["error"]).to eq "payment-intent-failure" expect(order.payments.completed.count).to be 0 end end - context "when the token request returns an error message" do - let(:token_response_mock) do - { status: 402, body: JSON.generate(error: { message: "token-failure" }) } + context "when the payment_metho request returns an error message" do + let(:payment_method_response_mock) do + { status: 402, body: JSON.generate(error: { message: "payment-method-failure" }) } end - # Note, no requests have been stubbed it "should not process the payment" do put update_checkout_path, params expect(response.status).to be 400 - expect(json_response["flash"]["error"]).to eq "token-failure" + expect(json_response["flash"]["error"]).to include "payment-method-failure" expect(order.payments.completed.count).to be 0 end end @@ -237,7 +235,7 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques create( :credit_card, user_id: order.user_id, - gateway_payment_profile_id: card_id, + gateway_payment_profile_id: stripe_payment_method, gateway_customer_profile_id: customer_id, last_digits: "4321", cc_type: "master", @@ -247,27 +245,17 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques ) end - let(:token_response_mock) { { status: 200, body: JSON.generate(id: new_token) } } - let(:charge_response_mock) do - { status: 200, body: JSON.generate(id: "ch_1234", object: "charge", amount: 2000) } - end - before do params[:order][:existing_card_id] = credit_card.id quick_login_as(order.user) - # Requests a token - #stub_request(:post, "https://api.stripe.com/v1/tokens") - # .with(body: { "card" => card_id, "customer" => customer_id }) - # .to_return(token_response_mock) - # Charges the card stub_request(:post, "https://api.stripe.com/v1/payment_intents") - .with(basic_auth: ["sk_test_12345", ""], body: %r{.*#{customer_id}.*#{order.number}.*#{card_id}.*}) - .to_return(charge_response_mock) + .with(basic_auth: ["sk_test_12345", ""], body: %r{#{customer_id}.*#{stripe_payment_method}}) + .to_return(payment_intent_response_mock) end - context "and the charge and token requests are accepted" do + context "and the payment intent and payment method requests are accepted" do it "should process the payment, and keep the profile ids and other card details" do put update_checkout_path, params @@ -277,7 +265,7 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques card = order.payments.completed.first.source expect(card.gateway_customer_profile_id).to eq customer_id - expect(card.gateway_payment_profile_id).to eq card_id + expect(card.gateway_payment_profile_id).to eq stripe_payment_method expect(card.cc_type).to eq "master" expect(card.last_digits).to eq "4321" expect(card.first_name).to eq "Sammy" @@ -285,9 +273,9 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques end end - context "when the charge request returns an error message" do - let(:charge_response_mock) do - { status: 402, body: JSON.generate(error: { message: "charge-failure" }) } + context "when the payment intent request returns an error message" do + let(:payment_intent_response_mock) do + { status: 402, body: JSON.generate(error: { message: "payment-intent-failure" }) } end it "should not process the payment" do @@ -295,22 +283,7 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques expect(response.status).to be 400 - expect(json_response["flash"]["error"]).to eq "charge-failure" - expect(order.payments.completed.count).to be 0 - end - end - - context "when the token request returns an error message" do - let(:token_response_mock) do - { status: 402, body: JSON.generate(error: { message: "token-error" }) } - end - - it "should not process the payment" do - put update_checkout_path, params - - expect(response.status).to be 400 - - expect(json_response["flash"]["error"]).to eq "token-error" + expect(json_response["flash"]["error"]).to eq "payment-intent-failure" expect(order.payments.completed.count).to be 0 end end