diff options
author | Alessandro Desantis <desa.alessandro@gmail.com> | 2021-02-05 13:30:47 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-05 13:30:47 +0100 |
commit | 3a3657b79bd5d98025136da4b39751e6a43b7b9f (patch) | |
tree | b7a57b183641d64d05e5e70e281fd78cb5e37ebd /spec | |
parent | 69f0ca038b66d0ca36971405e51c0d3aa916cf19 (diff) | |
parent | 4717d24c0e7203210efe8c23b55467c3e728cdc5 (diff) |
Merge pull request #172 from solidusio-contrib/aldesantis/refactoring
Processor and Checkout refactoring
Diffstat (limited to 'spec')
23 files changed, 334 insertions, 851 deletions
diff --git a/spec/jobs/solidus_subscriptions/process_installment_job_spec.rb b/spec/jobs/solidus_subscriptions/process_installment_job_spec.rb new file mode 100644 index 0000000..4a33819 --- /dev/null +++ b/spec/jobs/solidus_subscriptions/process_installment_job_spec.rb @@ -0,0 +1,11 @@ +RSpec.describe SolidusSubscriptions::ProcessInstallmentJob do + it 'processes checkout for the installment' do + installment = build_stubbed(:installment) + checkout = instance_spy(SolidusSubscriptions::Checkout) + allow(SolidusSubscriptions::Checkout).to receive(:new).with(installment).and_return(checkout) + + described_class.perform_now(installment) + + expect(checkout).to have_received(:process) + end +end diff --git a/spec/jobs/solidus_subscriptions/process_installments_job_spec.rb b/spec/jobs/solidus_subscriptions/process_installments_job_spec.rb deleted file mode 100644 index 111fc05..0000000 --- a/spec/jobs/solidus_subscriptions/process_installments_job_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'spec_helper' - -RSpec.describe SolidusSubscriptions::ProcessInstallmentsJob do - let(:root_order) { create :completed_order_with_pending_payment } - let(:installments) do - traits = { - subscription_traits: [{ - user: root_order.user, - line_item_traits: [{ - spree_line_item: root_order.line_items.first - }] - }] - } - - create_list(:installment, 2, traits) - end - - describe '#perform' do - subject { described_class.new.perform(installments) } - - it 'processes the consolidated installment' do - expect_any_instance_of(SolidusSubscriptions::Checkout). - to receive(:process).once - - subject - end - end -end diff --git a/spec/lib/solidus_subscriptions/checkout_spec.rb b/spec/lib/solidus_subscriptions/checkout_spec.rb new file mode 100644 index 0000000..2a83d9b --- /dev/null +++ b/spec/lib/solidus_subscriptions/checkout_spec.rb @@ -0,0 +1,122 @@ +RSpec.describe SolidusSubscriptions::Checkout, :checkout do + context 'when the order can be created and paid' do + it 'creates and finalizes a new order for the installment' do + stub_spree_preferences(auto_capture: true) + installment = create(:installment, :actionable) + + order = described_class.new(installment).process + + expect(order).to be_complete + expect(order).to be_paid + end + + # rubocop:disable RSpec/MultipleExpectations + it 'copies basic information from the subscription' do + stub_spree_preferences(auto_capture: true) + installment = create(:installment, :actionable) + subscription = installment.subscription + + order = described_class.new(installment).process + + expect(order.ship_address.value_attributes).to eq(subscription.shipping_address_to_use.value_attributes) + expect(order.bill_address.value_attributes).to eq(subscription.billing_address_to_use.value_attributes) + expect(order.payments.first.payment_method).to eq(subscription.payment_method_to_use) + expect(order.payments.first.source).to eq(subscription.payment_source_to_use) + expect(order.user).to eq(subscription.user) + expect(order.email).to eq(subscription.user.email) + end + # rubocop:enable RSpec/MultipleExpectations + + it 'marks the order as a subscription order' do + stub_spree_preferences(auto_capture: true) + installment = create(:installment, :actionable) + subscription = installment.subscription + + order = described_class.new(installment).process + + expect(order.subscription).to eq(subscription) + expect(order.subscription_order).to eq(true) + end + + it 'matches the total on the subscription' do + stub_spree_preferences(auto_capture: true) + installment = create(:installment, :actionable) + subscription = installment.subscription + + order = described_class.new(installment).process + + expect(order.item_total).to eq(subscription.line_items.first.subscribable.price) + end + + it 'calls the success dispatcher' do + stub_spree_preferences(auto_capture: true) + installment = create(:installment, :actionable) + success_dispatcher = stub_dispatcher(SolidusSubscriptions::Dispatcher::SuccessDispatcher, installment) + + described_class.new(installment).process + + expect(success_dispatcher).to have_received(:dispatch) + end + end + + context 'when payment of the order fails' do + it 'calls the payment failed dispatcher' do + stub_spree_preferences(auto_capture: true) + installment = create(:installment, :actionable).tap do |i| + i.subscription.update!(payment_source: create(:credit_card, number: '4111123412341234')) + end + payment_failed_dispatcher = stub_dispatcher(SolidusSubscriptions::Dispatcher::PaymentFailedDispatcher, installment) + + described_class.new(installment).process + + expect(payment_failed_dispatcher).to have_received(:dispatch) + end + end + + context 'when an item is out of stock' do + it 'calls the out of stock dispatcher' do + stub_spree_preferences(auto_capture: true) + installment = create(:installment, :actionable).tap do |i| + i.subscription.line_items.first.subscribable.stock_items.each do |stock_item| + stock_item.update!(backorderable: false) + end + end + out_of_stock_dispatcher = stub_dispatcher(SolidusSubscriptions::Dispatcher::OutOfStockDispatcher, installment) + + described_class.new(installment).process + + expect(out_of_stock_dispatcher).to have_received(:dispatch) + end + end + + context 'when a generic transition error happens during checkout' do + it 'calls the failure dispatcher' do + stub_spree_preferences(auto_capture: true) + installment = create(:installment, :actionable) + failure_dispatcher = stub_dispatcher(SolidusSubscriptions::Dispatcher::FailureDispatcher, installment) + # rubocop:disable RSpec/AnyInstance + allow_any_instance_of(Spree::Order).to receive(:next!) + .and_raise(StateMachines::InvalidTransition.new( + Spree::Order.new, + Spree::Order.state_machines[:state], + :next, + )) + # rubocop:enable RSpec/AnyInstance + + described_class.new(installment).process + + expect(failure_dispatcher).to have_received(:dispatch) + end + end + + private + + def stub_dispatcher(klass, installment) + instance_spy(klass).tap do |dispatcher| + allow(klass).to receive(:new).with( + installment, + an_instance_of(Spree::Order) + ).and_return(dispatcher) + end + end +end diff --git a/spec/lib/solidus_subscriptions/dispatcher/failure_dispatcher_spec.rb b/spec/lib/solidus_subscriptions/dispatcher/failure_dispatcher_spec.rb new file mode 100644 index 0000000..f247237 --- /dev/null +++ b/spec/lib/solidus_subscriptions/dispatcher/failure_dispatcher_spec.rb @@ -0,0 +1,27 @@ +RSpec.describe SolidusSubscriptions::Dispatcher::FailureDispatcher do + describe '#dispatch' do + it 'marks the installment as failed' do + installment = instance_spy(SolidusSubscriptions::Installment) + order = create(:order_with_line_items) + + dispatcher = described_class.new(installment, order) + dispatcher.dispatch + + expect(installment).to have_received(:failed!).with(order) + end + + it 'cancels the order' do + if Spree.solidus_gem_version > Gem::Version.new('2.10') + skip 'Orders in `cart` state cannot be canceled starting from Solidus 2.11.' + end + + installment = instance_spy(SolidusSubscriptions::Installment) + order = create(:order_with_line_items) + + dispatcher = described_class.new(installment, order) + dispatcher.dispatch + + expect(order.state).to eq('canceled') + end + end +end diff --git a/spec/lib/solidus_subscriptions/dispatcher/out_of_stock_dispatcher_spec.rb b/spec/lib/solidus_subscriptions/dispatcher/out_of_stock_dispatcher_spec.rb new file mode 100644 index 0000000..abb8343 --- /dev/null +++ b/spec/lib/solidus_subscriptions/dispatcher/out_of_stock_dispatcher_spec.rb @@ -0,0 +1,13 @@ +RSpec.describe SolidusSubscriptions::Dispatcher::OutOfStockDispatcher do + describe '#dispatch' do + it 'marks the installment as out of stock' do + installment = instance_spy(SolidusSubscriptions::Installment) + order = build_stubbed(:order) + + dispatcher = described_class.new(installment, order) + dispatcher.dispatch + + expect(installment).to have_received(:out_of_stock) + end + end +end diff --git a/spec/lib/solidus_subscriptions/dispatcher/payment_failed_dispatcher_spec.rb b/spec/lib/solidus_subscriptions/dispatcher/payment_failed_dispatcher_spec.rb new file mode 100644 index 0000000..0a222d4 --- /dev/null +++ b/spec/lib/solidus_subscriptions/dispatcher/payment_failed_dispatcher_spec.rb @@ -0,0 +1,42 @@ +RSpec.describe SolidusSubscriptions::Dispatcher::PaymentFailedDispatcher do + describe '#dispatch' do + it 'marks the installment as payment_failed' do + installment = instance_spy(SolidusSubscriptions::Installment) + order = create(:order_with_line_items) + + dispatcher = described_class.new(installment, order) + dispatcher.dispatch + + expect(installment).to have_received(:payment_failed!).with(order) + end + + it 'cancels the order' do + if Spree.solidus_gem_version > Gem::Version.new('2.10') + skip 'Orders in `cart` state cannot be canceled starting from Solidus 2.11.' + end + + installment = instance_spy(SolidusSubscriptions::Installment) + order = create(:order_with_line_items) + + dispatcher = described_class.new(installment, order) + dispatcher.dispatch + + expect(order.state).to eq('canceled') + end + + it 'fires an installments_failed_payment event' do + stub_const('Spree::Event', class_spy(Spree::Event)) + installment = instance_spy(SolidusSubscriptions::Installment) + order = create(:order_with_line_items) + + dispatcher = described_class.new(installment, order) + dispatcher.dispatch + + expect(Spree::Event).to have_received(:fire).with( + 'solidus_subscriptions.installment_failed_payment', + installment: installment, + order: order, + ) + end + end +end diff --git a/spec/lib/solidus_subscriptions/dispatcher/success_dispatcher_spec.rb b/spec/lib/solidus_subscriptions/dispatcher/success_dispatcher_spec.rb new file mode 100644 index 0000000..6a71800 --- /dev/null +++ b/spec/lib/solidus_subscriptions/dispatcher/success_dispatcher_spec.rb @@ -0,0 +1,28 @@ +RSpec.describe SolidusSubscriptions::Dispatcher::SuccessDispatcher do + describe '#dispatch' do + it 'marks the installment as success' do + installment = instance_spy(SolidusSubscriptions::Installment) + order = create(:order_with_line_items) + + dispatcher = described_class.new(installment, order) + dispatcher.dispatch + + expect(installment).to have_received(:success!).with(order) + end + + it 'fires an installments_succeeded event' do + stub_const('Spree::Event', class_spy(Spree::Event)) + installment = instance_spy(SolidusSubscriptions::Installment) + order = create(:order_with_line_items) + + dispatcher = described_class.new(installment, order) + dispatcher.dispatch + + expect(Spree::Event).to have_received(:fire).with( + 'solidus_subscriptions.installment_succeeded', + installment: installment, + order: order, + ) + end + end +end diff --git a/spec/lib/solidus_subscriptions/processor_spec.rb b/spec/lib/solidus_subscriptions/processor_spec.rb index d3bb268..e82c0e9 100644 --- a/spec/lib/solidus_subscriptions/processor_spec.rb +++ b/spec/lib/solidus_subscriptions/processor_spec.rb @@ -1,156 +1,124 @@ -require 'spec_helper' - RSpec.describe SolidusSubscriptions::Processor, :checkout do - include ActiveJob::TestHelper - around { |e| perform_enqueued_jobs { e.run } } - - let!(:user) { create(:user, :subscription_user) } - let!(:credit_card) { - card = create(:credit_card, gateway_customer_profile_id: 'BGS-123', user: user) - wallet_payment_source = user.wallet.add(card) - user.wallet.default_wallet_payment_source = wallet_payment_source - user.save - card - } - - let!(:actionable_subscriptions) { create_list(:subscription, 2, :actionable, user: user) } - let!(:pending_cancellation_subscriptions) do - create_list(:subscription, 2, :pending_cancellation, user: user) - end + shared_examples 'processes the subscription' do + it 'resets the successive_skip_count' do + subscription + subscription.update_columns(successive_skip_count: 3) - let!(:expiring_subscriptions) do - create_list( - :subscription, - 2, - :actionable, - :with_line_item, - user: user, - end_date: Date.current.tomorrow, - ) - end + described_class.run - let!(:future_subscriptions) { create_list(:subscription, 2, :not_actionable) } - let!(:canceled_subscriptions) { create_list(:subscription, 2, :canceled) } - let!(:inactive) { create_list(:subscription, 2, :inactive) } - - let!(:successful_installments) { create_list :installment, 2, :success } - let!(:failed_installments) do - create_list( - :installment, - 2, - :failed, - subscription_traits: [{ user: user }] - ) - end + expect(subscription.reload.successive_skip_count).to eq(0) + end - # all subscriptions and previously failed installments belong to the same user - let(:expected_orders) { 1 } + context 'with clear_past_installments set to true' do + it 'clears any past unfulfilled installments' do + stub_config(clear_past_installments: true) + subscription + installment = create(:installment, :actionable, subscription: subscription) - shared_examples 'a subscription order' do - let(:order_variant_ids) { Spree::Order.last.variant_ids } - let(:expected_ids) do - subs = actionable_subscriptions + pending_cancellation_subscriptions + expiring_subscriptions - subs_ids = subs.flat_map { |s| s.line_items.pluck(:subscribable_id) } - inst_ids = failed_installments.flat_map { |i| i.subscription.line_items.pluck(:subscribable_id) } + described_class.run - subs_ids + inst_ids + expect(installment.reload.actionable_date).to eq(nil) + end end - it 'creates the correct number of orders' do - expect { subject }.to change { Spree::Order.complete.count }.by expected_orders - end + context 'with clear_past_installments set to false' do + it 'does not clear any past unfulfilled installments' do + stub_config(clear_past_installments: false) + subscription + installment = create(:installment, :actionable, subscription: subscription) - it 'creates the correct order' do - subject - expect(order_variant_ids).to match_array expected_ids + described_class.run + + expect(installment.reload.actionable_date).not_to be_nil + end end - it 'advances the subscription actionable dates' do - subscription = actionable_subscriptions.first + it 'creates a new installment' do + subscription - current_date = subscription.actionable_date - expected_date = subscription.next_actionable_date + described_class.run - expect { subject }. - to change { subscription.reload.actionable_date }. - from(current_date).to(expected_date) + expect(subscription.installments.count).to eq(1) end - it 'cancels subscriptions pending cancellation' do - subs = pending_cancellation_subscriptions.first - expect { subject }. - to change { subs.reload.state }. - from('pending_cancellation').to('canceled') - end + it 'schedules the newly created installment for processing' do + subscription + + described_class.run - it 'resets the subscription successive skip count' do - subs = pending_cancellation_subscriptions.first - expect { subject }. - to change { subs.reload.state }. - from('pending_cancellation').to('canceled') + expect(SolidusSubscriptions::ProcessInstallmentJob).to have_been_enqueued + .with(subscription.installments.last) end - it 'deactivates expired subscriptions' do - sub = expiring_subscriptions.first + it 'schedules other actionable installments for processing' do + actionable_installment = create(:installment, :actionable) - expect { subject }. - to change { sub.reload.state }. - from('active').to('inactive') + described_class.run + + expect(SolidusSubscriptions::ProcessInstallmentJob).to have_been_enqueued + .with(actionable_installment) end + end - context 'the subscriptions have different shipping addresses' do - let!(:sub_to_different_address) do - create(:subscription, :actionable, :with_shipping_address, user: user) - end + shared_examples 'schedules the subscription for reprocessing' do + it 'advances the actionable_date' do + subscription + subscription.update_columns(interval_length: 1, interval_units: 'week') + old_actionable_date = subscription.actionable_date - it 'creates an order for each shipping address' do - expect { subject }.to change { Spree::Order.complete.count }.by 2 - end + described_class.run + + expect(subscription.reload.actionable_date.to_date).to eq((old_actionable_date + 1.week).to_date) end + end - context "when the config 'clear_past_installments' is enabled" do - it 'clears the past failed installments' do - stub_config(clear_past_installments: true) + context 'with a regular subscription' do + let(:subscription) { create(:subscription, :actionable) } - subject + include_examples 'processes the subscription' + include_examples 'schedules the subscription for reprocessing' + end - failed_installments.each do |fi| - expect(fi.reload.actionable_date).to eq(nil) - end - end + context 'with a subscription that is pending deactivation' do + let(:subscription) do + create( + :subscription, + :actionable, + interval_units: 'week', + interval_length: 2, + end_date: 3.days.from_now, + ) end - context 'the subscriptions have different billing addresses' do - let!(:sub_to_different_address) do - create(:subscription, :actionable, :with_billing_address, user: user) - end + include_examples 'processes the subscription' + include_examples 'schedules the subscription for reprocessing' - it 'creates an order for each billing address' do - expect { subject }.to change { Spree::Order.complete.count }.by 2 - end - end + it 'deactivates the subscription' do + subscription - context 'the subscription is cancelled with pending installments' do - let!(:cancelled_installment) do - installment = create(:installment, actionable_date: Time.zone.today) - installment.subscription.cancel! - end + described_class.run - it 'does not process the installment' do - expect { subject }.to change { Spree::Order.complete.count }.by expected_orders - end + expect(subscription.reload.state).to eq('inactive') end end - describe '.run' do - subject { described_class.run } + context 'with a subscription that is pending cancellation' do + let(:subscription) do + create( + :subscription, + :actionable, + :pending_cancellation, + ) + end - it_behaves_like 'a subscription order' - end + include_examples 'processes the subscription' + + it 'cancels the subscription' do + subscription - describe '#build_jobs' do - subject { described_class.new([user]).build_jobs } + described_class.run - it_behaves_like 'a subscription order' + expect(subscription.reload.state).to eq('canceled') + end end end diff --git a/spec/services/solidus_subscriptions/subscription_generator_spec.rb b/spec/lib/solidus_subscriptions/subscription_generator_spec.rb index b7d73b8..b7d73b8 100644 --- a/spec/services/solidus_subscriptions/subscription_generator_spec.rb +++ b/spec/lib/solidus_subscriptions/subscription_generator_spec.rb diff --git a/spec/services/solidus_subscriptions/subscription_order_promotion_rule_spec.rb b/spec/lib/solidus_subscriptions/subscription_order_promotion_rule_spec.rb index bacbef2..bacbef2 100644 --- a/spec/services/solidus_subscriptions/subscription_order_promotion_rule_spec.rb +++ b/spec/lib/solidus_subscriptions/subscription_order_promotion_rule_spec.rb diff --git a/spec/services/solidus_subscriptions/subscription_promotion_rule_spec.rb b/spec/lib/solidus_subscriptions/subscription_promotion_rule_spec.rb index f4c65cc..f4c65cc 100644 --- a/spec/services/solidus_subscriptions/subscription_promotion_rule_spec.rb +++ b/spec/lib/solidus_subscriptions/subscription_promotion_rule_spec.rb diff --git a/spec/models/solidus_subscriptions/installment_spec.rb b/spec/models/solidus_subscriptions/installment_spec.rb index 4e4831e..399a7e6 100644 --- a/spec/models/solidus_subscriptions/installment_spec.rb +++ b/spec/models/solidus_subscriptions/installment_spec.rb @@ -5,15 +5,6 @@ RSpec.describe SolidusSubscriptions::Installment, type: :model do it { is_expected.to validate_presence_of :subscription } - describe '#line_item_builder' do - subject { installment.line_item_builder } - - let(:line_items) { installment.subscription.line_items } - - it { is_expected.to be_a SolidusSubscriptions::LineItemBuilder } - it { is_expected.to have_attributes(subscription_line_items: line_items) } - end - describe '#out_of_stock' do subject { installment.out_of_stock } diff --git a/spec/models/solidus_subscriptions/line_item_spec.rb b/spec/models/solidus_subscriptions/line_item_spec.rb index ad80384..aaa24a5 100644 --- a/spec/models/solidus_subscriptions/line_item_spec.rb +++ b/spec/models/solidus_subscriptions/line_item_spec.rb @@ -24,90 +24,4 @@ RSpec.describe SolidusSubscriptions::LineItem, type: :model do expect(subject.from_now).to eq Date.parse("2016-10-22") end end - - describe '#as_json' do - subject { line_item.as_json } - - around { |e| Timecop.freeze { e.run } } - - let(:line_item) { create(:subscription_line_item, :with_subscription) } - - let(:expected_hash) do - hash = { - "id" => line_item.id, - "spree_line_item_id" => line_item.spree_line_item.id, - "subscription_id" => line_item.subscription_id, - "quantity" => line_item.quantity, - "end_date" => line_item.end_date, - "subscribable_id" => line_item.subscribable_id, - "created_at" => line_item.created_at, - "updated_at" => line_item.updated_at, - "interval_units" => line_item.interval_units, - "interval_length" => line_item.interval_length - } - Rails.gem_version >= Gem::Version.new('6.0.0') ? hash.as_json : hash - end - - it 'includes the attribute values' do - expect(subject).to match a_hash_including(expected_hash) - end - - it 'includes the dummy lineitem' do - expect(subject).to have_key('dummy_line_item') - end - end - - describe '#dummy_line_item' do - subject { line_item.dummy_line_item } - - let(:line_item) { create(:subscription_line_item, :with_subscription) } - - it { is_expected.to be_a Spree::LineItem } - it { is_expected.to be_frozen } - - it 'has the correct variant' do - expect(subject.variant_id).to eq line_item.subscribable_id - end - - context 'with no spree line item' do - let(:line_item) { create(:subscription_line_item, :with_subscription, spree_line_item: nil) } - - it { is_expected.to be_a Spree::LineItem } - it { is_expected.to be_frozen } - - it 'has the correct variant' do - expect(subject.variant_id).to eq line_item.subscribable_id - end - end - - context 'with an associated subscription' do - context 'the associated subscription has a shipping address' do - let(:line_item) do - create(:subscription_line_item, :with_subscription, subscription_traits: [:with_shipping_address]) - end - - it 'uses the subscription shipping address' do - expect(subject.order.ship_address).to eq line_item.subscription.shipping_address - end - - it 'uses the subscription users billing address' do - expect(subject.order.bill_address).to eq line_item.subscription.user.bill_address - end - end - - context 'the associated subscription has a billing address' do - let(:line_item) do - create(:subscription_line_item, :with_subscription, subscription_traits: [:with_billing_address]) - end - - it 'uses the subscription users shipping address' do - expect(subject.order.ship_address).to eq line_item.subscription.user.ship_address - end - - it 'uses the subscription billing address' do - expect(subject.order.bill_address).to eq line_item.subscription.billing_address - end - end - end - end end diff --git a/spec/models/solidus_subscriptions/subscription_spec.rb b/spec/models/solidus_subscriptions/subscription_spec.rb index 5d855db..f305580 100644 --- a/spec/models/solidus_subscriptions/subscription_spec.rb +++ b/spec/models/solidus_subscriptions/subscription_spec.rb @@ -348,16 +348,6 @@ RSpec.describe SolidusSubscriptions::Subscription, type: :model do end end - describe '#line_item_builder' do - subject { subscription.line_item_builder } - - let(:subscription) { create :subscription, :with_line_item } - let(:line_items) { subscription.line_items } - - it { is_expected.to be_a SolidusSubscriptions::LineItemBuilder } - it { is_expected.to have_attributes(subscription_line_items: line_items) } - end - describe '#processing_state' do subject { subscription.processing_state } diff --git a/spec/services/solidus_subscriptions/checkout_spec.rb b/spec/services/solidus_subscriptions/checkout_spec.rb deleted file mode 100644 index 4b408dc..0000000 --- a/spec/services/solidus_subscriptions/checkout_spec.rb +++ /dev/null @@ -1,389 +0,0 @@ -require 'spec_helper' - -RSpec.describe SolidusSubscriptions::Checkout do - let(:checkout) { described_class.new(installments) } - let(:root_order) { create :completed_order_with_pending_payment, user: subscription_user } - let(:subscription_user) { create(:user, :subscription_user) } - let!(:credit_card) { - card = create(:credit_card, user: subscription_user, gateway_customer_profile_id: 'BGS-123', payment_method: payment_method) - wallet_payment_source = subscription_user.wallet.add(card) - subscription_user.wallet.default_wallet_payment_source = wallet_payment_source - card - } - let(:payment_method) { create(:payment_method) } - let(:installments) { create_list(:installment, 2, installment_traits) } - - let(:installment_traits) do - { - subscription_traits: [{ - user: subscription_user, - line_item_traits: [{ - spree_line_item: root_order.line_items.first - }] - }] - } - end - - before do - Spree::Variant.all.each { |v| v.update(subscribable: true) } - end - - context 'initialized with installments belonging to multiple users' do - subject { checkout } - - let(:installments) { build_stubbed_list :installment, 2 } - - it 'raises an error' do - expect { subject }. - to raise_error SolidusSubscriptions::UserMismatchError, /must have the same user/ - end - end - - describe '#process', :checkout do - subject(:order) { checkout.process } - - let(:subscription_line_item) { installments.first.subscription.line_items.first } - - shared_examples 'a completed checkout' do - it { is_expected.to be_a Spree::Order } - - let(:total) { 49.98 } - let(:quantity) { installments.length } - - it 'has the correct number of line items' do - count = order.line_items.length - expect(count).to eq quantity - end - - it 'the line items have the correct values' do - line_item = order.line_items.first - expect(line_item).to have_attributes( - quantity: subscription_line_item.quantity, - variant_id: subscription_line_item.subscribable_id - ) - end - - it 'has a shipment' do - expect(order.shipments).to be_present - end - - it 'has a payment' do - expect(order.payments.valid).to be_present - end - - it 'has the correct totals' do - expect(order).to have_attributes( - total: total, - shipment_total: 10 - ) - end - - it { is_expected.to be_complete } - - it 'associates the order to the installment detail' do - order - installment_orders = installments.flat_map { |i| i.details.map(&:order) }.compact - expect(installment_orders).to all eq order - end - - it 'creates an installment detail for each installment' do - expect { subject }. - to change { SolidusSubscriptions::InstallmentDetail.count }. - by(installments.count) - end - end - - context 'no line items get added to the cart' do - before do - installments - Spree::StockItem.update_all(count_on_hand: 0, backorderable: false) - end - - it 'creates two failed installment details' do - expect { order }. - to change { SolidusSubscriptions::InstallmentDetail.count }. - by(installments.length) - - details = SolidusSubscriptions::InstallmentDetail.last(installments.length) - expect(details).to all be_failed - end - - it { is_expected.to be_nil } - - it 'creates no order' do - expect { subject }.not_to change { Spree::Order.count } - end - end - - if Gem::Specification.find_by_name('solidus').version >= Gem::Version.new('1.4.0') - context 'Altered checkout flow' do - before do - @old_checkout_flow = Spree::Order.checkout_flow - Spree::Order.remove_checkout_step(:delivery) - end - - after do - Spree::Order.checkout_flow(&@old_checkout_flow) - end - - it 'has a payment' do - expect(order.payments.valid).to be_present - end - - it 'has the correct totals' do - expect(order).to have_attributes( - total: 39.98, - shipment_total: 0 - ) - end - - it { is_expected.to be_complete } - end - end - - context 'the variant is out of stock' do - let(:subscription_line_item) { installments.last.subscription.line_items.first } - let(:expected_date) { Time.zone.today + SolidusSubscriptions.configuration.reprocessing_interval } - - # Remove stock for 1 variant in the consolidated installment - before do - subscribable_id = installments.first.subscription.line_items.first.subscribable_id - variant = Spree::Variant.find(subscribable_id) - variant.stock_items.update_all(count_on_hand: 0, backorderable: false) - end - - it 'creates a failed installment detail' do - subject - detail = installments.first.details.last - - expect(detail).not_to be_successful - expect(detail.message). - to eq I18n.t('solidus_subscriptions.installment_details.out_of_stock') - end - - it 'removes the installment from the list of installments' do - expect { subject }. - to change { checkout.installments.length }. - by(-1) - end - - it_behaves_like 'a completed checkout' do - let(:total) { 29.99 } - let(:quantity) { installments.length - 1 } - end - end - - context 'the payment fails' do - let(:payment_method) { create(:payment_method) } - let!(:credit_card) { - card = create(:credit_card, user: checkout.user, payment_method: payment_method) - wallet_payment_source = checkout.user.wallet.add(card) - checkout.user.wallet.default_wallet_payment_source = wallet_payment_source - card - } - let(:expected_date) { Time.zone.today + SolidusSubscriptions.configuration.reprocessing_interval } - - it { is_expected.to be_nil } - - it 'marks all of the installments as failed' do - subject - - details = installments.map do |installments| - installments.details.reload.last - end - - expect(details).to all be_failed && have_attributes( - message: I18n.t('solidus_subscriptions.installment_details.payment_failed') - ) - end - - it 'marks the installment to be reprocessed' do - subject - actionable_dates = installments.map do |installment| - installment.reload.actionable_date - end - - expect(actionable_dates).to all eq expected_date - end - end - - context 'when there are cart promotions' do - let!(:promo) do - create( - :promotion, - :with_item_total_rule, - :with_order_adjustment, - promo_params - ) - end - - # Promotions require the :apply_automatically flag to be auto applied in - # solidus versions greater than 1.0 - let(:promo_params) do - {}.tap do |params| - if Spree::Promotion.new.respond_to?(:apply_automatically) - params[:apply_automatically] = true - end - end - end - - it_behaves_like 'a completed checkout' do - let(:total) { 39.98 } - end - - it 'applies the correct adjustments' do - expect(subject.adjustments).to be_present - end - end - - context 'there is an aribitrary failure' do - let(:expected_date) { Time.zone.today + SolidusSubscriptions.configuration.reprocessing_interval } - - before do - allow(checkout).to receive(:populate).and_raise('arbitrary runtime error') - end - - it 'advances the installment actionable dates', :aggregate_failures do - expect { subject }.to raise_error('arbitrary runtime error') - - actionable_dates = installments.map do |installment| - installment.reload.actionable_date - end - - expect(actionable_dates).to all eq expected_date - end - end - - context 'the user has store credit' do - let!(:store_credit) { create :store_credit, user: subscription_user } - let!(:store_credit_payment_method) { create :store_credit_payment_method } - - it_behaves_like 'a completed checkout' - - it 'has a valid store credit payment' do - expect(order.payments.valid.store_credits).to be_present - end - end - - context 'the subscription has a shipping address' do - let(:installment_traits) do - { - subscription_traits: [{ - shipping_address: shipping_address, - user: subscription_user, - line_item_traits: [{ spree_line_item: root_order.line_items.first }] - }] - } - end - let(:shipping_address) { create :address } - - it_behaves_like 'a completed checkout' - - it 'ships to the subscription address' do - expect(subject.ship_address).to eq shipping_address - end - end - - context 'the subscription has a billing address' do - let(:installment_traits) do - { - subscription_traits: [{ - billing_address: billing_address, - user: subscription_user, - line_item_traits: [{ spree_line_item: root_order.line_items.first }] - }] - } - end - let(:billing_address) { create :address } - - it_behaves_like 'a completed checkout' - - it 'bills to the subscription address' do - expect(subject.bill_address).to eq billing_address - end - end - - context 'the subscription has a payment method' do - let(:installment_traits) do - { - subscription_traits: [{ - payment_method: payment_method, - user: subscription_user, - line_item_traits: [{ spree_line_item: root_order.line_items.first }] - }] - } - end - let(:payment_method) { create :check_payment_method } - - it_behaves_like 'a completed checkout' - - it 'pays with the payment method' do - expect(subject.payments.valid.first.payment_method).to eq payment_method - end - end - - context 'the subscription has a payment method and a source' do - let(:installment_traits) do - { - subscription_traits: [{ - payment_method: payment_method, - payment_source: payment_source, - user: subscription_user, - line_item_traits: [{ spree_line_item: root_order.line_items.first }] - }] - } - end - let(:payment_source) { create :credit_card, payment_method: payment_method, user: subscription_user } - let(:payment_method) { create :credit_card_payment_method } - - it_behaves_like 'a completed checkout' - - it 'pays with the payment method' do - expect(subject.payments.valid.first.payment_method).to eq payment_method - end - - it 'pays with the payment source' do - expect(subject.payments.valid.first.source).to eq payment_source - end - end - - context 'there are multiple associated subscritpion line items' do - it_behaves_like 'a completed checkout' do - let(:quantity) { subscription_line_items.length } - end - - let(:installments) { create_list(:installment, 1, installment_traits) } - let(:subscription_line_items) { create_list(:subscription_line_item, 2, quantity: 1) } - - let(:installment_traits) do - { - subscription_traits: [{ - user: subscription_user, - line_items: subscription_line_items - }] - } - end - end - end - - describe '#order' do - subject { checkout.order } - - let(:user) { installments.first.subscription.user } - - it { is_expected.to be_a Spree::Order } - - it 'has the correct attributes' do - expect(subject).to have_attributes( - user: user, - email: user.email, - store: installments.first.subscription.store - ) - end - - it 'is the same instance any time its called' do - order = checkout.order - expect(subject).to equal order - end - end -end diff --git a/spec/services/solidus_subscriptions/dispatcher_spec.rb b/spec/services/solidus_subscriptions/dispatcher_spec.rb deleted file mode 100644 index 49c3f4b..0000000 --- a/spec/services/solidus_subscriptions/dispatcher_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -RSpec.describe SolidusSubscriptions::Dispatcher do - describe '#dispatch' do - it 'raises a NotImplementedError' do - dispatcher = described_class.new([]) - - expect { - dispatcher.dispatch - }.to raise_error(NotImplementedError) - end - end -end diff --git a/spec/services/solidus_subscriptions/failure_dispatcher_spec.rb b/spec/services/solidus_subscriptions/failure_dispatcher_spec.rb deleted file mode 100644 index a7c18ea..0000000 --- a/spec/services/solidus_subscriptions/failure_dispatcher_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -RSpec.describe SolidusSubscriptions::FailureDispatcher do - describe '#dispatch' do - it 'marks all the installments as failed' do - installments = Array.new(2) { instance_spy(SolidusSubscriptions::Installment) } - order = create(:order_with_line_items) - - dispatcher = described_class.new(installments, order) - dispatcher.dispatch - - expect(installments).to all(have_received(:failed!).with(order).once) - end - - it 'cancels the order' do - if Spree.solidus_gem_version > Gem::Version.new('2.10') - skip 'Orders in `cart` state cannot be canceled starting from Solidus 2.11.' - end - - installments = Array.new(2) { instance_spy(SolidusSubscriptions::Installment) } - order = create(:order_with_line_items) - - dispatcher = described_class.new(installments, order) - dispatcher.dispatch - - expect(order.state).to eq('canceled') - end - end -end diff --git a/spec/services/solidus_subscriptions/line_item_builder_spec.rb b/spec/services/solidus_subscriptions/line_item_builder_spec.rb deleted file mode 100644 index d1e041c..0000000 --- a/spec/services/solidus_subscriptions/line_item_builder_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'spec_helper' - -RSpec.describe SolidusSubscriptions::LineItemBuilder do - let(:builder) { described_class.new subscription_line_items } - let(:variant) { create(:variant, subscribable: true) } - let(:subscription_line_item) { subscription_line_items.first } - let(:subscription_line_items) do - build_stubbed_list(:subscription_line_item, 1, subscribable_id: variant.id) - end - - describe '#spree_line_items' do - subject { builder.spree_line_items } - - let(:expected_attributes) do - { - variant_id: subscription_line_item.subscribable_id, - quantity: subscription_line_item.quantity - } - end - - it { is_expected.to be_a Array } - - it 'contains a line item with the correct attributes' do - expect(subject.first).to have_attributes expected_attributes - end - - context 'the variant is out of stock' do - before { create :stock_location, backorderable_default: false } - - it { is_expected.to be_empty } - end - end -end diff --git a/spec/services/solidus_subscriptions/order_builder_spec.rb b/spec/services/solidus_subscriptions/order_builder_spec.rb deleted file mode 100644 index 3463bd1..0000000 --- a/spec/services/solidus_subscriptions/order_builder_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'spec_helper' - -RSpec.describe SolidusSubscriptions::OrderBuilder do - let(:builder) { described_class.new order } - - describe '#add_line_items' do - subject { builder.add_line_items([line_item]) } - - let(:variant) { create :variant, subscribable: true } - let(:order) do - create :order, line_items_attributes: line_items_attributes - end - - let(:line_item) { create(:line_item, quantity: 4, variant: variant) } - - context 'the line item doesnt already exist on the order' do - let(:line_items_attributes) { [] } - - it 'adds a new line item to the order' do - expect { subject }. - to change { order.line_items.count }. - from(0).to(1) - end - - it 'has a line item with the correct values' do - subject - line_item = order.line_items.last - - expect(line_item).to have_attributes( - variant_id: variant.id, - quantity: line_item.quantity - ) - end - end - - context 'the line item already exists on the order' do - let(:line_items_attributes) do - [{ - variant: variant, - quantity: 3 - }] - end - - it 'increases the correct line item by the correct amount' do - existing_line_item = order.line_items.first - - expect { subject }. - to change { existing_line_item.reload.quantity }. - by(line_item.quantity) - end - end - end -end diff --git a/spec/services/solidus_subscriptions/out_of_stock_dispatcher_spec.rb b/spec/services/solidus_subscriptions/out_of_stock_dispatcher_spec.rb deleted file mode 100644 index 6f3825c..0000000 --- a/spec/services/solidus_subscriptions/out_of_stock_dispatcher_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -RSpec.describe SolidusSubscriptions::OutOfStockDispatcher do - describe '#dispatch' do - it 'marks all the installments as out of stock' do - installments = Array.new(2) { instance_spy(SolidusSubscriptions::Installment) } - - dispatcher = described_class.new(installments) - dispatcher.dispatch - - expect(installments).to all(have_received(:out_of_stock).once) - end - end -end diff --git a/spec/services/solidus_subscriptions/payment_failed_dispatcher_spec.rb b/spec/services/solidus_subscriptions/payment_failed_dispatcher_spec.rb deleted file mode 100644 index a6a8a0c..0000000 --- a/spec/services/solidus_subscriptions/payment_failed_dispatcher_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -RSpec.describe SolidusSubscriptions::PaymentFailedDispatcher do - describe '#dispatch' do - it 'marks all the installments as payment_failed' do - installments = Array.new(2) { instance_spy(SolidusSubscriptions::Installment) } - order = create(:order_with_line_items) - - dispatcher = described_class.new(installments, order) - dispatcher.dispatch - - expect(installments).to all(have_received(:payment_failed!).with(order).once) - end - - it 'cancels the order' do - if Spree.solidus_gem_version > Gem::Version.new('2.10') - skip 'Orders in `cart` state cannot be canceled starting from Solidus 2.11.' - end - - installments = Array.new(2) { instance_spy(SolidusSubscriptions::Installment) } - order = create(:order_with_line_items) - - dispatcher = described_class.new(installments, order) - dispatcher.dispatch - - expect(order.state).to eq('canceled') - end - - it 'fires an installments_failed_payment event' do - stub_const('Spree::Event', class_spy(Spree::Event)) - installments = Array.new(2) { instance_spy(SolidusSubscriptions::Installment) } - order = create(:order_with_line_items) - - dispatcher = described_class.new(installments, order) - dispatcher.dispatch - - expect(Spree::Event).to have_received(:fire).with( - 'solidus_subscriptions.installments_failed_payment', - installments: installments, - order: order, - ) - end - end -end diff --git a/spec/services/solidus_subscriptions/success_dispatcher_spec.rb b/spec/services/solidus_subscriptions/success_dispatcher_spec.rb deleted file mode 100644 index ce41638..0000000 --- a/spec/services/solidus_subscriptions/success_dispatcher_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -RSpec.describe SolidusSubscriptions::SuccessDispatcher do - describe '#dispatch' do - it 'marks all the installments as success' do - installments = Array.new(2) { instance_spy(SolidusSubscriptions::Installment) } - order = create(:order_with_line_items) - - dispatcher = described_class.new(installments, order) - dispatcher.dispatch - - expect(installments).to all(have_received(:success!).with(order).once) - end - - it 'fires an installments_succeeded event' do - stub_const('Spree::Event', class_spy(Spree::Event)) - installments = Array.new(2) { instance_spy(SolidusSubscriptions::Installment) } - order = create(:order_with_line_items) - - dispatcher = described_class.new(installments, order) - dispatcher.dispatch - - expect(Spree::Event).to have_received(:fire).with( - 'solidus_subscriptions.installments_succeeded', - installments: installments, - order: order, - ) - end - end -end diff --git a/spec/subscribers/solidus_subscriptions/churn_buster_subscriber_spec.rb b/spec/subscribers/solidus_subscriptions/churn_buster_subscriber_spec.rb index 572913b..11ada2c 100644 --- a/spec/subscribers/solidus_subscriptions/churn_buster_subscriber_spec.rb +++ b/spec/subscribers/solidus_subscriptions/churn_buster_subscriber_spec.rb @@ -29,10 +29,10 @@ RSpec.describe SolidusSubscriptions::ChurnBusterSubscriber do allow(SolidusSubscriptions).to receive(:churn_buster).and_return(churn_buster) order = build_stubbed(:order) - installments = build_list(:installment, 2) + installment = build_stubbed(:installment) Spree::Event.fire( - 'solidus_subscriptions.installments_succeeded', - installments: installments, + 'solidus_subscriptions.installment_succeeded', + installment: installment, order: order, ) @@ -46,10 +46,10 @@ RSpec.describe SolidusSubscriptions::ChurnBusterSubscriber do allow(SolidusSubscriptions).to receive(:churn_buster).and_return(churn_buster) order = build_stubbed(:order) - installments = build_list(:installment, 2) + installment = build_stubbed(:installment) Spree::Event.fire( - 'solidus_subscriptions.installments_failed_payment', - installments: installments, + 'solidus_subscriptions.installment_failed_payment', + installment: installment, order: order, ) |