From ca17b8842cc3fb5cc80ffe2fed17fef52d564f41 Mon Sep 17 00:00:00 2001 From: sawan gupta Date: Sat, 27 Feb 2016 22:44:07 +0530 Subject: [PATCH 1/3] complete rspecs for price model 1) Add paranoia examples to shared directory 2) Make small code level changes while writing specs --- core/app/models/spree/price.rb | 9 +- core/spec/models/spree/price_spec.rb | 216 +++++++++++++----- .../models/spree/shared/paranoia_examples.rb | 15 ++ core/spec/spec_helper.rb | 1 + 4 files changed, 179 insertions(+), 62 deletions(-) create mode 100644 core/spec/models/spree/shared/paranoia_examples.rb diff --git a/core/app/models/spree/price.rb b/core/app/models/spree/price.rb index c46809965a7..760f2528eaa 100644 --- a/core/app/models/spree/price.rb +++ b/core/app/models/spree/price.rb @@ -4,15 +4,18 @@ class Price < Spree::Base acts_as_paranoid - MAXIMUM_AMOUNT = BigDecimal('99_999_999.99') + AMOUNT = { + max: BigDecimal('99_999_999.99'), + min: 0 + } belongs_to :variant, class_name: 'Spree::Variant', inverse_of: :prices, touch: true before_validation :ensure_currency validates :amount, allow_nil: true, numericality: { - greater_than_or_equal_to: 0, - less_than_or_equal_to: MAXIMUM_AMOUNT + greater_than_or_equal_to: AMOUNT[:min], + less_than_or_equal_to: AMOUNT[:max] } extend DisplayMoney diff --git a/core/spec/models/spree/price_spec.rb b/core/spec/models/spree/price_spec.rb index ff796f77013..f39ccdd109a 100644 --- a/core/spec/models/spree/price_spec.rb +++ b/core/spec/models/spree/price_spec.rb @@ -1,34 +1,37 @@ require 'spec_helper' describe Spree::Price, :type => :model do - describe '#amount=' do - let(:price) { Spree::Price.new } - let(:amount) { '3,0A0' } - before do - price.amount = amount - end + it_behaves_like 'a Paranoid model' - it 'is expected to equal to localized number' do - expect(price.amount).to eq(Spree::LocalizedNumber.parse(amount)) + describe 'Modules' do + describe 'Inclusions' do + it { expect(Spree::Price.include?(Spree::VatPriceCalculation)).to be true } + it { expect(Spree::Price.ancestors).to include Spree::DisplayMoney } end end - describe '#price' do - let(:price) { Spree::Price.new } - let(:amount) { 3000.00 } - - context 'when amount is changed' do - before do - price.amount = amount + describe 'Constants' do + describe 'MAXIMUM AMOUNT' do + it 'return 99999999.99' do + expect(Spree::Price::AMOUNT[:max]).to eq BigDecimal('99_999_999.99') end + end - it 'is expected to equal to price' do - expect(price.amount).to eq(price.price) + describe 'MINIMUM AMOUNT' do + it 'return 0' do + expect(Spree::Price::AMOUNT[:min]).to eq 0 end end end + describe 'association' do + it do + is_expected.to belong_to(:variant).class_name('Spree::Variant'). + inverse_of(:prices).touch(true) + end + end + describe 'validations' do let(:variant) { stub_model Spree::Variant } subject { Spree::Price.new variant: variant, amount: amount } @@ -38,7 +41,7 @@ it { is_expected.to be_valid } end - context 'when the amount is less than 0' do + context 'when the amount is less than #{Spree::Price::AMOUNT[:min]}' do let(:amount) { -1 } it 'has 1 error_on' do @@ -46,83 +49,178 @@ end it 'populates errors' do subject.valid? - expect(subject.errors.messages[:amount].first).to eq 'must be greater than or equal to 0' + expect(subject.errors.messages[:amount].first).to eq "must be greater than or equal to #{Spree::Price::AMOUNT[:min]}" end end context 'when the amount is greater than maximum amount' do - let(:amount) { Spree::Price::MAXIMUM_AMOUNT + 1 } + let(:amount) { Spree::Price::AMOUNT[:max] + 1 } it 'has 1 error_on' do expect(subject.error_on(:amount).size).to eq(1) end it 'populates errors' do subject.valid? - expect(subject.errors.messages[:amount].first).to eq "must be less than or equal to #{Spree::Price::MAXIMUM_AMOUNT}" + expect(subject.errors.messages[:amount].first).to eq "must be less than or equal to #{Spree::Price::AMOUNT[:max]}" end end context 'when the amount is between 0 and the maximum amount' do - let(:amount) { Spree::Price::MAXIMUM_AMOUNT } + let(:amount) { Spree::Price::AMOUNT[:max] } it { is_expected.to be_valid } end end - describe '#price_including_vat_for(zone)' do - let(:variant) { stub_model Spree::Variant } - let(:default_zone) { Spree::Zone.new } - let(:zone) { Spree::Zone.new } - let(:amount) { 10 } - let(:tax_category) { Spree::TaxCategory.new } - let(:price) { Spree::Price.new variant: variant, amount: amount } - let(:price_options) { { tax_zone: zone } } + describe 'Callbacks' do + it { is_expected.to callback(:ensure_currency).before(:validation) } + end - subject(:price_with_vat) { price.price_including_vat_for(price_options) } + describe 'whitelisted ransackable attributes' do + it 'returns amount attribute' do + expect(Spree::Price.whitelisted_ransackable_attributes).to eq(['amount']) + end + end + + # Instance methods + + describe 'Instance Methods' do + + describe '#amount=' do + let(:price) { Spree::Price.new } + let(:amount) { '3,0A0' } - context 'when called with a non-default zone' do before do - allow(variant).to receive(:tax_category).and_return(tax_category) - expect(price).to receive(:default_zone).at_least(:once).and_return(default_zone) - allow(price).to receive(:apply_foreign_vat?).and_return(true) - allow(price).to receive(:included_tax_amount).with(tax_zone: default_zone, tax_category: tax_category) { 0.19 } - allow(price).to receive(:included_tax_amount).with(tax_zone: zone, tax_category: tax_category) { 0.25 } + price.amount = amount end - it "returns the correct price including another VAT to two digits" do - expect(price_with_vat).to eq(10.50) + it 'is expected to equal to localized number' do + expect(price.amount).to eq(Spree::LocalizedNumber.parse(amount)) end end - context 'when called from the default zone' do - before do - allow(variant).to receive(:tax_category).and_return(tax_category) - expect(price).to receive(:default_zone).at_least(:once).and_return(zone) + describe '#price_including_vat_for(zone)' do + let(:variant) { stub_model Spree::Variant } + let(:default_zone) { Spree::Zone.new } + let(:zone) { Spree::Zone.new } + let(:amount) { 10 } + let(:tax_category) { Spree::TaxCategory.new } + let(:price) { Spree::Price.new variant: variant, amount: amount } + let(:price_options) { { tax_zone: zone } } + + subject(:price_with_vat) { price.price_including_vat_for(price_options) } + + context 'when called with a non-default zone' do + before do + allow(variant).to receive(:tax_category).and_return(tax_category) + expect(price).to receive(:default_zone).at_least(:once).and_return(default_zone) + allow(price).to receive(:apply_foreign_vat?).and_return(true) + allow(price).to receive(:included_tax_amount).with(tax_zone: default_zone, tax_category: tax_category) { 0.19 } + allow(price).to receive(:included_tax_amount).with(tax_zone: zone, tax_category: tax_category) { 0.25 } + end + + it "returns the correct price including another VAT to two digits" do + expect(price_with_vat).to eq(10.50) + end end - it "returns the correct price" do - expect(price).to receive(:price).and_call_original - expect(price_with_vat).to eq(10.00) + context 'when called from the default zone' do + before do + allow(variant).to receive(:tax_category).and_return(tax_category) + expect(price).to receive(:default_zone).at_least(:once).and_return(zone) + end + + it "returns the correct price" do + expect(price).to receive(:price).and_call_original + expect(price_with_vat).to eq(10.00) + end + end + + context 'when no default zone is set' do + before do + allow(variant).to receive(:tax_category).and_return(tax_category) + expect(price).to receive(:default_zone).at_least(:once).and_return(nil) + end + + it "returns the correct price" do + expect(price).to receive(:price).and_call_original + expect(price.price_including_vat_for(tax_zone: zone)).to eq(10.00) + end end end - context 'when no default zone is set' do - before do - allow(variant).to receive(:tax_category).and_return(tax_category) - expect(price).to receive(:default_zone).at_least(:once).and_return(nil) + describe '#display_price_including_vat_for(zone)' do + subject { Spree::Price.new amount: 10 } + it 'calls #price_including_vat_for' do + expect(subject).to receive(:price_including_vat_for) + subject.display_price_including_vat_for(nil) end + end - it "returns the correct price" do - expect(price).to receive(:price).and_call_original - expect(price.price_including_vat_for(tax_zone: zone)).to eq(10.00) + describe '#money' do + context 'when price has amount' do + let(:price) { build(:price) } + it 'reutrns amount with currency' do + expect(price.money.to_s).to eq('$19.99') + end + end + + context 'when price does not has amount' do + let(:price) { build(:price) } + before { price.amount = nil } + it 'reutrns amount with currency' do + expect(price.money.to_s).to eq('$0.00') + end end end - end - describe '#display_price_including_vat_for(zone)' do - subject { Spree::Price.new amount: 10 } - it 'calls #price_including_vat_for' do - expect(subject).to receive(:price_including_vat_for) - subject.display_price_including_vat_for(nil) + describe '#price' do + let(:price) { build(:price) } + it 'returns amount' do + expect(price.price).to eq(price.amount) + end + end + + describe '#price=' do + let(:price) { build(:price) } + context 'when price contains currency symbol' do + it 'removes currency symbol' do + expect(Spree::LocalizedNumber).to receive(:parse).with(price.price) + price.price = 19.99 + end + end + end + + describe '#variant' do + let(:price) { create(:price) } + subject(:variant) { price.variant } + before do + variant.deleted_at = Time.current + variant.save + end + it 'returns variants without adding the deleted_at where clause when unscoped' do + expect(price.reload.variant).to eq variant + end + end + + describe '#ensure_currency' do + let(:price) { create(:price) } + + context 'when currency is not already set' do + it 'sets currency to Spree::Config[:currency]' do + expect(price.currency).to eq Spree::Config[:currency] + end + end + + context 'when currency is already set and configuration changes' do + subject(:currency) { 'RS' } + before do + Spree::Config[:currency] = currency + price.save + end + it 'does not sets currency to Spree::Config[:currency]' do + expect(price.currency).not_to eq currency + end + end end end end diff --git a/core/spec/models/spree/shared/paranoia_examples.rb b/core/spec/models/spree/shared/paranoia_examples.rb new file mode 100644 index 00000000000..c06340af31b --- /dev/null +++ b/core/spec/models/spree/shared/paranoia_examples.rb @@ -0,0 +1,15 @@ +shared_examples_for 'a Paranoid model' do + + it { is_expected.to have_db_column(:deleted_at) } + + it { is_expected.to have_db_index(:deleted_at) } + + it 'adds a deleted_at where clause' do + expect(described_class.all.to_sql).to include("deleted_at") + end + + it 'skips adding the deleted_at where clause when unscoped' do + expect(described_class.unscoped.to_sql).not_to include("deleted_at") + end + +end diff --git a/core/spec/spec_helper.rb b/core/spec/spec_helper.rb index a53818eb212..0837e1d46ef 100644 --- a/core/spec/spec_helper.rb +++ b/core/spec/spec_helper.rb @@ -27,6 +27,7 @@ require 'ffaker' Dir["./spec/support/**/*.rb"].sort.each { |f| require f } +Dir["./spec/models/spree/shared/**/*.rb"].sort.each { |f| require f } if ENV["CHECK_TRANSLATIONS"] require "spree/testing_support/i18n" From c97cd6b8a856e284098fc566ca70e3f0af657a03 Mon Sep 17 00:00:00 2001 From: sawan gupta Date: Thu, 3 Mar 2016 14:02:27 +0530 Subject: [PATCH 2/3] rename AMOUNT to AMOUNT_LIMIT --- core/app/models/spree/price.rb | 6 +++--- core/spec/models/spree/price_spec.rb | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/app/models/spree/price.rb b/core/app/models/spree/price.rb index 760f2528eaa..7be24fe439f 100644 --- a/core/app/models/spree/price.rb +++ b/core/app/models/spree/price.rb @@ -4,7 +4,7 @@ class Price < Spree::Base acts_as_paranoid - AMOUNT = { + AMOUNT_LIMIT = { max: BigDecimal('99_999_999.99'), min: 0 } @@ -14,8 +14,8 @@ class Price < Spree::Base before_validation :ensure_currency validates :amount, allow_nil: true, numericality: { - greater_than_or_equal_to: AMOUNT[:min], - less_than_or_equal_to: AMOUNT[:max] + greater_than_or_equal_to: AMOUNT_LIMIT[:min], + less_than_or_equal_to: AMOUNT_LIMIT[:max] } extend DisplayMoney diff --git a/core/spec/models/spree/price_spec.rb b/core/spec/models/spree/price_spec.rb index f39ccdd109a..7d4945f3ed7 100644 --- a/core/spec/models/spree/price_spec.rb +++ b/core/spec/models/spree/price_spec.rb @@ -12,15 +12,15 @@ end describe 'Constants' do - describe 'MAXIMUM AMOUNT' do + describe 'AMOUNT_LIMIT[:max]' do it 'return 99999999.99' do - expect(Spree::Price::AMOUNT[:max]).to eq BigDecimal('99_999_999.99') + expect(Spree::Price::AMOUNT_LIMIT[:max]).to eq BigDecimal('99_999_999.99') end end - describe 'MINIMUM AMOUNT' do + describe 'AMOUNT_LIMIT[:min]' do it 'return 0' do - expect(Spree::Price::AMOUNT[:min]).to eq 0 + expect(Spree::Price::AMOUNT_LIMIT[:min]).to eq 0 end end end @@ -41,7 +41,7 @@ it { is_expected.to be_valid } end - context 'when the amount is less than #{Spree::Price::AMOUNT[:min]}' do + context 'when the amount is less than #{Spree::Price::AMOUNT_LIMIT[:min]}' do let(:amount) { -1 } it 'has 1 error_on' do @@ -49,24 +49,24 @@ end it 'populates errors' do subject.valid? - expect(subject.errors.messages[:amount].first).to eq "must be greater than or equal to #{Spree::Price::AMOUNT[:min]}" + expect(subject.errors.messages[:amount].first).to eq "must be greater than or equal to #{Spree::Price::AMOUNT_LIMIT[:min]}" end end context 'when the amount is greater than maximum amount' do - let(:amount) { Spree::Price::AMOUNT[:max] + 1 } + let(:amount) { Spree::Price::AMOUNT_LIMIT[:max] + 1 } it 'has 1 error_on' do expect(subject.error_on(:amount).size).to eq(1) end it 'populates errors' do subject.valid? - expect(subject.errors.messages[:amount].first).to eq "must be less than or equal to #{Spree::Price::AMOUNT[:max]}" + expect(subject.errors.messages[:amount].first).to eq "must be less than or equal to #{Spree::Price::AMOUNT_LIMIT[:max]}" end end context 'when the amount is between 0 and the maximum amount' do - let(:amount) { Spree::Price::AMOUNT[:max] } + let(:amount) { Spree::Price::AMOUNT_LIMIT[:max] } it { is_expected.to be_valid } end end From f19dc3f4b45644a2e8ef1a45d7bb9ed968c8807c Mon Sep 17 00:00:00 2001 From: sawan gupta Date: Mon, 21 Mar 2016 11:57:35 +0530 Subject: [PATCH 3/3] fix hound ci issues --- core/app/models/spree/price.rb | 2 +- core/spec/models/spree/price_spec.rb | 12 +++++++----- core/spec/models/spree/shared/paranoia_examples.rb | 2 -- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/app/models/spree/price.rb b/core/app/models/spree/price.rb index 7be24fe439f..50eef46e389 100644 --- a/core/app/models/spree/price.rb +++ b/core/app/models/spree/price.rb @@ -7,7 +7,7 @@ class Price < Spree::Base AMOUNT_LIMIT = { max: BigDecimal('99_999_999.99'), min: 0 - } + }.freeze belongs_to :variant, class_name: 'Spree::Variant', inverse_of: :prices, touch: true diff --git a/core/spec/models/spree/price_spec.rb b/core/spec/models/spree/price_spec.rb index 7d4945f3ed7..2ac65ad2c9d 100644 --- a/core/spec/models/spree/price_spec.rb +++ b/core/spec/models/spree/price_spec.rb @@ -28,7 +28,7 @@ describe 'association' do it do is_expected.to belong_to(:variant).class_name('Spree::Variant'). - inverse_of(:prices).touch(true) + inverse_of(:prices).touch(true) end end @@ -49,7 +49,8 @@ end it 'populates errors' do subject.valid? - expect(subject.errors.messages[:amount].first).to eq "must be greater than or equal to #{Spree::Price::AMOUNT_LIMIT[:min]}" + expect(subject.errors.messages[:amount].first). + to eq "must be greater than or equal to #{Spree::Price::AMOUNT_LIMIT[:min]}" end end @@ -61,7 +62,8 @@ end it 'populates errors' do subject.valid? - expect(subject.errors.messages[:amount].first).to eq "must be less than or equal to #{Spree::Price::AMOUNT_LIMIT[:max]}" + expect(subject.errors.messages[:amount].first). + to eq "must be less than or equal to #{Spree::Price::AMOUNT_LIMIT[:max]}" end end @@ -84,7 +86,6 @@ # Instance methods describe 'Instance Methods' do - describe '#amount=' do let(:price) { Spree::Price.new } let(:amount) { '3,0A0' } @@ -114,7 +115,8 @@ allow(variant).to receive(:tax_category).and_return(tax_category) expect(price).to receive(:default_zone).at_least(:once).and_return(default_zone) allow(price).to receive(:apply_foreign_vat?).and_return(true) - allow(price).to receive(:included_tax_amount).with(tax_zone: default_zone, tax_category: tax_category) { 0.19 } + allow(price).to receive(:included_tax_amount). + with(tax_zone: default_zone, tax_category: tax_category) { 0.19 } allow(price).to receive(:included_tax_amount).with(tax_zone: zone, tax_category: tax_category) { 0.25 } end diff --git a/core/spec/models/spree/shared/paranoia_examples.rb b/core/spec/models/spree/shared/paranoia_examples.rb index c06340af31b..1149faa2a57 100644 --- a/core/spec/models/spree/shared/paranoia_examples.rb +++ b/core/spec/models/spree/shared/paranoia_examples.rb @@ -1,5 +1,4 @@ shared_examples_for 'a Paranoid model' do - it { is_expected.to have_db_column(:deleted_at) } it { is_expected.to have_db_index(:deleted_at) } @@ -11,5 +10,4 @@ it 'skips adding the deleted_at where clause when unscoped' do expect(described_class.unscoped.to_sql).not_to include("deleted_at") end - end