Files
openfoodnetwork/spec/models/spree/credit_card_spec.rb
Matt-Yorkley 4cdb892c75 Refactor formatting of credit card brand names and reformat automatically when saving
This little bit of "translation" between what we might receive as input and what ActiveMerchant requires is important, but currently the responsibility for this job is spread all over the code base. It can now just live in the CreditCard model (in one place) and doesn't need to be duplicated anywhere else (like several different places in frontend Javascript!)
2021-12-02 16:22:52 +00:00

325 lines
11 KiB
Ruby

# frozen_string_literal: false
require 'spec_helper'
module Spree
describe CreditCard do
let(:valid_credit_card_attributes) {
{
number: '4111111111111111',
verification_value: '123',
month: 12,
year: Time.zone.now.year + 1
}
}
describe "original specs from Spree" do
def self.payment_states
Spree::Payment.state_machine.states.keys
end
def stub_rails_env(environment)
allow(Rails).to receive_messages(env: ActiveSupport::StringInquirer.new(environment))
end
let(:credit_card) { Spree::CreditCard.new }
context "#can_capture?" do
it "should be true if payment is pending" do
payment = build_stubbed(:payment, created_at: Time.zone.now)
allow(payment).to receive(:pending?) { true }
expect(credit_card.can_capture?(payment)).to be_truthy
end
it "should be true if payment is checkout" do
payment = build_stubbed(:payment, created_at: Time.zone.now)
allow(payment).to receive_messages pending?: false,
checkout?: true
expect(credit_card.can_capture?(payment)).to be_truthy
end
end
context "#can_void?" do
it "should be true if payment is not void" do
payment = build_stubbed(:payment)
allow(payment).to receive(:void?) { false }
expect(credit_card.can_void?(payment)).to be_truthy
end
end
context "#can_credit?" do
it "should be false if payment is not completed" do
payment = build_stubbed(:payment)
allow(payment).to receive(:completed?) { false }
expect(credit_card.can_credit?(payment)).to be_falsy
end
it "should be false when order payment_state is not 'credit_owed'" do
payment = build_stubbed(:payment,
order: create(:order, payment_state: 'paid'))
allow(payment).to receive(:completed?) { true }
expect(credit_card.can_credit?(payment)).to be_falsy
end
it "should be false when credit_allowed is zero" do
payment = build_stubbed(:payment,
order: create(:order, payment_state: 'credit_owed'))
allow(payment).to receive_messages completed?: true,
credit_allowed: 0
expect(credit_card.can_credit?(payment)).to be_falsy
end
end
context "#valid?" do
it "should validate presence of number" do
credit_card.attributes = valid_credit_card_attributes.except(:number)
expect(credit_card).to_not be_valid
expect(credit_card.errors[:number]).to eq ["can't be blank"]
end
it "should validate presence of security code" do
credit_card.attributes = valid_credit_card_attributes.except(:verification_value)
expect(credit_card).to_not be_valid
expect(credit_card.errors[:verification_value]).to eq ["can't be blank"]
end
it "should validate expiration is not in the past" do
credit_card.month = 1.month.ago.month
credit_card.year = 1.month.ago.year
expect(credit_card).to_not be_valid
expect(credit_card.errors[:base]).to eq ["has expired"]
end
it "does not run expiration in the past validation if month is not set" do
credit_card.month = nil
credit_card.year = Time.zone.now.year
expect(credit_card).to_not be_valid
expect(credit_card.errors[:base]).to be_blank
end
it "does not run expiration in the past validation if year is not set" do
credit_card.month = Time.zone.now.month
credit_card.year = nil
expect(credit_card).to_not be_valid
expect(credit_card.errors[:base]).to be_blank
end
it "does not run expiration in the past validation if year and month are empty" do
credit_card.year = ""
credit_card.month = ""
expect(credit_card).to_not be_valid
expect(credit_card.errors[:card]).to be_blank
end
it "should only validate on create" do
credit_card.attributes = valid_credit_card_attributes
credit_card.save
expect(credit_card).to be_valid
end
end
context "#save" do
before do
credit_card.attributes = valid_credit_card_attributes
credit_card.save!
end
let!(:persisted_card) { Spree::CreditCard.find(credit_card.id) }
it "should not actually store the number" do
expect(persisted_card.number).to be_blank
end
it "should not actually store the security code" do
expect(persisted_card.verification_value).to be_blank
end
end
context "#number=" do
it "should strip non-numeric characters from card input" do
credit_card.number = "6011000990139424"
expect(credit_card.number).to eq "6011000990139424"
credit_card.number = " 6011-0009-9013-9424 "
expect(credit_card.number).to eq "6011000990139424"
end
it "should not raise an exception on non-string input" do
credit_card.number = ({})
expect(credit_card.number).to be_nil
end
end
context "#associations" do
it "should be able to access its payments" do
expect { credit_card.payments.to_a }.not_to raise_error
end
end
context "#to_active_merchant" do
before do
credit_card.number = "4111111111111111"
credit_card.year = Time.zone.now.year
credit_card.month = Time.zone.now.month
credit_card.first_name = "Bob"
credit_card.last_name = "Boblaw"
credit_card.verification_value = 123
end
it "converts to an ActiveMerchant::Billing::CreditCard object" do
am_card = credit_card.to_active_merchant
expect(am_card.number).to eq "4111111111111111"
expect(am_card.year).to eq Time.zone.now.year
expect(am_card.month).to eq Time.zone.now.month
expect(am_card.first_name).to eq "Bob"
am_card.last_name = "Boblaw"
expect(am_card.verification_value).to eq 123
end
end
end
describe "formatting the card type for ActiveMerchant" do
context "#cc_type=" do
let(:credit_card) { build(:credit_card) }
it "converts the card type format" do
credit_card.cc_type = 'mastercard'
expect(credit_card.cc_type).to eq 'master'
credit_card.cc_type = 'maestro'
expect(credit_card.cc_type).to eq 'master'
credit_card.cc_type = 'amex'
expect(credit_card.cc_type).to eq 'american_express'
credit_card.cc_type = 'dinersclub'
expect(credit_card.cc_type).to eq 'diners_club'
credit_card.cc_type = 'some_outlandish_cc_type'
expect(credit_card.cc_type).to eq 'some_outlandish_cc_type'
end
end
context "on save" do
it "converts the card type format" do
expect_any_instance_of(Spree::CreditCard).to receive(:reformat_card_type!).
at_least(:once).and_call_original
credit_card = Spree::CreditCard.create(
valid_credit_card_attributes.merge(cc_type: "Master Card")
)
expect(credit_card.cc_type).to eq "master"
end
end
end
describe "setting default credit card for a user" do
let(:user) { create(:user) }
let(:onetime_card_attrs) do
{ user: user, gateway_payment_profile_id: "tok_1EY..." }
end
let(:stored_card_attrs) do
{
user: user,
gateway_customer_profile_id: "cus_F2T...",
gateway_payment_profile_id: "card_1EY..."
}
end
let(:stored_default_card_attrs) do
stored_card_attrs.merge(is_default: true)
end
context "when a card is already set as the default" do
let!(:card1) { create(:credit_card, stored_default_card_attrs) }
context "and I create a new card" do
context "without specifying it as the default" do
let!(:card2) { create(:credit_card, stored_card_attrs) }
it "keeps the existing default" do
expect(card1.reload.is_default).to be true
expect(card2.reload.is_default).to be false
end
end
context "and I specify it as the default" do
let!(:card2) { create(:credit_card, stored_default_card_attrs) }
it "switches the default to the new card" do
expect(card1.reload.is_default).to be false
expect(card2.reload.is_default).to be true
end
end
end
context "and I update another card" do
let!(:card2) { create(:credit_card, user: user) }
context "without specifying it as the default" do
it "keeps the existing default" do
card2.update!(stored_card_attrs)
expect(card1.reload.is_default).to be true
expect(card2.reload.is_default).to be false
end
end
context "and I specify it as the default" do
it "switches the default to the updated card" do
card2.update!(stored_default_card_attrs)
expect(card1.reload.is_default).to be false
expect(card2.reload.is_default).to be true
end
end
end
end
context "when no card is currently set as the default for a user" do
context "and I create a new card" do
context "without specifying it as the default" do
let!(:card1) { create(:credit_card, stored_card_attrs) }
it "sets it as the default anyway" do
expect(card1.reload.is_default).to be true
end
end
context "and I specify it as the default" do
let!(:card1) { create(:credit_card, stored_default_card_attrs) }
it "sets it as the default" do
expect(card1.reload.is_default).to be true
end
end
end
context "and the checkout creates a card" do
let!(:card1) { create(:credit_card, onetime_card_attrs) }
let(:store_card_profile_attrs) {
{
cc_type: "visa",
gateway_customer_profile_id: "cus_FH9HflKAJw6Kxy",
gateway_payment_profile_id: "card_1EmayNBZvgSKc1B2wctIzzoh"
}
}
it "doesn't set a one-time card as the default" do
expect(card1.reload.is_default).to be false
end
it "sets a re-usable card as the default" do
# The checkout first creates a one-time card and then converts it
# to a re-usable card.
# This imitates Stripe::ProfileStorer.
card1.update!(store_card_profile_attrs)
expect(card1.reload.is_default).to be true
end
end
end
end
end
end