From 46ba6b7f9ce8edba2c6d536a401eb30e28f06630 Mon Sep 17 00:00:00 2001 From: cyrillefr Date: Tue, 17 Jun 2025 14:50:35 +0200 Subject: [PATCH] Style Metrics/ModuleLength in spec file --- .rubocop_todo.yml | 1 - spec/models/spree/credit_card_spec.rb | 578 +++++++++++++------------- 2 files changed, 288 insertions(+), 291 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 7557e26e56..df5fb3f67b 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -161,7 +161,6 @@ Metrics/ModuleLength: - 'app/models/spree/order/checkout.rb' - 'app/models/spree/payment/processing.rb' - 'lib/open_food_network/column_preference_defaults.rb' - - 'spec/models/spree/credit_card_spec.rb' - 'spec/models/spree/line_item_spec.rb' - 'spec/models/spree/order/tax_spec.rb' - 'spec/models/spree/product_spec.rb' diff --git a/spec/models/spree/credit_card_spec.rb b/spec/models/spree/credit_card_spec.rb index 749bdea460..d39162360e 100644 --- a/spec/models/spree/credit_card_spec.rb +++ b/spec/models/spree/credit_card_spec.rb @@ -2,322 +2,320 @@ require 'spec_helper' -module Spree - RSpec.describe CreditCard do - let(:valid_credit_card_attributes) { - { - number: '4111111111111111', - verification_value: '123', - month: 12, - year: Time.zone.now.year + 1 - } +RSpec.describe Spree::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 + 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) { described_class.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_and_complete_order?(payment)).to be_truthy 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_and_complete_order?(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_and_complete_order?(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).not_to 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).not_to 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).not_to 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).not_to 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).not_to 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).not_to 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 + 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_and_complete_order?(payment)).to be_truthy 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 + 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 - describe "setting default credit card for a user" do - let(:user) { create(:user) } - let(:onetime_card_attrs) do - { user:, gateway_payment_profile_id: "tok_1EY..." } - end - let(:stored_card_attrs) do - { - 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) + 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 - context "when a card is already set as the default" do - let!(:card1) { create(:credit_card, stored_default_card_attrs) } + 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 - 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 "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 - it "keeps the existing default" do - expect(card1.reload.is_default).to be true - expect(card2.reload.is_default).to be false - end - end + expect(credit_card.can_credit?(payment)).to be_falsy + end + end - context "and I specify it as the default" do - let!(:card2) { create(:credit_card, stored_default_card_attrs) } + context "#valid?" do + it "should validate presence of number" do + credit_card.attributes = valid_credit_card_attributes.except(:number) + expect(credit_card).not_to be_valid + expect(credit_card.errors[:number]).to eq ["can't be blank"] + end - 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 + it "should validate presence of security code" do + credit_card.attributes = valid_credit_card_attributes.except(:verification_value) + expect(credit_card).not_to 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).not_to 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).not_to 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).not_to 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).not_to 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) { described_class.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(described_class).to receive(:reformat_card_type!). + at_least(:once).and_call_original + + credit_card = described_class.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:, gateway_payment_profile_id: "tok_1EY..." } + end + let(:stored_card_attrs) do + { + 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 update another card" do - let!(:card2) { create(:credit_card, user:) } + context "and I specify it as the default" do + let!(:card2) { create(:credit_card, stored_default_card_attrs) } - 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 + 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 - 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) + context "and I update another card" do + let!(:card2) { create(:credit_card, 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