From 4464a85a74a864baa85213b60e9301c8e3fd8ede Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Mon, 11 Sep 2017 15:02:19 +1000 Subject: [PATCH] Add missing controller specs for CreditCardController #destroy --- .../spree/credit_cards_controller.rb | 19 ++-- app/models/spree/ability_decorator.rb | 5 ++ app/models/spree/credit_card_decorator.rb | 2 + .../spree/credit_cards_controller_spec.rb | 90 ++++++++++++++++--- 4 files changed, 97 insertions(+), 19 deletions(-) diff --git a/app/controllers/spree/credit_cards_controller.rb b/app/controllers/spree/credit_cards_controller.rb index aa67514f47..a4b8ce9479 100644 --- a/app/controllers/spree/credit_cards_controller.rb +++ b/app/controllers/spree/credit_cards_controller.rb @@ -17,25 +17,32 @@ module Spree end def destroy - @credit_card = Spree::CreditCard.find(params[:id]) - destroy_at_stripe + @credit_card = Spree::CreditCard.find_by_id(params[:id]) + if @credit_card + authorize! :destroy, @credit_card + destroy_at_stripe + end - if @credit_card.destroy + # Using try because we may not have a card here + if @credit_card.try(:destroy) flash[:success] = I18n.t(:card_has_been_removed, number: "x-#{@credit_card.last_digits}") else flash[:error] = I18n.t(:card_could_not_be_removed) end - redirect_to "/account#/cards" + redirect_to account_path(anchor: 'cards') + rescue Stripe::CardError => e + flash[:error] = I18n.t(:card_could_not_be_removed) + redirect_to account_path(anchor: 'cards') end + private + # Currently can only destroy the whole customer object def destroy_at_stripe stripe_customer = Stripe::Customer.retrieve(@credit_card.gateway_customer_profile_id) stripe_customer.delete if stripe_customer end - private - def create_customer(token) Stripe::Customer.create(email: spree_current_user.email, source: token) end diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index 9e36f7e5c6..164e27d81a 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -56,9 +56,14 @@ class AbilityDecorator user == item.order.user && item.order.changes_allowed? end + can [:cancel], Spree::Order do |order| order.user == user end + + can [:destroy], Spree::CreditCard do |credit_card| + credit_card.user == user + end end # New users can create an enterprise, and gain other permissions from doing this. diff --git a/app/models/spree/credit_card_decorator.rb b/app/models/spree/credit_card_decorator.rb index 69dadd6707..b9c0fca337 100644 --- a/app/models/spree/credit_card_decorator.rb +++ b/app/models/spree/credit_card_decorator.rb @@ -12,6 +12,8 @@ Spree::CreditCard.class_eval do # https://github.com/spree/spree/commit/411010f3975c919ab298cb63962ee492455b415c belongs_to :payment_method + belongs_to :user + # Allows us to use a gateway_payment_profile_id to store Stripe Tokens # Should be able to remove once we reach Spree v2.2.0 # Commit: https://github.com/spree/spree/commit/5a4d690ebc64b264bf12904a70187e7a8735ef3f diff --git a/spec/controllers/spree/credit_cards_controller_spec.rb b/spec/controllers/spree/credit_cards_controller_spec.rb index fcff7c7254..0fc910f2d2 100644 --- a/spec/controllers/spree/credit_cards_controller_spec.rb +++ b/spec/controllers/spree/credit_cards_controller_spec.rb @@ -5,26 +5,30 @@ describe Spree::CreditCardsController do include AuthenticationWorkflow let(:user) { create_enterprise_user } let(:token) { "tok_234bd2c22" } - let(:params) do - { - format: :json, - "exp_month" => 12, - "exp_year" => 2020, - "last4" => 4242, - "token" => token, - "cc_type" => "visa" - } - end before do allow(Stripe).to receive(:api_key) { "sk_test_12345" } allow(controller).to receive(:spree_current_user) { user } - stub_request(:post, "https://api.stripe.com/v1/customers") - .with(:body => { email: user.email, source: token }) - .to_return(response_mock) end describe "#new_from_token" do + let(:params) do + { + format: :json, + "exp_month" => 12, + "exp_year" => 2020, + "last4" => 4242, + "token" => token, + "cc_type" => "visa" + } + end + + before do + stub_request(:post, "https://api.stripe.com/v1/customers") + .with(:body => { email: user.email, source: token }) + .to_return(response_mock) + end + context "when the request to store the customer/card with Stripe is successful" do let(:response_mock) { { status: 200, body: JSON.generate(id: "cus_AZNMJ", default_source: "card_1AEEb") } } @@ -64,4 +68,64 @@ describe Spree::CreditCardsController do end end end + + describe "#destroy" do + context "when the specified credit card is not found" do + let(:params) { { id: 123 } } + + it "redirects to /account with a flash error, does not request deletion with Stripe" do + expect(controller).to_not receive(:destroy_at_stripe) + delete :destroy, params + expect(flash[:error]).to eq I18n.t(:card_could_not_be_removed) + expect(response).to redirect_to spree.account_path(anchor: 'cards') + end + end + + context "when the specified credit card is found" do + let!(:card) { create(:credit_card, gateway_customer_profile_id: 'cus_AZNMJ') } + let(:params) { { id: card.id } } + + context "but the card is not owned by the user" do + it "redirects to unauthorized" do + delete :destroy, params + expect(response).to redirect_to spree.unauthorized_path + end + end + + context "and the card is owned by the user" do + before do + card.update_attribute(:user_id, user.id) + + stub_request(:get, "https://api.stripe.com/v1/customers/cus_AZNMJ"). + to_return(:status => 200, :body => JSON.generate(id: "cus_AZNMJ")) + end + + context "where the request to destroy the Stripe customer fails" do + before do + stub_request(:delete, "https://api.stripe.com/v1/customers/cus_AZNMJ"). + to_return(:status => 402, :body => JSON.generate(error: { message: 'Bup-bow!' })) + end + + it "doesn't delete the card" do + expect{ delete :destroy, params }.to_not change(Spree::CreditCard, :count) + expect(flash[:error]).to eq I18n.t(:card_could_not_be_removed) + expect(response).to redirect_to spree.account_path(anchor: 'cards') + end + end + + context "where the request to destroy the Stripe customer succeeds" do + before do + stub_request(:delete, "https://api.stripe.com/v1/customers/cus_AZNMJ"). + to_return(:status => 200, :body => JSON.generate(deleted: true, id: "cus_AZNMJ")) + end + + it "deletes the card and redirects to account_path" do + expect{ delete :destroy, params }.to change(Spree::CreditCard, :count).by(-1) + expect(flash[:success]).to eq I18n.t(:card_has_been_removed, number: "x-#{card.last_digits}") + expect(response).to redirect_to spree.account_path(anchor: 'cards') + end + end + end + end + end end