From 5a70664a6a808cb9d1d7ef39b368bc383d412595 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Mon, 27 Dec 2021 19:01:39 +0000 Subject: [PATCH] Pull stripe-related tests into new controller spec --- spec/controllers/checkout_controller_spec.rb | 123 +------------- .../stripe_controller_spec.rb | 155 ++++++++++++++++++ 2 files changed, 157 insertions(+), 121 deletions(-) create mode 100644 spec/controllers/payment_gateways/stripe_controller_spec.rb diff --git a/spec/controllers/checkout_controller_spec.rb b/spec/controllers/checkout_controller_spec.rb index c1f3d900b9..844ffac75e 100644 --- a/spec/controllers/checkout_controller_spec.rb +++ b/spec/controllers/checkout_controller_spec.rb @@ -79,7 +79,7 @@ describe CheckoutController, type: :controller do end end - describe "redirection to cart and stripe" do + describe "running out of stock" do let(:order_cycle_distributed_variants) { double(:order_cycle_distributed_variants) } before do @@ -90,7 +90,7 @@ describe CheckoutController, type: :controller do allow(OrderCycleDistributedVariants).to receive(:new).and_return(order_cycle_distributed_variants) end - context "running out of stock" do + context "handling stock issues" do it "redirects when some items are out of stock" do allow(order).to receive_message_chain(:insufficient_stock_lines, :empty?).and_return false @@ -105,125 +105,6 @@ describe CheckoutController, type: :controller do get :edit expect(response).to redirect_to cart_path end - - context "after redirecting back from Stripe" do - let(:order) { create(:order_with_totals_and_distribution) } - let!(:payment) { create(:payment, state: "pending", amount: order.total, order: order) } - let!(:transaction_fee) { - create(:adjustment, state: "open", amount: 10, order: order, adjustable: payment) - } - - before do - allow(order).to receive_message_chain(:insufficient_stock_lines, :empty?).and_return(false) - allow(order_cycle_distributed_variants).to receive(:distributes_order_variants?). - with(order).and_return(true) - allow(controller).to receive(:valid_payment_intent_provided?) { true } - order.save - allow(order).to receive_message_chain(:payments, :completed) { [] } - allow(order).to receive_message_chain(:payments, :incomplete) { [payment] } - allow(payment).to receive(:adjustment) { transaction_fee } - end - - it "cancels the payment and resets the order to cart" do - expect(payment).to receive(:void_transaction!).and_call_original - - spree_post :edit - - expect(response).to redirect_to cart_path - expect(flash[:notice]).to eq I18n.t('checkout.payment_cancelled_due_to_stock') - - expect(order.state).to eq "cart" - expect(payment.state).to eq "void" - expect(transaction_fee.reload.eligible).to eq false - expect(transaction_fee.state).to eq "finalized" - end - end - end - - describe "when items are available and in stock" do - before do - allow(order).to receive_message_chain(:insufficient_stock_lines, :empty?).and_return true - end - - describe "order variants are distributed in the OC" do - before do - expect(order_cycle_distributed_variants).to receive(:distributes_order_variants?).with(order).and_return(true) - end - - it "does not redirect" do - get :edit - expect(response.status).to eq 200 - end - - it "returns a specific flash message when Spree::Core::GatewayError occurs" do - order_checkout_restart = double(:order_checkout_restart) - allow(OrderCheckoutRestart).to receive(:new) { order_checkout_restart } - call_count = 0 - allow(order_checkout_restart).to receive(:call) do - call_count += 1 - raise Spree::Core::GatewayError, "Gateway blow up" if call_count == 1 - end - - spree_post :edit - - expect(response.status).to eq(200) - flash_message = I18n.t(:spree_gateway_error_flash_for_checkout, error: "Gateway blow up") - expect(flash[:error]).to eq flash_message - end - end - - describe "when the order is in payment state and a stripe payment intent is provided" do - let(:user) { order.user } - let(:order) { create(:order_with_totals) } - let(:payment_method) { create(:stripe_sca_payment_method) } - let(:payment) { - create( - :payment, - amount: order.total, - state: "requires_authorization", - payment_method: payment_method, - response_code: "pi_123" - ) - } - - before do - Stripe.api_key = "sk_test_12345" - stub_payment_intent_get_request - stub_successful_capture_request(order: order) - - allow(controller).to receive(:spree_current_user).and_return(user) - user.bill_address = create(:address) - user.ship_address = create(:address) - user.save! - - order.update_attribute :state, "payment" - order.payments << payment - - # this is called a 2nd time after order completion from the reset_order_service - expect(order_cycle_distributed_variants).to receive(:distributes_order_variants?).twice.and_return(true) - end - - it "completes the order and redirects to the order confirmation page" do - get :edit, params: { payment_intent: "pi_123" } - expect(order.completed?).to be true - expect(response).to redirect_to order_path(order) - end - - it "does not attempt to load different addresses" do - expect(OpenFoodNetwork::AddressFinder).to_not receive(:new) - - get :edit, params: { payment_intent: "pi_123" } - end - - it "creates a customer record" do - order.update_columns(customer_id: nil) - Customer.delete_all - - expect { - get :edit, params: { payment_intent: "pi_123" } - }.to change { Customer.count }.by(1) - end - end end end diff --git a/spec/controllers/payment_gateways/stripe_controller_spec.rb b/spec/controllers/payment_gateways/stripe_controller_spec.rb new file mode 100644 index 0000000000..81eaa2ed30 --- /dev/null +++ b/spec/controllers/payment_gateways/stripe_controller_spec.rb @@ -0,0 +1,155 @@ +# frozen_string_literal: true + +require 'spec_helper' + +module PaymentGateways + describe StripeController, type: :controller do + include StripeStubs + + let!(:distributor) { create(:distributor_enterprise, with_payment_and_shipping: true) } + let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor]) } + let!(:order) { create(:order_with_totals, distributor: distributor, order_cycle: order_cycle) } + let(:exchange) { order_cycle.exchanges.to_enterprises(distributor).outgoing.first } + + let(:order_cycle_distributed_variants) { instance_double(OrderCycleDistributedVariants) } + + before do + exchange.variants << order.line_items.first.variant + allow(controller).to receive(:current_order).and_return(order) + end + + describe "#confirm" do + context "when the order is in payment state and a stripe payment intent is provided" do + let(:user) { order.user } + let(:payment_method) { create(:stripe_sca_payment_method) } + let(:payment) { + create( + :payment, + amount: order.total, + state: "requires_authorization", + payment_method: payment_method, + response_code: "pi_123" + ) + } + + before do + Stripe.api_key = "sk_test_12345" + stub_payment_intent_get_request + stub_successful_capture_request(order: order) + + allow(controller).to receive(:spree_current_user).and_return(user) + user.bill_address = create(:address) + user.ship_address = create(:address) + user.save! + + order.update_attribute :state, "payment" + order.payments << payment + end + + it "completes the order and redirects to the order confirmation page" do + expect(controller).to receive(:processing_succeeded).and_call_original + expect(controller).to receive(:order_completion_reset).and_call_original + + get :confirm, params: { payment_intent: "pi_123" } + + expect(order.completed?).to be true + expect(response).to redirect_to order_path(order, order_token: order.token) + expect(flash[:notice]).to eq I18n.t(:order_processed_successfully) + end + + it "creates a customer record" do + order.update_columns(customer_id: nil) + Customer.delete_all + + expect { + get :confirm, params: { payment_intent: "pi_123" } + }.to change { Customer.count }.by(1) + end + end + + context "when the order is not in payment state" do + before { order.update_columns(state: "cart", completed_at: nil) } + + it "fails" do + expect(controller).to receive(:processing_failed).and_call_original + + get :confirm, params: { payment_intent: "pi_123" } + + expect(order.completed?).to be false + expect(response).to redirect_to checkout_path + expect(flash[:error]).to eq I18n.t(:payment_processing_failed) + end + end + + context "when a valid payment intent is not provided" do + it "fails" do + expect(controller).to receive(:processing_failed).and_call_original + + get :confirm, params: { payment_intent: "pi_666" } + + expect(order.completed?).to be false + expect(response).to redirect_to checkout_path + expect(flash[:error]).to eq I18n.t(:payment_processing_failed) + end + end + + context "when items in the cart are invalid" do + before do + allow(order_cycle_distributed_variants). + to receive(:distributes_order_variants?).and_return(false) + end + + it "fails" do + expect(controller).to receive(:processing_failed).and_call_original + + get :confirm, params: { payment_intent: "pi_123" } + + expect(order.completed?).to be false + expect(response).to redirect_to checkout_path + expect(flash[:error]).to eq I18n.t(:payment_processing_failed) + end + end + + context "items running out of stock during order completion" do + it "redirects to cart when some items are out of stock" do + allow(controller).to receive(:valid_payment_intent?).and_return true + allow(order).to receive_message_chain(:insufficient_stock_lines, :empty?).and_return false + + get :confirm, params: { payment_intent: "pi_123" } + expect(response).to redirect_to cart_path + end + + context "handling pending payments" do + let!(:payment) { create(:payment, state: "pending", amount: order.total, order: order) } + let!(:transaction_fee) { + create(:adjustment, state: "open", amount: 10, order: order, adjustable: payment) + } + + before do + allow(order).to receive_message_chain(:insufficient_stock_lines, :empty?) { false } + order.save + allow(order).to receive_message_chain(:payments, :completed) { [] } + allow(order).to receive_message_chain(:payments, :incomplete) { [payment] } + allow(controller).to receive(:valid_payment_intent?) { true } + allow(controller).to receive(:last_payment) { payment } + allow(payment).to receive(:adjustment) { transaction_fee } + end + + it "cancels the payment and resets the order to cart" do + expect(payment).to receive(:void_transaction!).and_call_original + + get :confirm, params: { payment_intent: "pi_123" } + + expect(response).to redirect_to cart_path + expect(flash[:notice]).to eq I18n.t('checkout.payment_cancelled_due_to_stock') + + expect(order.state).to eq "cart" + expect(payment.state).to eq "void" + expect(transaction_fee.reload.eligible).to eq false + expect(transaction_fee.state).to eq "finalized" + end + end + end + end + end +end