summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlessandro Desantis <desa.alessandro@gmail.com>2020-11-19 13:14:38 +0100
committerAlessandro Desantis <desa.alessandro@gmail.com>2021-01-30 15:23:41 +0100
commit16dd27dab051bfd7fd8edd7721391e3bd80a62ea (patch)
treeb5cb7d1e4f90c8c227fcb64abb49d5f3a0b9f895
parent0a0659d1150a7df8f0ca23e4876672e95a103f51 (diff)
Streamline and simplify `SolidusSubscriptions::Checkout`
This service object contained a lot of indirection and took on too many responsibilities. The new version is much more streamlined and the flow of operations should be much clearer.
-rw-r--r--app/jobs/solidus_subscriptions/process_installment_job.rb2
-rw-r--r--app/services/solidus_subscriptions/checkout.rb170
-rw-r--r--app/services/solidus_subscriptions/order_builder.rb42
-rw-r--r--app/services/solidus_subscriptions/user_mismatch_error.rb17
-rw-r--r--spec/services/solidus_subscriptions/checkout_spec.rb431
-rw-r--r--spec/services/solidus_subscriptions/order_builder_spec.rb53
6 files changed, 127 insertions, 588 deletions
diff --git a/app/jobs/solidus_subscriptions/process_installment_job.rb b/app/jobs/solidus_subscriptions/process_installment_job.rb
index 6beeec6..17eb446 100644
--- a/app/jobs/solidus_subscriptions/process_installment_job.rb
+++ b/app/jobs/solidus_subscriptions/process_installment_job.rb
@@ -5,7 +5,7 @@ module SolidusSubscriptions
queue_as SolidusSubscriptions.configuration.processing_queue
def perform(installment)
- Checkout.new([installment]).process
+ Checkout.new(installment).process
end
end
end
diff --git a/app/services/solidus_subscriptions/checkout.rb b/app/services/solidus_subscriptions/checkout.rb
index c40849a..e348547 100644
--- a/app/services/solidus_subscriptions/checkout.rb
+++ b/app/services/solidus_subscriptions/checkout.rb
@@ -1,155 +1,73 @@
# frozen_string_literal: true
-# This class takes a collection of installments and populates a new spree
-# order with the correct contents based on the subscriptions associated to the
-# intallments. This is to group together subscriptions being
-# processed on the same day for a specific user
module SolidusSubscriptions
class Checkout
- # @return [Array<Installment>] The collection of installments to be used
- # when generating a new order
- attr_reader :installments
+ attr_reader :installment
- delegate :user, to: :subscription
-
- # Get a new instance of a Checkout
- #
- # @param installments [Array<Installment>] The collection of installments
- # to be used when generating a new order
- def initialize(installments)
- @installments = installments
- raise UserMismatchError.new(installments) if different_owners?
+ def initialize(installment)
+ @installment = installment
end
- # Generate a new Spree::Order based on the information associated to the
- # installments
- #
- # @return [Spree::Order]
def process
- populate
-
- # Installments are removed and set for future processing if they are
- # out of stock. If there are no line items left there is nothing to do
- return if installments.empty?
-
- if checkout
- SolidusSubscriptions.configuration.success_dispatcher_class.new(installments, order).dispatch
- return order
+ order = create_order
+
+ begin
+ populate_order(order)
+ finalize_order(order)
+
+ SolidusSubscriptions.configuration.success_dispatcher_class.new([installment], order).dispatch
+ rescue StateMachines::InvalidTransition
+ if order.payments.any?(&:failed?)
+ SolidusSubscriptions.configuration.payment_failed_dispatcher_class.new([installment], order).dispatch
+ else
+ SolidusSubscriptions.configuration.failure_dispatcher_class.new([installment], order).dispatch
+ end
+ rescue ::Spree::Order::InsufficientStock
+ SolidusSubscriptions.configuration.out_of_stock_dispatcher_class.new([installment], order).dispatch
end
- # A new order will only have 1 payment that we created
- if order.payments.any?(&:failed?)
- SolidusSubscriptions.configuration.payment_failed_dispatcher_class.new(installments, order).dispatch
- installments.clear
- nil
- end
- ensure
- # Any installments that failed to be processed will be reprocessed
- unfulfilled_installments = installments.select(&:unfulfilled?)
- if unfulfilled_installments.any?
- SolidusSubscriptions.configuration.failure_dispatcher_class.
- new(unfulfilled_installments, order).dispatch
- end
+ order
end
- # The order fulfilling the consolidated installment
- #
- # @return [Spree::Order]
- def order
- @order ||= ::Spree::Order.create(
- user: user,
- email: user.email,
- store: subscription.store || ::Spree::Store.default,
+ private
+
+ def create_order
+ ::Spree::Order.create(
+ user: installment.subscription.user,
+ email: installment.subscription.user.email,
+ store: installment.subscription.store || ::Spree::Store.default,
subscription_order: true,
- subscription: subscription
+ subscription: installment.subscription
)
end
- private
+ def populate_order(order)
+ installment.subscription.line_items.each do |line_item|
+ order.contents.add(line_item.subscribable, line_item.quantity)
+ end
+ end
- def checkout
+ def finalize_order(order)
+ ::Spree::PromotionHandler::Cart.new(order).activate
order.recalculate
- apply_promotions
order.checkout_steps[0...-1].each do
case order.state
- when "address"
- order.ship_address = ship_address
- order.bill_address = bill_address
- when "payment"
- create_payment
+ when 'address'
+ order.ship_address = installment.subscription.shipping_address_to_use
+ order.bill_address = installment.subscription.billing_address_to_use
+ when 'payment'
+ order.payments.create(
+ payment_method: installment.subscription.payment_method_to_use,
+ source: installment.subscription.payment_source_to_use,
+ amount: order.total,
+ )
end
order.next!
end
- # Do this as a separate "quiet" transition so that it returns true or
- # false rather than raising a failed transition error
- order.complete
- end
-
- def populate
- unfulfilled_installments = []
-
- order_line_items = installments.flat_map do |installment|
- line_items = installment.line_item_builder.spree_line_items
-
- unfulfilled_installments.push(installment) if line_items.empty?
-
- line_items
- end
-
- # Remove installments which had no stock from the active list
- # They will be reprocessed later
- @installments -= unfulfilled_installments
- if unfulfilled_installments.any?
- SolidusSubscriptions.configuration.out_of_stock_dispatcher_class.new(unfulfilled_installments).dispatch
- end
-
- return if installments.empty?
-
- order_builder.add_line_items(order_line_items)
- end
-
- def order_builder
- @order_builder ||= OrderBuilder.new(order)
- end
-
- def subscription
- installments.first.subscription
- end
-
- def ship_address
- subscription.shipping_address_to_use
- end
-
- def bill_address
- subscription.billing_address_to_use
- end
-
- def payment_source
- subscription.payment_source_to_use
- end
-
- def payment_method
- subscription.payment_method_to_use
- end
-
- def create_payment
- order.payments.create(
- source: payment_source,
- amount: order.total,
- payment_method: payment_method,
- )
- end
-
- def apply_promotions
- ::Spree::PromotionHandler::Cart.new(order).activate
- order.updater.update # reload totals
- end
-
- def different_owners?
- installments.map { |i| i.subscription.user }.uniq.length > 1
+ order.complete!
end
end
end
diff --git a/app/services/solidus_subscriptions/order_builder.rb b/app/services/solidus_subscriptions/order_builder.rb
deleted file mode 100644
index a577e98..0000000
--- a/app/services/solidus_subscriptions/order_builder.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-# This class is responsible for adding line items to order without going
-# through order contents.
-module SolidusSubscriptions
- class OrderBuilder
- attr_reader :order
-
- # Get a new instance of an OrderBuilder
- #
- # @param order [Spree::Order] The order to be built
- #
- # @return [SolidusSubscriptions::OrderBuilder]
- def initialize(order)
- @order = order
- end
-
- # Add line items to an order. If the order already
- # has a line item for a given variant_id, update the quantity. Otherwise
- # add the line item to the order.
- #
- # @param items [Array<Spree::LineItem>] The order to add the line item to
- # @return [Array<Spree::LineItem] The collection that was passed in
- def add_line_items(items)
- items.map { |item| add_item_to_order(item) }
- end
-
- private
-
- def add_item_to_order(new_item)
- line_item = order.line_items.detect do |li|
- li.variant_id == new_item.variant_id
- end
-
- if line_item
- line_item.increment!(:quantity, new_item.quantity)
- else
- order.line_items << new_item
- end
- end
- end
-end
diff --git a/app/services/solidus_subscriptions/user_mismatch_error.rb b/app/services/solidus_subscriptions/user_mismatch_error.rb
deleted file mode 100644
index 1d227ca..0000000
--- a/app/services/solidus_subscriptions/user_mismatch_error.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-module SolidusSubscriptions
- class UserMismatchError < StandardError
- def initialize(installments)
- @installments = installments
- end
-
- def to_s
- <<-MSG.squish
- Installments must have the same user to be processed as a consolidated
- installment. Could not process installments:
- #{@installments.map(&:id).join(', ')}
- MSG
- end
- end
-end
diff --git a/spec/services/solidus_subscriptions/checkout_spec.rb b/spec/services/solidus_subscriptions/checkout_spec.rb
index 4b408dc..f35b8c0 100644
--- a/spec/services/solidus_subscriptions/checkout_spec.rb
+++ b/spec/services/solidus_subscriptions/checkout_spec.rb
@@ -1,389 +1,122 @@
-require 'spec_helper'
+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)
-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) }
+ order = described_class.new(installment).process
- 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/
+ expect(order).to be_complete
+ expect(order).to be_paid
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
+ # 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
- it { is_expected.to be_complete }
+ order = described_class.new(installment).process
- 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
+ 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
- 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)
+ it 'marks the order as a subscription order' do
+ stub_spree_preferences(auto_capture: true)
+ installment = create(:installment, :actionable)
+ subscription = installment.subscription
- details = SolidusSubscriptions::InstallmentDetail.last(installments.length)
- expect(details).to all be_failed
- end
+ order = described_class.new(installment).process
- it { is_expected.to be_nil }
-
- it 'creates no order' do
- expect { subject }.not_to change { Spree::Order.count }
- end
+ expect(order.subscription).to eq(subscription)
+ expect(order.subscription_order).to eq(true)
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
+ it 'matches the total on the subscription' do
+ stub_spree_preferences(auto_capture: true)
+ installment = create(:installment, :actionable)
+ subscription = installment.subscription
- after do
- Spree::Order.checkout_flow(&@old_checkout_flow)
- end
+ order = described_class.new(installment).process
- 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
+ expect(order.item_total).to eq(subscription.line_items.first.subscribable.price)
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 'calls the success dispatcher' do
+ stub_spree_preferences(auto_capture: true)
+ installment = create(:installment, :actionable)
+ success_dispatcher = stub_dispatcher(SolidusSubscriptions::Dispatcher::SuccessDispatcher, installment)
- it 'marks the installment to be reprocessed' do
- subject
- actionable_dates = installments.map do |installment|
- installment.reload.actionable_date
- end
+ described_class.new(installment).process
- expect(actionable_dates).to all eq expected_date
- end
+ expect(success_dispatcher).to have_received(:dispatch)
end
+ end
- context 'when there are cart promotions' do
- let!(:promo) do
- create(
- :promotion,
- :with_item_total_rule,
- :with_order_adjustment,
- promo_params
- )
+ 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)
- # 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
+ described_class.new(installment).process
- 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
+ expect(payment_failed_dispatcher).to have_received(:dispatch)
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
+ 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
-
- 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 }
+ out_of_stock_dispatcher = stub_dispatcher(SolidusSubscriptions::Dispatcher::OutOfStockDispatcher, installment)
- it_behaves_like 'a completed checkout'
+ described_class.new(installment).process
- 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
+ expect(out_of_stock_dispatcher).to have_received(:dispatch)
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
+ 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
- let(:installments) { create_list(:installment, 1, installment_traits) }
- let(:subscription_line_items) { create_list(:subscription_line_item, 2, quantity: 1) }
+ described_class.new(installment).process
- let(:installment_traits) do
- {
- subscription_traits: [{
- user: subscription_user,
- line_items: subscription_line_items
- }]
- }
- end
+ expect(failure_dispatcher).to have_received(:dispatch)
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
+ private
- it 'is the same instance any time its called' do
- order = checkout.order
- expect(subject).to equal order
+ 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/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