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.
- checksums.yaml +5 -5
- data/.circleci/config.yml +41 -0
- data/.gem_release.yml +5 -0
- data/.github/stale.yml +17 -0
- data/.github_changelog_generator +2 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +36 -0
- data/CHANGELOG.md +113 -0
- data/Gemfile +33 -0
- data/LICENSE +26 -0
- data/README.md +194 -0
- data/Rakefile +6 -0
- data/app/controllers/spree/admin/postage_labels_controller.rb +20 -0
- data/app/decorators/models/solidus_easypost/spree/carton_decorator.rb +38 -0
- data/app/decorators/models/solidus_easypost/spree/shipment_decorator.rb +47 -0
- data/app/decorators/models/solidus_easypost/spree/shipping_rate_decorator.rb +13 -0
- data/app/models/solidus_easypost/parcel_dimension.rb +34 -0
- data/app/models/solidus_easypost/return_authorization.rb +27 -0
- data/app/overrides/spree/admin/orders/_shipment/add_postage_label.html.erb.deface +10 -0
- data/bin/console +17 -0
- data/bin/rails +7 -0
- data/bin/rails-engine +13 -0
- data/bin/rails-sandbox +16 -0
- data/bin/rake +7 -0
- data/bin/sandbox +86 -0
- data/bin/setup +8 -0
- data/config/initializers/webhooks.rb +7 -0
- data/config/locales/en.yml +8 -0
- data/config/routes.rb +9 -0
- data/db/migrate/20140515024440_add_easy_post_fields_to_shipping_rate.rb +9 -0
- data/db/migrate/20201025110912_add_tracker_id_to_cartons.rb +6 -0
- data/lib/generators/solidus_easypost/install/install_generator.rb +28 -0
- data/lib/generators/solidus_easypost/install/templates/initializer.rb +26 -0
- data/lib/solidus_easypost/address_builder.rb +45 -0
- data/lib/solidus_easypost/calculator/base_dimension_calculator.rb +28 -0
- data/lib/solidus_easypost/calculator/weight_dimension_calculator.rb +22 -0
- data/lib/solidus_easypost/configuration.rb +34 -0
- data/lib/solidus_easypost/engine.rb +19 -0
- data/lib/solidus_easypost/errors/unknown_partial_resource_error.rb +11 -0
- data/lib/solidus_easypost/estimator.rb +37 -0
- data/lib/solidus_easypost/parcel_builder.rb +27 -0
- data/lib/solidus_easypost/shipment_builder.rb +32 -0
- data/lib/solidus_easypost/shipping_method_selector.rb +17 -0
- data/lib/solidus_easypost/shipping_rate_calculator.rb +9 -0
- data/lib/solidus_easypost/testing_support/factories/address_factory.rb +10 -0
- data/lib/solidus_easypost/testing_support/factories/product_factory.rb +7 -0
- data/lib/solidus_easypost/testing_support/factories/shipment_factory.rb +30 -0
- data/lib/solidus_easypost/testing_support/factories/shipping_method_factory.rb +8 -0
- data/lib/solidus_easypost/testing_support/factories/stock_location_factory.rb +10 -0
- data/lib/solidus_easypost/testing_support/factories/variant_factory.rb +7 -0
- data/lib/solidus_easypost/testing_support/factories.rb +3 -0
- data/lib/solidus_easypost/tracker_webhook_handler.rb +14 -0
- data/lib/solidus_easypost/version.rb +5 -0
- data/lib/solidus_easypost.rb +32 -0
- data/solidus_easypost.gemspec +41 -0
- data/spec/cassettes/address_builder/from_address.yml +65 -0
- data/spec/cassettes/address_builder/from_stock_location.yml +65 -0
- data/spec/cassettes/estimator.yml +269 -0
- data/spec/cassettes/integration/checkout.yml +377 -0
- data/spec/cassettes/integration/order_shipping/with_purchase_labels.yml +373 -0
- data/spec/cassettes/integration/order_shipping/without_purchase_labels.yml +251 -0
- data/spec/cassettes/parcel_builder/from_package.yml +63 -0
- data/spec/cassettes/parcel_builder/from_return_authorization.yml +63 -0
- data/spec/cassettes/postage_labels/show.yml +72 -0
- data/spec/cassettes/return_authorization.yml +310 -0
- data/spec/cassettes/shipment_builder/from_package.yml +251 -0
- data/spec/cassettes/shipment_builder/from_return_authorization.yml +251 -0
- data/spec/cassettes/shipment_builder/from_shipment.yml +250 -0
- data/spec/controllers/spree/admin/postage_labels_controller_spec.rb +18 -0
- data/spec/features/admin/postage_labels_spec.rb +18 -0
- data/spec/integration/checkout_spec.rb +45 -0
- data/spec/integration/order_shipping_spec.rb +33 -0
- data/spec/models/solidus_easypost/parcel_dimension_spec.rb +80 -0
- data/spec/models/solidus_easypost/return_authorization_spec.rb +17 -0
- data/spec/models/spree/carton_spec.rb +57 -0
- data/spec/models/spree/shipment_spec.rb +69 -0
- data/spec/models/spree/shipping_rate_spec.rb +23 -0
- data/spec/solidus_easypost/address_builder_spec.rb +17 -0
- data/spec/solidus_easypost/calculator/weight_dimension_calculator_spec.rb +39 -0
- data/spec/solidus_easypost/estimator_spec.rb +52 -0
- data/spec/solidus_easypost/parcel_builder_spec.rb +113 -0
- data/spec/solidus_easypost/shipment_builder_spec.rb +28 -0
- data/spec/solidus_easypost/shipping_method_selector_spec.rb +33 -0
- data/spec/solidus_easypost/shipping_rate_calculator_spec.rb +12 -0
- data/spec/solidus_easypost/tracker_webhook_handler_spec.rb +58 -0
- data/spec/solidus_easypost_spec.rb +19 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/easypost.rb +5 -0
- data/spec/support/factory_bot.rb +3 -0
- data/spec/support/helpers/api_stubs.rb +40 -0
- data/spec/support/helpers/configuration.rb +28 -0
- data/spec/support/helpers/shipping_methods.rb +26 -0
- data/spec/support/solidus.rb +1 -0
- data/spec/support/vcr.rb +12 -0
- 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
|
data/spec/spec_helper.rb
ADDED
|
@@ -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
|