solidus_easypost 1.0.3 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +41 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.github_changelog_generator +2 -0
  6. data/.gitignore +21 -0
  7. data/.rspec +2 -0
  8. data/.rubocop.yml +7 -0
  9. data/.rubocop_todo.yml +36 -0
  10. data/CHANGELOG.md +113 -0
  11. data/Gemfile +33 -0
  12. data/LICENSE +26 -0
  13. data/README.md +194 -0
  14. data/Rakefile +6 -0
  15. data/app/controllers/spree/admin/postage_labels_controller.rb +20 -0
  16. data/app/decorators/models/solidus_easypost/spree/carton_decorator.rb +38 -0
  17. data/app/decorators/models/solidus_easypost/spree/shipment_decorator.rb +47 -0
  18. data/app/decorators/models/solidus_easypost/spree/shipping_rate_decorator.rb +13 -0
  19. data/app/models/solidus_easypost/parcel_dimension.rb +34 -0
  20. data/app/models/solidus_easypost/return_authorization.rb +27 -0
  21. data/app/overrides/spree/admin/orders/_shipment/add_postage_label.html.erb.deface +10 -0
  22. data/bin/console +17 -0
  23. data/bin/rails +7 -0
  24. data/bin/rails-engine +13 -0
  25. data/bin/rails-sandbox +16 -0
  26. data/bin/rake +7 -0
  27. data/bin/sandbox +86 -0
  28. data/bin/setup +8 -0
  29. data/config/initializers/webhooks.rb +7 -0
  30. data/config/locales/en.yml +8 -0
  31. data/config/routes.rb +9 -0
  32. data/db/migrate/20140515024440_add_easy_post_fields_to_shipping_rate.rb +9 -0
  33. data/db/migrate/20201025110912_add_tracker_id_to_cartons.rb +6 -0
  34. data/lib/generators/solidus_easypost/install/install_generator.rb +28 -0
  35. data/lib/generators/solidus_easypost/install/templates/initializer.rb +26 -0
  36. data/lib/solidus_easypost/address_builder.rb +45 -0
  37. data/lib/solidus_easypost/calculator/base_dimension_calculator.rb +28 -0
  38. data/lib/solidus_easypost/calculator/weight_dimension_calculator.rb +22 -0
  39. data/lib/solidus_easypost/configuration.rb +34 -0
  40. data/lib/solidus_easypost/engine.rb +19 -0
  41. data/lib/solidus_easypost/errors/unknown_partial_resource_error.rb +11 -0
  42. data/lib/solidus_easypost/estimator.rb +37 -0
  43. data/lib/solidus_easypost/parcel_builder.rb +27 -0
  44. data/lib/solidus_easypost/shipment_builder.rb +32 -0
  45. data/lib/solidus_easypost/shipping_method_selector.rb +17 -0
  46. data/lib/solidus_easypost/shipping_rate_calculator.rb +9 -0
  47. data/lib/solidus_easypost/testing_support/factories/address_factory.rb +10 -0
  48. data/lib/solidus_easypost/testing_support/factories/product_factory.rb +7 -0
  49. data/lib/solidus_easypost/testing_support/factories/shipment_factory.rb +30 -0
  50. data/lib/solidus_easypost/testing_support/factories/shipping_method_factory.rb +8 -0
  51. data/lib/solidus_easypost/testing_support/factories/stock_location_factory.rb +10 -0
  52. data/lib/solidus_easypost/testing_support/factories/variant_factory.rb +7 -0
  53. data/lib/solidus_easypost/testing_support/factories.rb +3 -0
  54. data/lib/solidus_easypost/tracker_webhook_handler.rb +14 -0
  55. data/lib/solidus_easypost/version.rb +5 -0
  56. data/lib/solidus_easypost.rb +32 -0
  57. data/solidus_easypost.gemspec +41 -0
  58. data/spec/cassettes/address_builder/from_address.yml +65 -0
  59. data/spec/cassettes/address_builder/from_stock_location.yml +65 -0
  60. data/spec/cassettes/estimator.yml +269 -0
  61. data/spec/cassettes/integration/checkout.yml +377 -0
  62. data/spec/cassettes/integration/order_shipping/with_purchase_labels.yml +373 -0
  63. data/spec/cassettes/integration/order_shipping/without_purchase_labels.yml +251 -0
  64. data/spec/cassettes/parcel_builder/from_package.yml +63 -0
  65. data/spec/cassettes/parcel_builder/from_return_authorization.yml +63 -0
  66. data/spec/cassettes/postage_labels/show.yml +72 -0
  67. data/spec/cassettes/return_authorization.yml +310 -0
  68. data/spec/cassettes/shipment_builder/from_package.yml +251 -0
  69. data/spec/cassettes/shipment_builder/from_return_authorization.yml +251 -0
  70. data/spec/cassettes/shipment_builder/from_shipment.yml +250 -0
  71. data/spec/controllers/spree/admin/postage_labels_controller_spec.rb +18 -0
  72. data/spec/features/admin/postage_labels_spec.rb +18 -0
  73. data/spec/integration/checkout_spec.rb +45 -0
  74. data/spec/integration/order_shipping_spec.rb +33 -0
  75. data/spec/models/solidus_easypost/parcel_dimension_spec.rb +80 -0
  76. data/spec/models/solidus_easypost/return_authorization_spec.rb +17 -0
  77. data/spec/models/spree/carton_spec.rb +57 -0
  78. data/spec/models/spree/shipment_spec.rb +69 -0
  79. data/spec/models/spree/shipping_rate_spec.rb +23 -0
  80. data/spec/solidus_easypost/address_builder_spec.rb +17 -0
  81. data/spec/solidus_easypost/calculator/weight_dimension_calculator_spec.rb +39 -0
  82. data/spec/solidus_easypost/estimator_spec.rb +52 -0
  83. data/spec/solidus_easypost/parcel_builder_spec.rb +113 -0
  84. data/spec/solidus_easypost/shipment_builder_spec.rb +28 -0
  85. data/spec/solidus_easypost/shipping_method_selector_spec.rb +33 -0
  86. data/spec/solidus_easypost/shipping_rate_calculator_spec.rb +12 -0
  87. data/spec/solidus_easypost/tracker_webhook_handler_spec.rb +58 -0
  88. data/spec/solidus_easypost_spec.rb +19 -0
  89. data/spec/spec_helper.rb +31 -0
  90. data/spec/support/easypost.rb +5 -0
  91. data/spec/support/factory_bot.rb +3 -0
  92. data/spec/support/helpers/api_stubs.rb +40 -0
  93. data/spec/support/helpers/configuration.rb +28 -0
  94. data/spec/support/helpers/shipping_methods.rb +26 -0
  95. data/spec/support/solidus.rb +1 -0
  96. data/spec/support/vcr.rb +12 -0
  97. metadata +170 -142
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe SolidusEasypost::ParcelDimension do
6
+ describe '.new' do
7
+ subject(:instance) { described_class.new(params) }
8
+
9
+ let(:params) do
10
+ { height: 3 }
11
+ end
12
+
13
+ context 'when the weight is not passed' do
14
+ let(:params) do
15
+ { height: 3 }
16
+ end
17
+
18
+ it 'raises an argument error exception' do
19
+ expect {
20
+ instance
21
+ }.to raise_error(ArgumentError)
22
+ end
23
+ end
24
+
25
+ context 'when the passed weight is zero' do
26
+ let(:params) do
27
+ { height: 3, weight: 0 }
28
+ end
29
+
30
+ it 'raises an argument error exception' do
31
+ expect {
32
+ instance
33
+ }.to raise_error(ArgumentError)
34
+ end
35
+ end
36
+ end
37
+
38
+ describe '#to_h' do
39
+ subject(:instance_hash) { described_class.new(params).to_h }
40
+
41
+ context 'when the params contains zero values' do
42
+ let(:params) do
43
+ { weight: 3, width: 0, height: 0, unknown: -1 }
44
+ end
45
+
46
+ it 'returns the correct parcel dimension hash' do
47
+ expect(instance_hash).to eq({
48
+ weight: 3
49
+ })
50
+ end
51
+ end
52
+
53
+ context 'when the params contains the wrong params' do
54
+ let(:params) do
55
+ { weight: 3, unknown: -1, another: 11 }
56
+ end
57
+
58
+ it 'returns the correct parcel dimension hash' do
59
+ expect(instance_hash).to eq({
60
+ weight: 3
61
+ })
62
+ end
63
+ end
64
+
65
+ context 'when the params contains the correct params' do
66
+ let(:params) do
67
+ { weight: 3, width: 1, depth: 6, height: 11 }
68
+ end
69
+
70
+ it 'returns the correct parcel dimension hash' do
71
+ expect(instance_hash).to eq({
72
+ height: 11,
73
+ weight: 3,
74
+ width: 1,
75
+ length: 6,
76
+ })
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe SolidusEasypost::ReturnAuthorization, vcr: { cassette_name: 'return_authorization' } do
6
+ describe '#return_label' do
7
+ it 'returns a valid return label' do
8
+ return_authorization = create(:return_item).return_authorization
9
+
10
+ easypost_return_authorization = described_class.new(return_authorization)
11
+ selected_easypost_rate = easypost_return_authorization.easypost_shipment.rates.first
12
+ return_label = easypost_return_authorization.return_label(selected_easypost_rate)
13
+
14
+ expect(return_label).to have_attributes(object: 'PostageLabel')
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ RSpec.describe Spree::Carton do
2
+ describe '.create' do
3
+ context 'when track_all_cartons is true' do
4
+ it 'tracks the package automatically' do
5
+ stub_easypost_config(track_all_cartons: true)
6
+ tracker = instance_double(EasyPost::Tracker, id: 'trk_test')
7
+ allow(EasyPost::Tracker).to receive(:create).and_return(tracker)
8
+
9
+ carton = create(:carton)
10
+
11
+ expect(carton.easy_post_tracker_id).to eq('trk_test')
12
+ end
13
+ end
14
+
15
+ context 'when track_all_cartons is false' do
16
+ it 'does not track all packages automatically' do
17
+ stub_easypost_config(track_all_cartons: false)
18
+
19
+ carton = create(:carton)
20
+
21
+ expect(carton.easy_post_tracker_id).to eq(nil)
22
+ end
23
+ end
24
+ end
25
+
26
+ describe '#easypost_tracker' do
27
+ context 'when a tracker was already created' do
28
+ it 'returns the existing tracker' do
29
+ carton = create(:carton, easy_post_tracker_id: 'trk_test')
30
+ tracker = instance_double(EasyPost::Tracker)
31
+ allow(EasyPost::Tracker).to receive(:retrieve).with('trk_test').and_return(tracker)
32
+
33
+ expect(carton.easypost_tracker).to eq(tracker)
34
+ end
35
+ end
36
+
37
+ context 'when a tracker was not created' do
38
+ it 'creates a new tracker' do
39
+ carton = create(:carton, tracking: 'TESTTRACKING', shipping_method: create(:shipping_method, carrier: 'FedEx'))
40
+ tracker = instance_double(EasyPost::Tracker, id: 'trk_test')
41
+ allow(EasyPost::Tracker).to receive(:create).with(tracking_code: 'TESTTRACKING', carrier: 'FedEx').and_return(tracker)
42
+
43
+ expect(carton.easypost_tracker).to eq(tracker)
44
+ end
45
+
46
+ it "sets the tracker's ID on the carton" do
47
+ carton = create(:carton)
48
+ tracker = instance_double(EasyPost::Tracker, id: 'trk_test')
49
+ allow(EasyPost::Tracker).to receive(:create).and_return(tracker)
50
+
51
+ carton.easypost_tracker
52
+
53
+ expect(carton.easy_post_tracker_id).to eq('trk_test')
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Spree::Shipment do
6
+ describe '#easypost_shipment' do
7
+ context 'when no shipping rate was selected' do
8
+ it 'returns nil' do
9
+ shipment = create(:shipment)
10
+
11
+ expect(shipment.easypost_shipment).to be_nil
12
+ end
13
+ end
14
+
15
+ context 'when a shipping rate was selected' do
16
+ it 'returns the shipment associated with the shipping rate' do
17
+ easypost_shipment = stub_easypost_shipment
18
+ shipment = create(
19
+ :shipment,
20
+ :with_easypost,
21
+ easypost_shipment_id: easypost_shipment.id,
22
+ )
23
+
24
+ expect(shipment.easypost_shipment).to eq(easypost_shipment)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#ship!' do
30
+ context 'when purchase_labels is true' do
31
+ it 'buys the selected rate' do
32
+ stub_easypost_config(purchase_labels: true)
33
+ easypost_shipment = stub_easypost_shipment
34
+ selected_easypost_rate = easypost_shipment.rates.first
35
+
36
+ shipment = create(
37
+ :shipment,
38
+ :with_easypost,
39
+ state: 'ready',
40
+ easypost_shipment_id: easypost_shipment.id,
41
+ easypost_rate_id: selected_easypost_rate.id,
42
+ )
43
+ shipment.ship!
44
+
45
+ expect(easypost_shipment).to have_received(:buy).with(selected_easypost_rate)
46
+ end
47
+ end
48
+
49
+ context 'when purchase_labels is false' do
50
+ it 'does not buy rates automatically' do
51
+ stub_easypost_config(purchase_labels: false)
52
+ easypost_shipment = stub_easypost_shipment
53
+ selected_easypost_rate = easypost_shipment.rates.first
54
+
55
+ shipment = create(
56
+ :shipment,
57
+ :with_easypost,
58
+ state: 'ready',
59
+ easypost_shipment_id: easypost_shipment.id,
60
+ easypost_rate_id: selected_easypost_rate.id,
61
+ )
62
+
63
+ shipment.ship!
64
+
65
+ expect(easypost_shipment).not_to have_received(:buy)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Spree::ShippingRate do
6
+ describe '#name' do
7
+ context 'when the shipping rate has its own name' do
8
+ it 'returns the name on the shipping rate' do
9
+ shipping_rate = build_stubbed(:shipping_rate, name: 'USPS Express')
10
+
11
+ expect(shipping_rate.name).to eq('USPS Express')
12
+ end
13
+ end
14
+
15
+ context 'when the shipping rate does not have its own name' do
16
+ it 'returns the name on the shipping method' do
17
+ shipping_rate = build_stubbed(:shipping_rate, name: nil)
18
+
19
+ expect(shipping_rate.name).to eq(shipping_rate.shipping_method.name)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ RSpec.describe SolidusEasypost::AddressBuilder do
2
+ describe '.from_address', vcr: { cassette_name: 'address_builder/from_address' } do
3
+ it 'builds an address with the correct attributes' do
4
+ address = described_class.from_address(build_stubbed(:address))
5
+
6
+ expect(address).to have_attributes(object: 'Address')
7
+ end
8
+ end
9
+
10
+ describe '.from_stock_location', vcr: { cassette_name: 'address_builder/from_stock_location' } do
11
+ it 'builds an address with the correct attributes' do
12
+ address = described_class.from_stock_location(create(:stock_location))
13
+
14
+ expect(address).to have_attributes(object: 'Address')
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe SolidusEasypost::Calculator::WeightDimensionCalculator do
4
+ describe '#compute' do
5
+ subject(:compute) { described_class.new.compute(resource) }
6
+
7
+ context 'when a wrong resource is passed' do
8
+ let(:resource) { create(:shipment) }
9
+
10
+ it 'raises an unknown partial resource error' do
11
+ expect { compute }.to raise_error(SolidusEasypost::Errors::UnknownPartialResourceError)
12
+ end
13
+ end
14
+
15
+ context 'when a Spree::Stock::Package is passed' do
16
+ let(:resource) { create(:shipment).to_package }
17
+
18
+ before { allow(SolidusEasypost::ParcelDimension).to receive(:new) }
19
+
20
+ it 'build a parcel dimension' do
21
+ compute
22
+
23
+ expect(SolidusEasypost::ParcelDimension).to have_received(:new).with({ weight: 10.to_f })
24
+ end
25
+ end
26
+
27
+ context 'when a SolidusEasypost::ReturnAuthorization is passed' do
28
+ let(:resource) { SolidusEasypost::ReturnAuthorization.new(create(:return_authorization)) }
29
+
30
+ before { allow(SolidusEasypost::ParcelDimension).to receive(:new) }
31
+
32
+ it 'build a parcel dimension' do
33
+ compute
34
+
35
+ expect(SolidusEasypost::ParcelDimension).to have_received(:new).with({ weight: 0.to_f })
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe SolidusEasypost::Estimator, vcr: { cassette_name: 'estimator' } do
6
+ describe '#shipping_rates' do
7
+ context 'when the shipping methods are available to users' do
8
+ it 'returns the shipping rates' do
9
+ stub_shipping_method_selector(available_to_users: true)
10
+
11
+ rates = described_class.new.shipping_rates(create(:shipment).to_package)
12
+
13
+ hash = {
14
+ "USPS Express" => 22.74,
15
+ "USPS First" => 3.82,
16
+ "USPS ParcelSelect" => 6.85,
17
+ "USPS Priority" => 6.95,
18
+ }
19
+
20
+ expect(rates.sort_by(&:name).map { |r| [r.name, r.cost] }.to_h).to eq(hash)
21
+ end
22
+ end
23
+
24
+ context 'when the shipping methods are not available to users' do
25
+ it 'returns no rates' do
26
+ stub_shipping_method_selector(available_to_users: false)
27
+
28
+ rates = described_class.new.shipping_rates(create(:shipment).to_package)
29
+
30
+ expect(rates).to be_empty
31
+ end
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def stub_shipping_method_selector(available_to_users:)
38
+ shipping_method_selector = Class.new.tap do |klass|
39
+ klass.define_method(:shipping_method_for) do |rate|
40
+ Spree::ShippingMethod.new(
41
+ name: "#{rate.carrier} #{rate.service}",
42
+ available_to_users: available_to_users,
43
+ )
44
+ end
45
+ end
46
+
47
+ stub_const('FakeShippingMethodSelector', shipping_method_selector)
48
+
49
+ allow(SolidusEasypost.configuration).to receive(:shipping_method_selector_class)
50
+ .and_return(FakeShippingMethodSelector)
51
+ end
52
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe SolidusEasypost::ParcelBuilder do
4
+ describe '.from_package', vcr: { cassette_name: 'parcel_builder/from_package' } do
5
+ let(:shipment) { create(:shipment) }
6
+ let(:package) { shipment.to_package }
7
+ let(:parcel_dimension_calculator) { instance_spy('SolidusEasypost.configuration.parcel_dimension_calculator_class') }
8
+ let(:parcel_dimension) { instance_spy('SolidusEasypost::ParcelDimension') }
9
+
10
+ before do
11
+ allow(SolidusEasypost.configuration.parcel_dimension_calculator_class)
12
+ .to receive(:new)
13
+ .and_return(parcel_dimension_calculator)
14
+
15
+ allow(parcel_dimension_calculator).to receive(:compute).and_return(parcel_dimension)
16
+ allow(parcel_dimension).to receive(:to_h).and_return(dimension_hash)
17
+ allow(EasyPost::Parcel).to receive(:create).and_call_original
18
+ end
19
+
20
+ context 'when there is only the weight set' do
21
+ let(:dimension_hash) { { weight: 10.to_f } }
22
+
23
+ it 'builds a parcel with the correct attributes' do
24
+ parcel = described_class.from_package(package)
25
+
26
+ expect(parcel_dimension_calculator)
27
+ .to have_received(:compute)
28
+ .with(package)
29
+
30
+ expect(EasyPost::Parcel)
31
+ .to have_received(:create)
32
+ .with({ weight: 10.to_f })
33
+
34
+ expect(parcel).to have_attributes(object: 'Parcel')
35
+ end
36
+ end
37
+
38
+ context 'when all the properties are set' do
39
+ let(:dimension_hash) do
40
+ { weight: 10.to_f, height: 2.to_f, width: 3.to_f, depth: 4.to_f }
41
+ end
42
+
43
+ it 'builds a parcel with the correct attributes' do
44
+ parcel = described_class.from_package(package)
45
+
46
+ expect(parcel_dimension_calculator)
47
+ .to have_received(:compute)
48
+ .with(package)
49
+
50
+ expect(EasyPost::Parcel)
51
+ .to have_received(:create)
52
+ .with({ weight: 10.to_f, height: 2.to_f, width: 3.to_f, depth: 4.to_f })
53
+
54
+ expect(parcel).to have_attributes(object: 'Parcel')
55
+ end
56
+ end
57
+ end
58
+
59
+ describe '.from_return_authorization', vcr: { cassette_name: 'parcel_builder/from_return_authorization' } do
60
+ let(:return_item) { create(:return_item) }
61
+ let(:return_authorization) { return_item.return_authorization }
62
+ let(:parcel_dimension_calculator) { instance_spy('SolidusEasypost.configuration.parcel_dimension_calculator_class') }
63
+ let(:parcel_dimension) { instance_spy('SolidusEasypost::ParcelDimension') }
64
+
65
+ before do
66
+ allow(SolidusEasypost.configuration.parcel_dimension_calculator_class)
67
+ .to receive(:new)
68
+ .and_return(parcel_dimension_calculator)
69
+
70
+ allow(parcel_dimension_calculator).to receive(:compute).and_return(parcel_dimension)
71
+ allow(parcel_dimension).to receive(:to_h).and_return(dimension_hash)
72
+ allow(EasyPost::Parcel).to receive(:create).and_call_original
73
+ end
74
+
75
+ context 'when there is only the weight set' do
76
+ let(:dimension_hash) { { weight: 10.to_f } }
77
+
78
+ it 'builds a parcel with the correct attributes' do
79
+ parcel = described_class.from_return_authorization(return_authorization)
80
+
81
+ expect(parcel_dimension_calculator)
82
+ .to have_received(:compute)
83
+ .with(return_authorization)
84
+
85
+ expect(EasyPost::Parcel)
86
+ .to have_received(:create)
87
+ .with({ weight: 10.to_f })
88
+
89
+ expect(parcel).to have_attributes(object: 'Parcel')
90
+ end
91
+ end
92
+
93
+ context 'when all the properties are set' do
94
+ let(:dimension_hash) do
95
+ { weight: 10.to_f, height: 2.to_f, width: 3.to_f, depth: 4.to_f }
96
+ end
97
+
98
+ it 'builds a parcel with the correct attributes' do
99
+ parcel = described_class.from_return_authorization(return_authorization)
100
+
101
+ expect(parcel_dimension_calculator)
102
+ .to have_received(:compute)
103
+ .with(return_authorization)
104
+
105
+ expect(EasyPost::Parcel)
106
+ .to have_received(:create)
107
+ .with({ weight: 10.to_f, height: 2.to_f, width: 3.to_f, depth: 4.to_f })
108
+
109
+ expect(parcel).to have_attributes(object: 'Parcel')
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe SolidusEasypost::ShipmentBuilder do
4
+ describe '.from_package', vcr: { cassette_name: 'shipment_builder/from_package' } do
5
+ it 'builds a shipment with the correct attributes' do
6
+ shipment = described_class.from_package(create(:shipment).to_package)
7
+
8
+ expect(shipment).to have_attributes(object: 'Shipment')
9
+ end
10
+ end
11
+
12
+ describe '.from_shipment', vcr: { cassette_name: 'shipment_builder/from_shipment' } do
13
+ it 'builds a shipment with the correct attributes' do
14
+ shipment = described_class.from_shipment(create(:shipment))
15
+
16
+ expect(shipment).to have_attributes(object: 'Shipment')
17
+ end
18
+ end
19
+
20
+ describe '.from_return_authorization', vcr: { cassette_name: 'shipment_builder/from_return_authorization' } do
21
+ it 'builds a shipment with the correct attributes' do
22
+ solidus_return_authorization = create(:return_item).return_authorization
23
+ shipment = described_class.from_return_authorization(SolidusEasypost::ReturnAuthorization.new(solidus_return_authorization))
24
+
25
+ expect(shipment).to have_attributes(object: 'Shipment')
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ RSpec.describe SolidusEasypost::ShippingMethodSelector do
2
+ describe '#shipping_method_for' do
3
+ context 'when a shipping method for the given carrier and service exists' do
4
+ it 'returns the existing shipping method' do
5
+ shipping_method = create(:shipping_method, carrier: 'USPS', service_level: 'Express')
6
+ easypost_rate = EasyPost::Rate.construct_from('carrier' => 'USPS', 'service' => 'Express')
7
+
8
+ selector = described_class.new
9
+ selected_shipping_method = selector.shipping_method_for(easypost_rate)
10
+
11
+ expect(selected_shipping_method).to eq(shipping_method)
12
+ end
13
+ end
14
+
15
+ context 'when a shipping method for the given carrier and service does not exist' do
16
+ it 'creates a new shipping method' do
17
+ shipping_category = create(:shipping_category)
18
+ easypost_rate = EasyPost::Rate.construct_from('carrier' => 'USPS', 'service' => 'Express')
19
+
20
+ selector = described_class.new
21
+ selected_shipping_method = selector.shipping_method_for(easypost_rate)
22
+
23
+ expect(selected_shipping_method).to have_attributes(
24
+ name: 'USPS Express',
25
+ carrier: 'USPS',
26
+ service_level: 'Express',
27
+ shipping_categories: [shipping_category],
28
+ available_to_users: false,
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ RSpec.describe SolidusEasypost::ShippingRateCalculator do
2
+ describe '#compute' do
3
+ it 'returns the amount on the EasyPost rate' do
4
+ easypost_rate = EasyPost::Rate.construct_from('rate' => 25.0)
5
+
6
+ calculator = described_class.new
7
+ computed_rate = calculator.compute(easypost_rate)
8
+
9
+ expect(computed_rate).to eq(25.0)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,58 @@
1
+ RSpec.describe SolidusEasypost::TrackerWebhookHandler do
2
+ describe '.call' do
3
+ context 'when the event is not tracker.updated' do
4
+ it 'does not process the event' do
5
+ stub_const('Spree::Event', class_spy(Spree::Event))
6
+ create(:carton, easy_post_tracker_id: 'trk_test')
7
+
8
+ payload = {
9
+ 'description' => 'tracker.created',
10
+ 'result' => {
11
+ 'id' => 'trk_test',
12
+ },
13
+ }
14
+ described_class.call(payload)
15
+
16
+ expect(Spree::Event).not_to have_received(:fire)
17
+ end
18
+ end
19
+
20
+ context 'when the tracker was not registered in Solidus' do
21
+ it 'does not process the event' do
22
+ stub_const('Spree::Event', class_spy(Spree::Event))
23
+ create(:carton, easy_post_tracker_id: 'trk_test')
24
+
25
+ payload = {
26
+ 'description' => 'tracker.updated',
27
+ 'result' => {
28
+ 'id' => 'trk_test1',
29
+ },
30
+ }
31
+ described_class.call(payload)
32
+
33
+ expect(Spree::Event).not_to have_received(:fire)
34
+ end
35
+ end
36
+
37
+ context 'when the event is a tracker update for a registered tracker' do
38
+ it 'forwards the event via the event bus' do
39
+ stub_const('Spree::Event', class_spy(Spree::Event))
40
+ carton = create(:carton, easy_post_tracker_id: 'trk_test')
41
+
42
+ payload = {
43
+ 'description' => 'tracker.updated',
44
+ 'result' => {
45
+ 'id' => 'trk_test',
46
+ },
47
+ }
48
+ described_class.call(payload)
49
+
50
+ expect(Spree::Event).to have_received(:fire).with(
51
+ 'solidus_easypost.tracker.updated',
52
+ carton: carton,
53
+ payload: payload,
54
+ )
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe SolidusEasypost do
6
+ describe '.configuration' do
7
+ it 'returns the configuration' do
8
+ expect(described_class.configuration).to be_instance_of(SolidusEasypost::Configuration)
9
+ end
10
+ end
11
+
12
+ describe '.configure' do
13
+ it 'yields the configuration' do
14
+ expect { |b| described_class.configure(&b) }.to yield_with_args(
15
+ an_instance_of(SolidusEasypost::Configuration),
16
+ )
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Configure Rails Environment
4
+ ENV['RAILS_ENV'] = 'test'
5
+
6
+ # Run Coverage report
7
+ require 'solidus_dev_support/rspec/coverage'
8
+
9
+ # Create the dummy app if it's still missing.
10
+ dummy_env = "#{__dir__}/dummy/config/environment.rb"
11
+ system 'bin/rake extension:test_app' unless File.exist? dummy_env
12
+ require dummy_env
13
+
14
+ # Requires factories and other useful helpers defined in spree_core.
15
+ require 'solidus_dev_support/rspec/feature_helper'
16
+
17
+ # Requires supporting ruby files with custom matchers and macros, etc,
18
+ # in spec/support/ and its subdirectories.
19
+ Dir["#{__dir__}/support/**/*.rb"].sort.each { |f| require f }
20
+
21
+ # Requires factories defined in lib/solidus_easypost/testing_support/factories.rb
22
+ require 'solidus_easypost/testing_support/factories'
23
+
24
+ RSpec.configure do |config|
25
+ config.infer_spec_type_from_file_location!
26
+ config.use_transactional_fixtures = false
27
+
28
+ if Spree.solidus_gem_version < Gem::Version.new('2.11')
29
+ config.extend Spree::TestingSupport::AuthorizationHelpers::Request, type: :system
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.configure do |config|
4
+ config.before { EasyPost.api_key = 'CvzYtuda6KRI9JjG7SAHbA' }
5
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.use_parent_strategy = false