solidus_core 1.0.2 → 1.0.3
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 +4 -4
- data/CHANGELOG.md +1 -0
- data/Gemfile +3 -0
- data/Rakefile +16 -0
- data/script/rails +9 -0
- data/solidus_core.gemspec +48 -0
- data/spec/fixtures/thinking-cat.jpg +0 -0
- data/spec/helpers/base_helper_spec.rb +173 -0
- data/spec/helpers/order_helper_spec.rb +12 -0
- data/spec/helpers/products_helper_spec.rb +220 -0
- data/spec/helpers/taxons_helper_spec.rb +17 -0
- data/spec/lib/calculated_adjustments_spec.rb +7 -0
- data/spec/lib/i18n_spec.rb +123 -0
- data/spec/lib/search/base_spec.rb +86 -0
- data/spec/lib/search/variant_spec.rb +92 -0
- data/spec/lib/spree/core/controller_helpers/auth_spec.rb +66 -0
- data/spec/lib/spree/core/controller_helpers/order_spec.rb +92 -0
- data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
- data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
- data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
- data/spec/lib/spree/core/current_store_spec.rb +36 -0
- data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
- data/spec/lib/spree/core/importer/order_spec.rb +431 -0
- data/spec/lib/spree/core/role_configuration_spec.rb +138 -0
- data/spec/lib/spree/core/validators/email_spec.rb +48 -0
- data/spec/lib/spree/localized_number_spec.rb +38 -0
- data/spec/lib/spree/migrations_spec.rb +36 -0
- data/spec/lib/spree/money_spec.rb +127 -0
- data/spec/lib/tasks/exchanges_spec.rb +231 -0
- data/spec/lib/tasks/migrations/copy_shipped_shipments_to_cartons_spec.rb +115 -0
- data/spec/lib/tasks/order_capturing_spec.rb +56 -0
- data/spec/mailers/carton_mailer_spec.rb +43 -0
- data/spec/mailers/order_mailer_spec.rb +122 -0
- data/spec/mailers/reimbursement_mailer_spec.rb +40 -0
- data/spec/mailers/test_mailer_spec.rb +15 -0
- data/spec/models/spree/ability_spec.rb +276 -0
- data/spec/models/spree/address_spec.rb +250 -0
- data/spec/models/spree/adjustment_reason_spec.rb +13 -0
- data/spec/models/spree/adjustment_spec.rb +177 -0
- data/spec/models/spree/app_configuration_spec.rb +20 -0
- data/spec/models/spree/asset_spec.rb +24 -0
- data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
- data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
- data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
- data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
- data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
- data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
- data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
- data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
- data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
- data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
- data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
- data/spec/models/spree/calculator/shipping/price_sack_spec.rb +30 -0
- data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +36 -0
- data/spec/models/spree/calculator/tiered_percent_spec.rb +47 -0
- data/spec/models/spree/calculator_spec.rb +36 -0
- data/spec/models/spree/carton_spec.rb +133 -0
- data/spec/models/spree/classification_spec.rb +15 -0
- data/spec/models/spree/concerns/display_money_spec.rb +43 -0
- data/spec/models/spree/concerns/user_methods_spec.rb +41 -0
- data/spec/models/spree/credit_card_spec.rb +334 -0
- data/spec/models/spree/customer_return_spec.rb +276 -0
- data/spec/models/spree/exchange_spec.rb +79 -0
- data/spec/models/spree/gateway/bogus_simple.rb +20 -0
- data/spec/models/spree/gateway/bogus_spec.rb +13 -0
- data/spec/models/spree/gateway_spec.rb +82 -0
- data/spec/models/spree/inventory_unit_spec.rb +307 -0
- data/spec/models/spree/item_adjustments_spec.rb +256 -0
- data/spec/models/spree/line_item_spec.rb +191 -0
- data/spec/models/spree/option_type_spec.rb +14 -0
- data/spec/models/spree/option_value_spec.rb +22 -0
- data/spec/models/spree/order/address_spec.rb +50 -0
- data/spec/models/spree/order/adjustments_spec.rb +39 -0
- data/spec/models/spree/order/callbacks_spec.rb +42 -0
- data/spec/models/spree/order/checkout_spec.rb +902 -0
- data/spec/models/spree/order/currency_updater_spec.rb +32 -0
- data/spec/models/spree/order/finalizing_spec.rb +111 -0
- data/spec/models/spree/order/payment_spec.rb +210 -0
- data/spec/models/spree/order/risk_assessment_spec.rb +68 -0
- data/spec/models/spree/order/state_machine_spec.rb +221 -0
- data/spec/models/spree/order/tax_spec.rb +84 -0
- data/spec/models/spree/order/totals_spec.rb +24 -0
- data/spec/models/spree/order/updating_spec.rb +18 -0
- data/spec/models/spree/order/validations_spec.rb +15 -0
- data/spec/models/spree/order_cancellations_spec.rb +120 -0
- data/spec/models/spree/order_capturing_spec.rb +116 -0
- data/spec/models/spree/order_contents_spec.rb +265 -0
- data/spec/models/spree/order_inventory_spec.rb +228 -0
- data/spec/models/spree/order_mutex_spec.rb +85 -0
- data/spec/models/spree/order_promotion_spec.rb +31 -0
- data/spec/models/spree/order_shipping_spec.rb +247 -0
- data/spec/models/spree/order_spec.rb +1412 -0
- data/spec/models/spree/order_stock_location_spec.rb +18 -0
- data/spec/models/spree/order_updater_spec.rb +299 -0
- data/spec/models/spree/payment_method/store_credit_spec.rb +294 -0
- data/spec/models/spree/payment_method_spec.rb +96 -0
- data/spec/models/spree/payment_spec.rb +1044 -0
- data/spec/models/spree/permission_sets/base_spec.rb +12 -0
- data/spec/models/spree/permission_sets/configuration_display.rb +82 -0
- data/spec/models/spree/permission_sets/configuration_management_spec.rb +50 -0
- data/spec/models/spree/permission_sets/dashboard_display_spec.rb +22 -0
- data/spec/models/spree/permission_sets/order_display_spec.rb +49 -0
- data/spec/models/spree/permission_sets/order_management_spec.rb +36 -0
- data/spec/models/spree/permission_sets/product_display_spec.rb +60 -0
- data/spec/models/spree/permission_sets/product_management_spec.rb +40 -0
- data/spec/models/spree/permission_sets/promotion_display_spec.rb +34 -0
- data/spec/models/spree/permission_sets/promotion_management_spec.rb +26 -0
- data/spec/models/spree/permission_sets/report_display_spec.rb +24 -0
- data/spec/models/spree/permission_sets/restricted_transfer_management_spec.rb +132 -0
- data/spec/models/spree/permission_sets/stock_display_spec.rb +26 -0
- data/spec/models/spree/permission_sets/stock_management_spec.rb +24 -0
- data/spec/models/spree/permission_sets/user_display_spec.rb +36 -0
- data/spec/models/spree/permission_sets/user_management_spec.rb +28 -0
- data/spec/models/spree/preference_spec.rb +80 -0
- data/spec/models/spree/preferences/configuration_spec.rb +30 -0
- data/spec/models/spree/preferences/preferable_spec.rb +294 -0
- data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
- data/spec/models/spree/preferences/static_model_preferences_spec.rb +78 -0
- data/spec/models/spree/preferences/statically_configurable_spec.rb +60 -0
- data/spec/models/spree/preferences/store_spec.rb +39 -0
- data/spec/models/spree/price_spec.rb +42 -0
- data/spec/models/spree/product/scopes_spec.rb +148 -0
- data/spec/models/spree/product_duplicator_spec.rb +103 -0
- data/spec/models/spree/product_filter_spec.rb +26 -0
- data/spec/models/spree/product_property_spec.rb +20 -0
- data/spec/models/spree/product_spec.rb +437 -0
- data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +96 -0
- data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +165 -0
- data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +115 -0
- data/spec/models/spree/promotion/actions/free_shipping_spec.rb +40 -0
- data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
- data/spec/models/spree/promotion/rules/item_total_spec.rb +67 -0
- data/spec/models/spree/promotion/rules/nth_order_spec.rb +70 -0
- data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
- data/spec/models/spree/promotion/rules/option_value_spec.rb +94 -0
- data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
- data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
- data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
- data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
- data/spec/models/spree/promotion_builder_spec.rb +118 -0
- data/spec/models/spree/promotion_category_spec.rb +17 -0
- data/spec/models/spree/promotion_code/code_builder_spec.rb +79 -0
- data/spec/models/spree/promotion_code_spec.rb +187 -0
- data/spec/models/spree/promotion_handler/cart_spec.rb +114 -0
- data/spec/models/spree/promotion_handler/coupon_spec.rb +335 -0
- data/spec/models/spree/promotion_handler/free_shipping_spec.rb +47 -0
- data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
- data/spec/models/spree/promotion_rule_spec.rb +28 -0
- data/spec/models/spree/promotion_spec.rb +767 -0
- data/spec/models/spree/refund_spec.rb +204 -0
- data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
- data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
- data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
- data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
- data/spec/models/spree/reimbursement_spec.rb +231 -0
- data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
- data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
- data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
- data/spec/models/spree/reimbursement_type/original_payment_spec.rb +107 -0
- data/spec/models/spree/reimbursement_type/store_credit_spec.rb +97 -0
- data/spec/models/spree/return_authorization_spec.rb +290 -0
- data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
- data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
- data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +85 -0
- data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
- data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
- data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
- data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
- data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
- data/spec/models/spree/return_item_spec.rb +775 -0
- data/spec/models/spree/returns_calculator_spec.rb +14 -0
- data/spec/models/spree/shipment_spec.rb +709 -0
- data/spec/models/spree/shipping_calculator_spec.rb +45 -0
- data/spec/models/spree/shipping_method_spec.rb +88 -0
- data/spec/models/spree/shipping_rate_spec.rb +142 -0
- data/spec/models/spree/state_spec.rb +14 -0
- data/spec/models/spree/stock/availability_validator_spec.rb +83 -0
- data/spec/models/spree/stock/coordinator_spec.rb +116 -0
- data/spec/models/spree/stock/differentiator_spec.rb +39 -0
- data/spec/models/spree/stock/estimator_spec.rb +146 -0
- data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
- data/spec/models/spree/stock/package_spec.rb +163 -0
- data/spec/models/spree/stock/packer_spec.rb +91 -0
- data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
- data/spec/models/spree/stock/quantifier_spec.rb +115 -0
- data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
- data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
- data/spec/models/spree/stock/splitter/shipping_category_spec.rb +50 -0
- data/spec/models/spree/stock/splitter/weight_spec.rb +29 -0
- data/spec/models/spree/stock_item_spec.rb +426 -0
- data/spec/models/spree/stock_location_spec.rb +279 -0
- data/spec/models/spree/stock_movement_spec.rb +56 -0
- data/spec/models/spree/stock_transfer_spec.rb +290 -0
- data/spec/models/spree/store_credit_category_spec.rb +17 -0
- data/spec/models/spree/store_credit_event_spec.rb +314 -0
- data/spec/models/spree/store_credit_spec.rb +876 -0
- data/spec/models/spree/store_spec.rb +55 -0
- data/spec/models/spree/tax_category_spec.rb +27 -0
- data/spec/models/spree/tax_rate_spec.rb +378 -0
- data/spec/models/spree/taxon_spec.rb +74 -0
- data/spec/models/spree/taxonomy_spec.rb +18 -0
- data/spec/models/spree/tracker_spec.rb +21 -0
- data/spec/models/spree/transfer_item_spec.rb +264 -0
- data/spec/models/spree/unit_cancel_spec.rb +148 -0
- data/spec/models/spree/user_spec.rb +223 -0
- data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +23 -0
- data/spec/models/spree/variant/scopes_spec.rb +55 -0
- data/spec/models/spree/variant_spec.rb +546 -0
- data/spec/models/spree/zone_spec.rb +305 -0
- data/spec/spec_helper.rb +78 -0
- data/spec/support/big_decimal.rb +5 -0
- data/spec/support/concerns/default_price.rb +34 -0
- data/spec/support/dummy_ability.rb +4 -0
- data/spec/support/test_gateway.rb +2 -0
- metadata +229 -3
- data/lib/spree/testing_support/rspec-activemodel-mocks_patch.rb +0 -8
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'spree/core/product_filters'
|
|
3
|
+
|
|
4
|
+
describe 'product filters', :type => :model do
|
|
5
|
+
# Regression test for #1709
|
|
6
|
+
context 'finds products filtered by brand' do
|
|
7
|
+
let(:product) { create(:product) }
|
|
8
|
+
before do
|
|
9
|
+
property = Spree::Property.create!(:name => "brand", :presentation => "brand")
|
|
10
|
+
product.set_property("brand", "Nike")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "does not attempt to call value method on Arel::Table" do
|
|
14
|
+
expect { Spree::Core::ProductFilters.brand_filter }.not_to raise_error
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "can find products in the 'Nike' brand" do
|
|
18
|
+
expect(Spree::Product.brand_any("Nike")).to include(product)
|
|
19
|
+
end
|
|
20
|
+
it "sorts products without brand specified" do
|
|
21
|
+
product.set_property("brand", "Nike")
|
|
22
|
+
create(:product).set_property("brand", nil)
|
|
23
|
+
expect { Spree::Core::ProductFilters.brand_filter[:labels] }.not_to raise_error
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Spree::ProductProperty, :type => :model do
|
|
4
|
+
|
|
5
|
+
context "validations" do
|
|
6
|
+
it "should validate length of value" do
|
|
7
|
+
pp = create(:product_property)
|
|
8
|
+
pp.value = "x" * 256
|
|
9
|
+
expect(pp).not_to be_valid
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context "touching" do
|
|
14
|
+
it "should update product" do
|
|
15
|
+
pp = create(:product_property)
|
|
16
|
+
expect(pp.product).to receive(:touch)
|
|
17
|
+
pp.touch
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
# coding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
module ThirdParty
|
|
6
|
+
class Extension < Spree::Base
|
|
7
|
+
# nasty hack so we don't have to create a table to back this fake model
|
|
8
|
+
self.table_name = 'spree_products'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe Spree::Product, :type => :model do
|
|
13
|
+
|
|
14
|
+
context 'product instance' do
|
|
15
|
+
let(:product) { create(:product) }
|
|
16
|
+
let(:variant) { create(:variant, :product => product) }
|
|
17
|
+
|
|
18
|
+
context '#duplicate' do
|
|
19
|
+
before do
|
|
20
|
+
allow(product).to receive_messages :taxons => [create(:taxon)]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'duplicates product' do
|
|
24
|
+
clone = product.duplicate
|
|
25
|
+
expect(clone.name).to eq('COPY OF ' + product.name)
|
|
26
|
+
expect(clone.master.sku).to eq('COPY OF ' + product.master.sku)
|
|
27
|
+
expect(clone.taxons).to eq(product.taxons)
|
|
28
|
+
expect(clone.images.size).to eq(product.images.size)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'calls #duplicate_extra' do
|
|
32
|
+
expect_any_instance_of(Spree::Product).to receive(:duplicate_extra) do |product, old_product|
|
|
33
|
+
product.name = old_product.name.reverse
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
clone = product.duplicate
|
|
37
|
+
expect(clone.name).to eq(product.name.reverse)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context "master variant" do
|
|
42
|
+
|
|
43
|
+
context "when master variant changed" do
|
|
44
|
+
before do
|
|
45
|
+
product.master.sku = "Something changed"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "saves the master" do
|
|
49
|
+
expect(product.master).to receive(:save!)
|
|
50
|
+
product.save
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when master default price changed" do
|
|
55
|
+
before do
|
|
56
|
+
master = product.master
|
|
57
|
+
master.default_price.price = 11
|
|
58
|
+
master.save!
|
|
59
|
+
product.master.default_price.price = 12
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "saves the master" do
|
|
63
|
+
expect(product.master).to receive(:save!)
|
|
64
|
+
product.save
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "saves the default price" do
|
|
68
|
+
expect(product.master.default_price).to receive(:save)
|
|
69
|
+
product.save
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context "when master variant and price haven't changed" do
|
|
74
|
+
it "does not save the master" do
|
|
75
|
+
expect(product.master).not_to receive(:save!)
|
|
76
|
+
product.save
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context "product has no variants" do
|
|
82
|
+
context "#destroy" do
|
|
83
|
+
it "should set deleted_at value" do
|
|
84
|
+
product.destroy
|
|
85
|
+
expect(product.deleted_at).not_to be_nil
|
|
86
|
+
expect(product.master.reload.deleted_at).not_to be_nil
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context "product has variants" do
|
|
92
|
+
before do
|
|
93
|
+
create(:variant, :product => product)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context "#destroy" do
|
|
97
|
+
it "should set deleted_at value" do
|
|
98
|
+
product.destroy
|
|
99
|
+
expect(product.deleted_at).not_to be_nil
|
|
100
|
+
expect(product.variants_including_master.all? { |v| !v.deleted_at.nil? }).to be true
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
context "#price" do
|
|
106
|
+
# Regression test for #1173
|
|
107
|
+
it 'strips non-price characters' do
|
|
108
|
+
product.price = "$10"
|
|
109
|
+
expect(product.price).to eq(10.0)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
context "#display_price" do
|
|
114
|
+
before { product.price = 10.55 }
|
|
115
|
+
|
|
116
|
+
it "shows the amount" do
|
|
117
|
+
expect(product.display_price.to_s).to eq("$10.55")
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context "with currency set to JPY" do
|
|
121
|
+
before do
|
|
122
|
+
product.master.default_price.currency = 'JPY'
|
|
123
|
+
product.master.default_price.save!
|
|
124
|
+
Spree::Config[:currency] = 'JPY'
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "displays the currency in yen" do
|
|
128
|
+
expect(product.display_price.to_s).to eq("¥11")
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
context "#available?" do
|
|
134
|
+
it "should be available if date is in the past" do
|
|
135
|
+
product.available_on = 1.day.ago
|
|
136
|
+
expect(product).to be_available
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "should not be available if date is nil or in the future" do
|
|
140
|
+
product.available_on = nil
|
|
141
|
+
expect(product).not_to be_available
|
|
142
|
+
|
|
143
|
+
product.available_on = 1.day.from_now
|
|
144
|
+
expect(product).not_to be_available
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "should not be available if destroyed" do
|
|
148
|
+
product.destroy
|
|
149
|
+
expect(product).not_to be_available
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
context "variants_and_option_values" do
|
|
154
|
+
let!(:high) { create(:variant, product: product) }
|
|
155
|
+
let!(:low) { create(:variant, product: product) }
|
|
156
|
+
|
|
157
|
+
before { high.option_values.destroy_all }
|
|
158
|
+
|
|
159
|
+
it "returns only variants with option values" do
|
|
160
|
+
expect(product.variants_and_option_values).to eq([low])
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
describe 'Variants sorting' do
|
|
165
|
+
context 'without master variant' do
|
|
166
|
+
it 'sorts variants by position' do
|
|
167
|
+
expect(product.variants.to_sql).to match(/ORDER BY (\`|\")spree_variants(\`|\").position ASC/)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
context 'with master variant' do
|
|
172
|
+
it 'sorts variants by position' do
|
|
173
|
+
expect(product.variants_including_master.to_sql).to match(/ORDER BY (\`|\")spree_variants(\`|\").position ASC/)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
context "has stock movements" do
|
|
179
|
+
let(:product) { create(:product) }
|
|
180
|
+
let(:variant) { product.master }
|
|
181
|
+
let(:stock_item) { variant.stock_items.first }
|
|
182
|
+
|
|
183
|
+
it "doesnt raise ReadOnlyRecord error" do
|
|
184
|
+
Spree::StockMovement.create!(stock_item: stock_item, quantity: 1)
|
|
185
|
+
expect { product.destroy }.not_to raise_error
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Regression test for #3737
|
|
190
|
+
context "has stock items" do
|
|
191
|
+
let(:product) { create(:product) }
|
|
192
|
+
it "can retrieve stock items" do
|
|
193
|
+
expect(product.master.stock_items.first).not_to be_nil
|
|
194
|
+
expect(product.stock_items.first).not_to be_nil
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
context "slugs" do
|
|
199
|
+
|
|
200
|
+
it "normalizes slug on update validation" do
|
|
201
|
+
product.slug = "hey//joe"
|
|
202
|
+
product.valid?
|
|
203
|
+
expect(product.slug).not_to match "/"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it "renames slug on destroy" do
|
|
207
|
+
old_slug = product.slug
|
|
208
|
+
product.destroy
|
|
209
|
+
expect(old_slug).to_not eq product.slug
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "validates slug uniqueness" do
|
|
213
|
+
existing_product = product
|
|
214
|
+
new_product = create(:product)
|
|
215
|
+
new_product.slug = existing_product.slug
|
|
216
|
+
|
|
217
|
+
expect(new_product.valid?).to eq false
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it "falls back to 'name-sku' for slug if regular name-based slug already in use" do
|
|
221
|
+
product1 = build(:product)
|
|
222
|
+
product1.name = "test"
|
|
223
|
+
product1.sku = "123"
|
|
224
|
+
product1.save!
|
|
225
|
+
|
|
226
|
+
product2 = build(:product)
|
|
227
|
+
product2.name = "test"
|
|
228
|
+
product2.sku = "456"
|
|
229
|
+
product2.save!
|
|
230
|
+
|
|
231
|
+
expect(product2.slug).to eq 'test-456'
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
context "properties" do
|
|
239
|
+
let(:product) { create(:product) }
|
|
240
|
+
|
|
241
|
+
it "should properly assign properties" do
|
|
242
|
+
product.set_property('the_prop', 'value1')
|
|
243
|
+
expect(product.property('the_prop')).to eq('value1')
|
|
244
|
+
|
|
245
|
+
product.set_property('the_prop', 'value2')
|
|
246
|
+
expect(product.property('the_prop')).to eq('value2')
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
it "should not create duplicate properties when set_property is called" do
|
|
250
|
+
expect {
|
|
251
|
+
product.set_property('the_prop', 'value2')
|
|
252
|
+
product.save
|
|
253
|
+
product.reload
|
|
254
|
+
}.not_to change(product.properties, :length)
|
|
255
|
+
|
|
256
|
+
expect {
|
|
257
|
+
product.set_property('the_prop_new', 'value')
|
|
258
|
+
product.save
|
|
259
|
+
product.reload
|
|
260
|
+
expect(product.property('the_prop_new')).to eq('value')
|
|
261
|
+
}.to change { product.properties.length }.by(1)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Regression test for #2455
|
|
265
|
+
it "should not overwrite properties' presentation names" do
|
|
266
|
+
Spree::Property.where(:name => 'foo').first_or_create!(:presentation => "Foo's Presentation Name")
|
|
267
|
+
product.set_property('foo', 'value1')
|
|
268
|
+
product.set_property('bar', 'value2')
|
|
269
|
+
expect(Spree::Property.where(:name => 'foo').first.presentation).to eq("Foo's Presentation Name")
|
|
270
|
+
expect(Spree::Property.where(:name => 'bar').first.presentation).to eq("bar")
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Regression test for #4416
|
|
274
|
+
context "#possible_promotions" do
|
|
275
|
+
let!(:promotion) do
|
|
276
|
+
create(:promotion, advertise: true, starts_at: 1.day.ago)
|
|
277
|
+
end
|
|
278
|
+
let!(:rule) do
|
|
279
|
+
Spree::Promotion::Rules::Product.create(
|
|
280
|
+
promotion: promotion,
|
|
281
|
+
products: [product]
|
|
282
|
+
)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it "lists the promotion as a possible promotion" do
|
|
286
|
+
expect(product.possible_promotions).to include(promotion)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
context '#create' do
|
|
292
|
+
let!(:prototype) { create(:prototype) }
|
|
293
|
+
let!(:product) { Spree::Product.new(name: "Foo", price: 1.99, shipping_category_id: create(:shipping_category).id) }
|
|
294
|
+
|
|
295
|
+
before { product.prototype_id = prototype.id }
|
|
296
|
+
|
|
297
|
+
context "when prototype is supplied" do
|
|
298
|
+
it "should create properties based on the prototype" do
|
|
299
|
+
product.save
|
|
300
|
+
expect(product.properties.count).to eq(1)
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
context "when prototype with option types is supplied" do
|
|
305
|
+
def build_option_type_with_values(name, values)
|
|
306
|
+
ot = create(:option_type, :name => name)
|
|
307
|
+
values.each do |val|
|
|
308
|
+
ot.option_values.create(:name => val.downcase, :presentation => val)
|
|
309
|
+
end
|
|
310
|
+
ot
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
let(:prototype) do
|
|
314
|
+
size = build_option_type_with_values("size", %w(Small Medium Large))
|
|
315
|
+
create(:prototype, :name => "Size", :option_types => [ size ])
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
let(:option_values_hash) do
|
|
319
|
+
hash = {}
|
|
320
|
+
prototype.option_types.each do |i|
|
|
321
|
+
hash[i.id.to_s] = i.option_value_ids
|
|
322
|
+
end
|
|
323
|
+
hash
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
it "should create option types based on the prototype" do
|
|
327
|
+
product.save
|
|
328
|
+
expect(product.option_type_ids.length).to eq(1)
|
|
329
|
+
expect(product.option_type_ids).to eq(prototype.option_type_ids)
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
it "should create product option types based on the prototype" do
|
|
333
|
+
product.save
|
|
334
|
+
expect(product.product_option_types.pluck(:option_type_id)).to eq(prototype.option_type_ids)
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
it "should create variants from an option values hash with one option type" do
|
|
338
|
+
product.option_values_hash = option_values_hash
|
|
339
|
+
product.save
|
|
340
|
+
expect(product.variants.length).to eq(3)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
it "should still create variants when option_values_hash is given but prototype id is nil" do
|
|
344
|
+
product.option_values_hash = option_values_hash
|
|
345
|
+
product.prototype_id = nil
|
|
346
|
+
product.save
|
|
347
|
+
expect(product.option_type_ids.length).to eq(1)
|
|
348
|
+
expect(product.option_type_ids).to eq(prototype.option_type_ids)
|
|
349
|
+
expect(product.variants.length).to eq(3)
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
it "should create variants from an option values hash with multiple option types" do
|
|
353
|
+
color = build_option_type_with_values("color", %w(Red Green Blue))
|
|
354
|
+
logo = build_option_type_with_values("logo", %w(Ruby Rails Nginx))
|
|
355
|
+
option_values_hash[color.id.to_s] = color.option_value_ids
|
|
356
|
+
option_values_hash[logo.id.to_s] = logo.option_value_ids
|
|
357
|
+
product.option_values_hash = option_values_hash
|
|
358
|
+
product.save
|
|
359
|
+
product.reload
|
|
360
|
+
expect(product.option_type_ids.length).to eq(3)
|
|
361
|
+
expect(product.variants.length).to eq(27)
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
context "#images" do
|
|
367
|
+
let(:product) { create(:product) }
|
|
368
|
+
let(:image) { File.open(File.expand_path('../../../fixtures/thinking-cat.jpg', __FILE__)) }
|
|
369
|
+
let(:params) { {:viewable_id => product.master.id, :viewable_type => 'Spree::Variant', :attachment => image, :alt => "position 2", :position => 2} }
|
|
370
|
+
|
|
371
|
+
before do
|
|
372
|
+
Spree::Image.create(params)
|
|
373
|
+
Spree::Image.create(params.merge({:alt => "position 1", :position => 1}))
|
|
374
|
+
Spree::Image.create(params.merge({:viewable_type => 'ThirdParty::Extension', :alt => "position 1", :position => 2}))
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
it "only looks for variant images" do
|
|
378
|
+
expect(product.images.size).to eq(2)
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
it "should be sorted by position" do
|
|
382
|
+
expect(product.images.pluck(:alt)).to eq(["position 1", "position 2"])
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# Regression tests for #2352
|
|
387
|
+
context "classifications and taxons" do
|
|
388
|
+
it "is joined through classifications" do
|
|
389
|
+
reflection = Spree::Product.reflect_on_association(:taxons)
|
|
390
|
+
expect(reflection.options[:through]).to eq(:classifications)
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
it "will delete all classifications" do
|
|
394
|
+
reflection = Spree::Product.reflect_on_association(:classifications)
|
|
395
|
+
expect(reflection.options[:dependent]).to eq(:delete_all)
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
context '#total_on_hand' do
|
|
400
|
+
it 'should be infinite if track_inventory_levels is false' do
|
|
401
|
+
Spree::Config[:track_inventory_levels] = false
|
|
402
|
+
expect(build(:product, :variants_including_master => [build(:master_variant)]).total_on_hand).to eql(Float::INFINITY)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
it 'should be infinite if variant is on demand' do
|
|
406
|
+
Spree::Config[:track_inventory_levels] = true
|
|
407
|
+
expect(build(:product, :variants_including_master => [build(:on_demand_master_variant)]).total_on_hand).to eql(Float::INFINITY)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
it 'should return sum of stock items count_on_hand' do
|
|
411
|
+
product = create(:product)
|
|
412
|
+
product.stock_items.first.set_count_on_hand 5
|
|
413
|
+
product.variants_including_master(true) # force load association
|
|
414
|
+
expect(product.total_on_hand).to eql(5)
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
it 'should return sum of stock items count_on_hand when variants_including_master is not loaded' do
|
|
418
|
+
product = create(:product)
|
|
419
|
+
product.stock_items.first.set_count_on_hand 5
|
|
420
|
+
expect(product.reload.total_on_hand).to eql(5)
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# Regression spec for https://github.com/spree/spree/issues/5588
|
|
425
|
+
context '#validate_master when duplicate SKUs entered' do
|
|
426
|
+
let!(:first_product) { create(:product, sku: 'a-sku') }
|
|
427
|
+
let(:second_product) { build(:product, sku: 'a-sku') }
|
|
428
|
+
|
|
429
|
+
subject { second_product }
|
|
430
|
+
it { is_expected.to be_invalid }
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
it "initializes a master variant when building a product" do
|
|
434
|
+
product = Spree::Product.new
|
|
435
|
+
expect(product.master.is_master).to be true
|
|
436
|
+
end
|
|
437
|
+
end
|