houdini/spec/lib/insert/insert_card_spec.rb
Bradley M. Kuhn 6772312ea7 Relicense all .rb files under new project license.
The primary license of the project is changing to:
  AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later

with some specific files to be licensed under the one of two licenses:
   CC0-1.0
   LGPL-3.0-or-later

This commit is one of the many steps to relicense the entire codebase.

Documentation granting permission for this relicensing (from all past
contributors who hold copyrights) is on file with Software Freedom
Conservancy, Inc.
2018-03-25 15:10:40 -04:00

479 lines
19 KiB
Ruby

# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
require 'rails_helper'
describe InsertCard do
describe'.with_stripe' do
let(:stripe_helper) { StripeMock.create_test_helper }
let(:stripe_card_token) { StripeMock.generate_card_token(last4: '9191', exp_year:2011)}
let(:default_card_attribs) {
{
created_at: Time.now,
updated_at: Time.now,
profile_id: nil,
status: nil,
inactive: nil,
deleted: nil,
expiration_month: nil,
expiration_year: nil,
email:nil,
supporter_id: nil
}
}
let(:nonprofit) { force_create(:nonprofit)}
let(:user) { user = force_create(:user)
force_create(:role, name: :nonprofit_admin, host: nonprofit, user: user)
user
}
around(:each) {|example|
Timecop.freeze(2020, 5, 4) do
StripeMock.start
example.run
StripeMock.stop
end
}
it 'params are invalid' do
ret = InsertCard::with_stripe({ })
expect(ret[:status]).to eq(:unprocessable_entity)
expect(ret[:json][:error]).to start_with('Validation error')
expect(ret[:json][:errors].length).to be(9)
expect_validation_errors(ret[:json][:errors], [ {key: 'holder_id', name: :required},
{key: 'holder_type', name: 'included_in'},
{key: 'holder_type', name: 'required'},
{key: 'stripe_card_id', name: 'required'},
{key: 'stripe_card_id', name: 'not_blank'},
{key: 'stripe_card_token', name: 'required'},
{key: 'stripe_card_token', name: 'not_blank'},
{key: 'name', name: 'required'},
{key: 'name', name: 'not_blank'}
])
end
describe 'for nonprofits' do
let(:supporter) { nonprofit.supporters.first }
it 'nonprofit doesn\'t exist' do
ret = InsertCard::with_stripe({:holder_id => 3, :holder_type => 'Nonprofit', :stripe_card_id => 'card_fafjeht', :stripe_card_token => stripe_card_token, :name => 'name'})
expect(ret[:status]).to eq(:unprocessable_entity)
expect(ret[:json][:error]).to include("Sorry, you need to provide a nonprofit or supporter")
end
it 'should properly add nonprofit card when no card exists' do
stripe_customer = nil
expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer}
card_data = { :holder_type => 'Nonprofit', :holder_id => nonprofit.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" }
orig_card = nonprofit.active_card
expect(orig_card).to be_nil
card_ret = InsertCard::with_stripe(card_data);
nonprofit.reload
card = nonprofit.active_card
compare_card_returned_to_real(card_ret, card)
expected_card = {
id: card.id,
name: 'card_name',
stripe_card_token: stripe_card_token,
stripe_card_id: 'card_88888',
holder_type: 'Nonprofit',
holder_id: nonprofit.id,
stripe_customer_id: stripe_customer['id']
}.merge(default_card_attribs).with_indifferent_access
expect(card.attributes).to eq expected_card
expect(Card.where('holder_id = ? and holder_type = ?', nonprofit.id, 'Nonprofit').count).to eq(1)
customer = verify_cust_added_np(card.stripe_customer_id, nonprofit.id)
expect(customer.sources.count).to eq(1)
expect(customer.sources.data[0].object).to eq('card')
expect(customer.sources.data[0].last4).to eq('9191')
expect(customer.sources.data[0].exp_year).to eq(2011)
end
it 'invalid params get ignored' do
stripe_customer = nil
expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer}
card_data = { :holder_type => 'Nonprofit', :holder_id => nonprofit.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token,
:name => "card_name", :created_at => DateTime.new(0), :updated_at => DateTime.new(0), :inactive => true}
card_ret = InsertCard::with_stripe(card_data);
nonprofit.reload
card = Card.find(card_ret[:json][:id])
expect(nonprofit.active_card).to eq card
compare_card_returned_to_real(card_ret, card)
expected_card = {
id: card.id,
name: 'card_name',
stripe_card_token: stripe_card_token,
stripe_card_id: 'card_88888',
holder_type: 'Nonprofit',
holder_id: nonprofit.id,
stripe_customer_id: stripe_customer['id']
}.merge(default_card_attribs).with_indifferent_access
expect(card.attributes).to eq expected_card
end
describe 'card exists' do
before(:each) {
@first_card_tok = StripeMock.generate_card_token(:last4 => '9999', :exp_year => '2122')
@stripe_customer = Stripe::Customer.create()
@stripe_customer.sources.create({token: @first_card_tok})
}
it 'should properly add nonprofit card and make old inactive' do
stripe_customer = nil
expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer}
first_card = nonprofit.create_active_card(:stripe_card_id => 'fake mcfake', :stripe_card_token => @first_card_tok, :name=> 'fake name')
card_data = { :holder_type => 'Nonprofit', :holder_id => nonprofit.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" }
card_ret = InsertCard::with_stripe(card_data);
nonprofit.reload
card = nonprofit.active_card
compare_card_returned_to_real(card_ret, card)
expected_card = {
id: card.id,
name: 'card_name',
stripe_card_token: stripe_card_token,
stripe_card_id: 'card_88888',
holder_type: 'Nonprofit',
holder_id: nonprofit.id,
stripe_customer_id: stripe_customer['id']
}.merge(default_card_attribs).with_indifferent_access
expect(card.attributes).to eq expected_card
expect(Card.where('holder_id = ? and holder_type = ?', nonprofit.id, 'Nonprofit').count).to eq(2)
expect(Card.where('holder_id = ? and holder_type = ? and inactive != ?', nonprofit.id, 'Nonprofit', false).count).to eq(1)
customer = verify_cust_added_np(card.stripe_customer_id, nonprofit.id)
expect(customer.sources.count).to eq(1)
expect(customer.sources.data.any?{|s| s.object == 'card' && s.last4 == '9191' && s.exp_year == 2011}).to eq(true)
#verify the original card didn't change
expect(nonprofit.cards.find(first_card.id).attributes.select{|k,_| k != 'inactive'}).to eq first_card.attributes.select{|k, _| k != 'inactive'}
expect(nonprofit.cards.find(first_card.id).inactive).to eq true
end
end
it 'handle card errors' do
StripeMock.prepare_error(Stripe::CardError.new('card error', nil, nil, 300,{},{error: {message: 'a message'}}), :new_customer)
card_data = { :holder_type => 'Nonprofit', :holder_id => nonprofit.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" }
card_ret = InsertCard::with_stripe(card_data);
expect(card_ret[:status]).to be :unprocessable_entity
expect(card_ret[:json][:error]).to start_with('Oops!')
end
it 'handle stripe errors' do
StripeMock.prepare_error(Stripe::StripeError.new('card error', nil, nil), :new_customer)
card_data = { :holder_type => 'Nonprofit', :holder_id => nonprofit.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" }
card_ret = InsertCard::with_stripe(card_data);
expect(card_ret[:status]).to eq :unprocessable_entity
expect(card_ret[:json][:error]).to start_with('Oops!')
end
def verify_cust_added_np(stripe_customer_id, holder_id)
verify_cust_added(stripe_customer_id, holder_id, 'Nonprofit')
end
end
describe 'for supporter' do
let(:supporter) {force_create(:supporter, nonprofit: nonprofit)}
let(:event) {
force_create(:event, nonprofit: nonprofit, end_datetime: Time.now.since(1.day))}
let(:user_not_from_nonprofit) {force_create(:user)}
def verify_cust_added_supporter(stripe_customer_id, holder_id)
verify_cust_added(stripe_customer_id, holder_id, 'Supporter')
end
def verify_supporter_source_token(source_token, card)
verify_source_token(source_token, card, 1, Time.now.since(20.minutes))
end
def verify_event_source_token(source_token, card, event)
verify_source_token(source_token, card, 20, event.end_datetime.since(20.days), event)
end
context 'card exists' do
let(:supporter) {create(:supporter, :has_a_card, nonprofit:nonprofit)}
it 'should properly add supporter card' do
expect(supporter.cards.count).to eq(1)
stripe_customer = nil
expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer}
card_data = { :holder_type => 'Supporter', :holder_id => supporter.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" }
orig_card = supporter.cards.first
card_ret = InsertCard::with_stripe(card_data);
supporter.reload
card = supporter.cards.where('cards.name = ?', 'card_name').first
compare_card_returned_to_real(card_ret, card, card_ret[:json]['token'])
expected_card = {
id: card.id,
name: 'card_name',
stripe_card_token: stripe_card_token,
stripe_card_id: 'card_88888',
holder_id: supporter.id,
holder_type: 'Supporter',
stripe_customer_id: stripe_customer['id'],
}.merge(default_card_attribs).with_indifferent_access
expect(card.attributes).to eq expected_card
expect(supporter.cards.count).to eq(2)
expect(Card.where('holder_id = ? and holder_type = ?', supporter.id, 'Supporter').count).to eq(2)
expect(Card.where('holder_id = ? and holder_type = ? and inactive != ?', supporter.id, 'Supporter', false).count).to eq(0)
expect(supporter.cards.find(orig_card.id)).to eq(orig_card)
verify_cust_added_supporter(card.stripe_customer_id, supporter.id)
verify_supporter_source_token(card_ret[:json]['token'], card)
end
it 'should properly add card for event' do
expect(supporter.cards.count).to eq(1)
stripe_customer = nil
expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer}
card_data = { :holder_type => 'Supporter', :holder_id => supporter.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" }
orig_card = supporter.cards.first
card_ret = InsertCard::with_stripe(card_data, nil, event.id, user);
supporter.reload
card = supporter.cards.where('cards.name = ?', 'card_name').first
compare_card_returned_to_real(card_ret, card, card_ret[:json]['token'])
expected_card = {
id: card.id,
name: 'card_name',
stripe_card_token: stripe_card_token,
stripe_card_id: 'card_88888',
holder_id: supporter.id,
holder_type: 'Supporter',
stripe_customer_id: stripe_customer['id'],
}.merge(default_card_attribs).with_indifferent_access
expect(card.attributes).to eq expected_card
expect(supporter.cards.count).to eq(2)
expect(Card.where('holder_id = ? and holder_type = ?', supporter.id, 'Supporter').count).to eq(2)
expect(Card.where('holder_id = ? and holder_type = ? and inactive != ?', supporter.id, 'Supporter', false).count).to eq(0)
expect(supporter.cards.find(orig_card.id)).to eq(orig_card)
verify_cust_added_supporter(card.stripe_customer_id, supporter.id)
verify_event_source_token(card_ret[:json]['token'], card, event)
end
end
context 'card doesnt exist' do
it 'invalid params get ignored' do
stripe_customer = nil
expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer}
card_data = { :holder_type => 'Supporter', :holder_id => supporter.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token,
:name => "card_name", :created_at => DateTime.new(0), :updated_at => DateTime.new(0), :inactive => true}
card_ret = InsertCard.with_stripe(card_data);
card = Card.find(card_ret[:json][:id])
supporter.reload
compare_card_returned_to_real(card_ret, card, card_ret[:json]['token'])
expected_card = {
id: card.id,
holder_type: 'Supporter',
holder_id: supporter.id,
stripe_card_token: stripe_card_token,
name: 'card_name',
stripe_card_id: 'card_88888',
stripe_customer_id: stripe_customer['id']
}.merge(default_card_attribs).with_indifferent_access
expect(card.attributes).to eq expected_card
verify_supporter_source_token(card_ret[:json]['token'], card)
end
it 'should properly add supporter card when no card exist' do
stripe_customer = nil
expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer}
card_data = { :holder_type => 'Supporter', :holder_id => supporter.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" }
card_ret = InsertCard::with_stripe(card_data);
supporter.reload
card = supporter.cards.where('cards.name = ?', 'card_name').first
compare_card_returned_to_real(card_ret, card, card_ret[:json]['token'])
expected_card = {
id: card.id,
name: 'card_name',
stripe_card_id: 'card_88888',
stripe_card_token: stripe_card_token,
stripe_customer_id: stripe_customer['id'],
holder_type: 'Supporter',
holder_id: supporter.id
}.merge(default_card_attribs).with_indifferent_access
expect(card.attributes).to eq expected_card
expect(supporter.cards.count).to eq(1)
expect(Card.where('holder_id = ? and holder_type = ?', supporter.id, 'Supporter').count).to eq(1)
expect(Card.where('holder_id = ? and holder_type = ? and inactive != ?', supporter.id, 'Supporter', false).count).to eq(0)
verify_cust_added_supporter(card.stripe_customer_id, supporter.id)
verify_supporter_source_token(card_ret[:json]['token'], card)
end
it 'should properly add card for event' do
stripe_customer = nil
expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer}
card_data = { :holder_type => 'Supporter', :holder_id => supporter.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" }
card_ret = InsertCard::with_stripe(card_data, nil, event.id, user);
supporter.reload
card = supporter.cards.where('cards.name = ?', 'card_name').first
compare_card_returned_to_real(card_ret, card, card_ret[:json]['token'])
expected_card = {
id: card.id,
name: 'card_name',
stripe_card_token: stripe_card_token,
stripe_card_id: 'card_88888',
holder_id: supporter.id,
holder_type: 'Supporter',
stripe_customer_id: stripe_customer['id'],
}.merge(default_card_attribs).with_indifferent_access
expect(card.attributes).to eq expected_card
expect(supporter.cards.count).to eq(1)
expect(Card.where('holder_id = ? and holder_type = ?', supporter.id, 'Supporter').count).to eq(1)
expect(Card.where('holder_id = ? and holder_type = ? and inactive != ?', supporter.id, 'Supporter', false).count).to eq(0)
verify_cust_added_supporter(card.stripe_customer_id, supporter.id)
verify_event_source_token(card_ret[:json]['token'], card, event)
end
end
it 'should return proper error when no supporter exists' do
ret = InsertCard::with_stripe({:holder_id => 5555555, :holder_type => 'Supporter', :stripe_card_id => 'card_fafjeht', :stripe_card_token => stripe_card_token, :name => 'name'})
expect(ret[:status]).to eq(:unprocessable_entity)
expect(ret[:json][:error]).to include("Sorry, you need to provide a nonprofit or supporter")
end
it 'should return proper error when you try to add using an event with unauthorized user' do
ret = InsertCard::with_stripe({holder_id: supporter.id, holder_type: 'Supporter', stripe_card_id: 'card_fafjeht', stripe_card_token: stripe_card_token, name: 'name'}, nil, event.id, user_not_from_nonprofit)
expect(ret[:json][:error]).to eq "You're not authorized to perform that action"
expect(ret[:status]).to eq (:unauthorized)
end
it 'should return proper error when an invalid event_id is provided' do
ret = InsertCard.with_stripe({holder_id: supporter.id, holder_type: 'Supporter', stripe_card_id: 'card_fafjeht', stripe_card_token: stripe_card_token, name: 'name'}, nil, 55555, user_not_from_nonprofit)
expect(ret).to eq({ status: :unprocessable_entity, json: {error: 'Oops! There was an error: 55555 is not a valid event'}})
end
it 'should return proper error when event doesnt match the supporters nonprofit' do
supporter2 = force_create(:supporter)
ret = InsertCard.with_stripe({holder_id: supporter2.id, holder_type: 'Supporter', stripe_card_id: 'card_fafjeht', stripe_card_token: stripe_card_token, name: 'name'}, nil, event.id, user_not_from_nonprofit)
expect(ret).to eq({ status: :unprocessable_entity, json: {error: "Oops! There was an error: Event #{event.id} is not for the same nonprofit as supporter #{supporter2.id}"}})
end
end
def compare_card_returned_to_real(card_ret, db_card, token=nil)
expect(card_ret[:status]).to eq(:ok)
expected_json = db_card.attributes
expected_json.merge!({'token' => token})
if token
expect(token).to match(UUID::Regex)
end
expect(card_ret[:json]).to eq(expected_json)
end
def verify_cust_added(stripe_customer_id, holder_id, holder_type)
customer = Stripe::Customer.retrieve(stripe_customer_id)
# does the customer exist? Was it set properly? Was the card set properly
expect(customer).to_not be_nil
expected_metadata = {
holder_id: holder_id,
holder_type: holder_type,
cardholders_name: nil
}
expect(customer.metadata.to_hash).to eq expected_metadata
customer
end
def verify_source_token(source_token, card, max_uses, expiration_time, event=nil)
tok = SourceToken.where('token = ?', source_token).first
expected = {
created_at: Time.now,
updated_at: Time.now,
tokenizable_id: card.id,
tokenizable_type: 'Card',
max_uses: max_uses,
total_uses: 0,
expiration: expiration_time,
event_id: event ? event.id : nil,
token: source_token
}.with_indifferent_access
expect(tok.attributes).to eq expected
end
end
end