summaryrefslogtreecommitdiff
path: root/spec/lib/solidus_subscriptions/checkout_spec.rb
blob: 25cbcf4007859e2be0d6806a6e21e5b10a20ed1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# frozen_string_literal: true

RSpec.describe SolidusSubscriptions::Checkout, :checkout do
  context 'when the order can be created and paid' do
    # rubocop:disable RSpec/MultipleExpectations
    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

    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.currency).to eq(subscription.currency)
      expect(order.user).to eq(subscription.user)
      expect(order.email).to eq(subscription.user.email)
    end

    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
    # rubocop:enable RSpec/MultipleExpectations

    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