spree_api 3.2.9 → 3.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/spree/api/base_controller.rb +11 -12
  3. data/app/controllers/spree/api/v1/checkouts_controller.rb +5 -8
  4. data/app/controllers/spree/api/v1/customer_returns_controller.rb +24 -0
  5. data/app/controllers/spree/api/v1/orders_controller.rb +13 -24
  6. data/app/controllers/spree/api/v1/payments_controller.rb +2 -3
  7. data/app/controllers/spree/api/v1/reimbursements_controller.rb +24 -0
  8. data/app/controllers/spree/api/v1/shipments_controller.rb +4 -4
  9. data/app/controllers/spree/api/v1/zones_controller.rb +8 -3
  10. data/app/helpers/spree/api/api_helpers.rb +13 -1
  11. data/app/models/concerns/spree/user_api_authentication.rb +19 -0
  12. data/app/models/concerns/spree/user_api_methods.rb +7 -0
  13. data/app/views/spree/api/v1/customer_returns/index.v1.rabl +7 -0
  14. data/app/views/spree/api/v1/line_items/show.v1.rabl +0 -1
  15. data/app/views/spree/api/v1/reimbursements/index.v1.rabl +7 -0
  16. data/config/initializers/user_class_extensions.rb +7 -0
  17. data/config/routes.rb +3 -0
  18. data/spec/controllers/spree/api/base_controller_spec.rb +84 -0
  19. data/spec/controllers/spree/api/v1/addresses_controller_spec.rb +56 -0
  20. data/spec/controllers/spree/api/v1/checkouts_controller_spec.rb +361 -0
  21. data/spec/controllers/spree/api/v1/classifications_controller_spec.rb +48 -0
  22. data/spec/controllers/spree/api/v1/countries_controller_spec.rb +48 -0
  23. data/spec/controllers/spree/api/v1/credit_cards_controller_spec.rb +80 -0
  24. data/spec/controllers/spree/api/v1/customer_returns_controller_spec.rb +27 -0
  25. data/spec/controllers/spree/api/v1/images_controller_spec.rb +114 -0
  26. data/spec/controllers/spree/api/v1/inventory_units_controller_spec.rb +48 -0
  27. data/spec/controllers/spree/api/v1/line_items_controller_spec.rb +210 -0
  28. data/spec/controllers/spree/api/v1/option_types_controller_spec.rb +122 -0
  29. data/spec/controllers/spree/api/v1/option_values_controller_spec.rb +141 -0
  30. data/spec/controllers/spree/api/v1/orders_controller_spec.rb +735 -0
  31. data/spec/controllers/spree/api/v1/payments_controller_spec.rb +234 -0
  32. data/spec/controllers/spree/api/v1/product_properties_controller_spec.rb +156 -0
  33. data/spec/controllers/spree/api/v1/products_controller_spec.rb +409 -0
  34. data/spec/controllers/spree/api/v1/promotion_application_spec.rb +50 -0
  35. data/spec/controllers/spree/api/v1/promotions_controller_spec.rb +64 -0
  36. data/spec/controllers/spree/api/v1/properties_controller_spec.rb +102 -0
  37. data/spec/controllers/spree/api/v1/reimbursements_controller_spec.rb +24 -0
  38. data/spec/controllers/spree/api/v1/return_authorizations_controller_spec.rb +161 -0
  39. data/spec/controllers/spree/api/v1/shipments_controller_spec.rb +187 -0
  40. data/spec/controllers/spree/api/v1/states_controller_spec.rb +86 -0
  41. data/spec/controllers/spree/api/v1/stock_items_controller_spec.rb +151 -0
  42. data/spec/controllers/spree/api/v1/stock_locations_controller_spec.rb +113 -0
  43. data/spec/controllers/spree/api/v1/stock_movements_controller_spec.rb +84 -0
  44. data/spec/controllers/spree/api/v1/stores_controller_spec.rb +133 -0
  45. data/spec/controllers/spree/api/v1/tags_controller_spec.rb +102 -0
  46. data/spec/controllers/spree/api/v1/taxonomies_controller_spec.rb +114 -0
  47. data/spec/controllers/spree/api/v1/taxons_controller_spec.rb +177 -0
  48. data/spec/controllers/spree/api/v1/unauthenticated_products_controller_spec.rb +26 -0
  49. data/spec/controllers/spree/api/v1/users_controller_spec.rb +153 -0
  50. data/spec/controllers/spree/api/v1/variants_controller_spec.rb +205 -0
  51. data/spec/controllers/spree/api/v1/zones_controller_spec.rb +91 -0
  52. data/spec/models/spree/legacy_user_spec.rb +19 -0
  53. data/spec/requests/rabl_cache_spec.rb +32 -0
  54. data/spec/requests/ransackable_attributes_spec.rb +79 -0
  55. data/spec/requests/version_spec.rb +19 -0
  56. data/spec/shared_examples/protect_product_actions.rb +17 -0
  57. data/spec/spec_helper.rb +63 -0
  58. data/spec/support/controller_hacks.rb +40 -0
  59. data/spec/support/database_cleaner.rb +14 -0
  60. data/spec/support/have_attributes_matcher.rb +13 -0
  61. data/spree_api.gemspec +4 -3
  62. metadata +105 -13
  63. data/app/views/spree/api/v1/config/money.v1.rabl +0 -2
  64. data/app/views/spree/api/v1/config/show.v1.rabl +0 -2
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Api::V1::InventoryUnitsController, type: :controller do
5
+ render_views
6
+
7
+ before do
8
+ stub_authentication!
9
+ @inventory_unit = create(:inventory_unit)
10
+ end
11
+
12
+ context "as an admin" do
13
+ sign_in_as_admin!
14
+
15
+ it "gets an inventory unit" do
16
+ api_get :show, id: @inventory_unit.id
17
+ expect(json_response['state']).to eq @inventory_unit.state
18
+ end
19
+
20
+ it "updates an inventory unit" do
21
+ api_put :update, id: @inventory_unit.id,
22
+ inventory_unit: { shipment_id: nil }
23
+ expect(json_response['shipment_id']).to be_nil
24
+ end
25
+
26
+ context 'fires state event' do
27
+ it 'if supplied with :fire param' do
28
+ api_put :update, id: @inventory_unit.id,
29
+ fire: 'ship',
30
+ inventory_unit: { shipment: { tracking: 'foobar' } }
31
+ expect(json_response['state']).to eq 'shipped'
32
+ end
33
+
34
+ it 'and returns exception if cannot fire' do
35
+ api_put :update, id: @inventory_unit.id,
36
+ fire: 'return'
37
+ expect(json_response['exception']).to match /cannot transition to return/
38
+ end
39
+
40
+ it 'and returns exception bad state' do
41
+ api_put :update, id: @inventory_unit.id,
42
+ fire: 'bad'
43
+ expect(json_response['exception']).to match /cannot transition to bad/
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,210 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ PermittedAttributes.module_eval do
5
+ mattr_writer :line_item_attributes
6
+ end
7
+
8
+ unless PermittedAttributes.line_item_attributes.include? :some_option
9
+ PermittedAttributes.line_item_attributes += [:some_option]
10
+ end
11
+
12
+ # This should go in an initializer
13
+ Spree::Api::V1::LineItemsController.line_item_options += [:some_option]
14
+
15
+ describe Api::V1::LineItemsController, type: :controller do
16
+ render_views
17
+
18
+ let!(:order) { create(:order_with_line_items, line_items_count: 1) }
19
+
20
+ let(:product) { create(:product) }
21
+ let(:attributes) { [:id, :quantity, :price, :variant, :total, :display_amount, :single_display_amount] }
22
+ let(:resource_scoping) { { order_id: order.to_param } }
23
+
24
+ before do
25
+ stub_authentication!
26
+ end
27
+
28
+ it "can learn how to create a new line item" do
29
+ api_get :new
30
+ expect(json_response["attributes"]).to eq(["quantity", "price", "variant_id"])
31
+ required_attributes = json_response["required_attributes"]
32
+ expect(required_attributes).to include("quantity", "variant_id")
33
+ end
34
+
35
+ context "authenticating with a token" do
36
+ it "can add a new line item to an existing order" do
37
+ api_post :create, line_item: { variant_id: product.master.to_param, quantity: 1 }, order_token: order.guest_token
38
+ expect(response.status).to eq(201)
39
+ expect(json_response).to have_attributes(attributes)
40
+ expect(json_response["variant"]["name"]).not_to be_blank
41
+ end
42
+
43
+ it "can add a new line item to an existing order with token in header" do
44
+ request.headers["X-Spree-Order-Token"] = order.guest_token
45
+ api_post :create, line_item: { variant_id: product.master.to_param, quantity: 1 }
46
+ expect(response.status).to eq(201)
47
+ expect(json_response).to have_attributes(attributes)
48
+ expect(json_response["variant"]["name"]).not_to be_blank
49
+ end
50
+ end
51
+
52
+ context "as the order owner" do
53
+ before do
54
+ allow_any_instance_of(Order).to receive_messages user: current_api_user
55
+ end
56
+
57
+ it "can add a new line item to an existing order" do
58
+ api_post :create, line_item: { variant_id: product.master.to_param, quantity: 1 }
59
+ expect(response.status).to eq(201)
60
+ expect(json_response).to have_attributes(attributes)
61
+ expect(json_response["variant"]["name"]).not_to be_blank
62
+ end
63
+
64
+ it "can add a new line item to an existing order with options" do
65
+ expect_any_instance_of(LineItem).to receive(:some_option=).with("foo")
66
+ api_post :create,
67
+ line_item: {
68
+ variant_id: product.master.to_param,
69
+ quantity: 1,
70
+ options: { some_option: "foo" }
71
+ }
72
+ expect(response.status).to eq(201)
73
+ end
74
+
75
+ it "default quantity to 1 if none is given" do
76
+ api_post :create, line_item: { variant_id: product.master.to_param }
77
+ expect(response.status).to eq(201)
78
+ expect(json_response).to have_attributes(attributes)
79
+ expect(json_response[:quantity]).to eq 1
80
+ end
81
+
82
+ it "increases a line item's quantity if it exists already" do
83
+ order.line_items.create(variant_id: product.master.id, quantity: 10)
84
+ api_post :create, line_item: { variant_id: product.master.to_param, quantity: 1 }
85
+ expect(response.status).to eq(201)
86
+ order.reload
87
+ expect(order.line_items.count).to eq(2) # 1 original due to factory, + 1 in this test
88
+ expect(json_response).to have_attributes(attributes)
89
+ expect(json_response["quantity"]).to eq(11)
90
+ end
91
+
92
+ it "can update a line item on the order" do
93
+ line_item = order.line_items.first
94
+ api_put :update, id: line_item.id, line_item: { quantity: 101 }
95
+ expect(response.status).to eq(200)
96
+ order.reload
97
+ expect(order.total).to eq(1010) # 10 original due to factory, + 1000 in this test
98
+ expect(json_response).to have_attributes(attributes)
99
+ expect(json_response["quantity"]).to eq(101)
100
+ end
101
+
102
+ it "can update a line item's options on the order" do
103
+ expect_any_instance_of(LineItem).to receive(:some_option=).with("foo")
104
+ line_item = order.line_items.first
105
+ api_put :update,
106
+ id: line_item.id,
107
+ line_item: { quantity: 1, options: { some_option: "foo" } }
108
+ expect(response.status).to eq(200)
109
+ end
110
+
111
+ it "can delete a line item on the order" do
112
+ line_item = order.line_items.first
113
+ api_delete :destroy, id: line_item.id
114
+ expect(response.status).to eq(204)
115
+ order.reload
116
+ expect(order.line_items.count).to eq(0) # 1 original due to factory, - 1 in this test
117
+ expect { line_item.reload }.to raise_error(ActiveRecord::RecordNotFound)
118
+ end
119
+
120
+ context "order contents changed after shipments were created" do
121
+ let!(:order) { Order.create }
122
+ let!(:line_item) { order.contents.add(product.master) }
123
+
124
+ before { order.create_proposed_shipments }
125
+
126
+ it "clear out shipments on create" do
127
+ expect(order.reload.shipments).not_to be_empty
128
+ api_post :create, line_item: { variant_id: product.master.to_param, quantity: 1 }
129
+ expect(order.reload.shipments).to be_empty
130
+ end
131
+
132
+ it "clear out shipments on update" do
133
+ expect(order.reload.shipments).not_to be_empty
134
+ api_put :update, id: line_item.id, line_item: { quantity: 1000 }
135
+ expect(order.reload.shipments).to be_empty
136
+ end
137
+
138
+ it "clear out shipments on delete" do
139
+ expect(order.reload.shipments).not_to be_empty
140
+ api_delete :destroy, id: line_item.id
141
+ expect(order.reload.shipments).to be_empty
142
+ end
143
+
144
+ context "order is completed" do
145
+ before do
146
+ order.reload
147
+ allow(order).to receive_messages completed?: true
148
+ allow(Order).to receive_message_chain :includes, find_by!: order
149
+ end
150
+
151
+ it "doesn't destroy shipments or restart checkout flow" do
152
+ expect(order.reload.shipments).not_to be_empty
153
+ api_post :create, line_item: { variant_id: product.master.to_param, quantity: 1 }
154
+ expect(order.reload.shipments).not_to be_empty
155
+ end
156
+
157
+ context 'deleting line items' do
158
+ let(:shipments) { order.shipments.load }
159
+
160
+ before(:each) do
161
+ allow(order).to receive(:shipments).and_return(shipments)
162
+ end
163
+
164
+ it 'restocks product after line item removal' do
165
+ line_item = order.line_items.first
166
+ variant = line_item.variant
167
+ expect do
168
+ api_delete :destroy, id: line_item.id
169
+ end.to change { variant.total_on_hand }.by(line_item.quantity)
170
+
171
+ expect(response.status).to eq(204)
172
+ order.reload
173
+ expect(order.line_items.count).to eq(0)
174
+ end
175
+
176
+ it 'calls `restock` on proper stock location' do
177
+ expect(shipments.first.stock_location).to receive(:restock)
178
+ api_delete :destroy, id: line_item.id
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ context "as just another user" do
186
+ before do
187
+ user = create(:user)
188
+ end
189
+
190
+ it "cannot add a new line item to the order" do
191
+ api_post :create, line_item: { variant_id: product.master.to_param, quantity: 1 }
192
+ assert_unauthorized!
193
+ end
194
+
195
+ it "cannot update a line item on the order" do
196
+ line_item = order.line_items.first
197
+ api_put :update, id: line_item.id, line_item: { quantity: 1000 }
198
+ assert_unauthorized!
199
+ expect(line_item.reload.quantity).not_to eq(1000)
200
+ end
201
+
202
+ it "cannot delete a line item on the order" do
203
+ line_item = order.line_items.first
204
+ api_delete :destroy, id: line_item.id
205
+ assert_unauthorized!
206
+ expect { line_item.reload }.not_to raise_error
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,122 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Api::V1::OptionTypesController, type: :controller do
5
+ render_views
6
+
7
+ let(:attributes) { [:id, :name, :presentation, :position] }
8
+ let!(:option_value) { create(:option_value) }
9
+ let!(:option_type) { option_value.option_type }
10
+
11
+ before do
12
+ stub_authentication!
13
+ end
14
+
15
+ def check_option_values(option_values)
16
+ expect(option_values.count).to eq(1)
17
+ expect(option_values.first).to have_attributes([:id, :name, :presentation,
18
+ :option_type_id, :option_type_name])
19
+ end
20
+
21
+ it "can list all option types" do
22
+ api_get :index
23
+ expect(json_response.count).to eq(1)
24
+ expect(json_response.first).to have_attributes(attributes)
25
+
26
+ check_option_values(json_response.first["option_values"])
27
+ end
28
+
29
+ it "can search for an option type" do
30
+ create(:option_type, name: "buzz")
31
+ api_get :index, q: { name_cont: option_type.name }
32
+ expect(json_response.count).to eq(1)
33
+ expect(json_response.first).to have_attributes(attributes)
34
+ end
35
+
36
+ it "can retrieve a list of specific option types" do
37
+ option_type_1 = create(:option_type)
38
+ option_type_2 = create(:option_type)
39
+ api_get :index, ids: "#{option_type.id},#{option_type_1.id}"
40
+ expect(json_response.count).to eq(2)
41
+
42
+ check_option_values(json_response.first["option_values"])
43
+ end
44
+
45
+ it "can list a single option type" do
46
+ api_get :show, id: option_type.id
47
+ expect(json_response).to have_attributes(attributes)
48
+ check_option_values(json_response["option_values"])
49
+ end
50
+
51
+ it "can learn how to create a new option type" do
52
+ api_get :new
53
+ expect(json_response["attributes"]).to eq(attributes.map(&:to_s))
54
+ expect(json_response["required_attributes"]).to_not be_empty
55
+ end
56
+
57
+ it "cannot create a new option type" do
58
+ api_post :create, option_type: {
59
+ name: "Option Type",
60
+ presentation: "Option Type"
61
+ }
62
+ assert_unauthorized!
63
+ end
64
+
65
+ it "cannot alter an option type" do
66
+ original_name = option_type.name
67
+ api_put :update, id: option_type.id,
68
+ option_type: {
69
+ name: "Option Type"
70
+ }
71
+ assert_not_found!
72
+ expect(option_type.reload.name).to eq(original_name)
73
+ end
74
+
75
+ it "cannot delete an option type" do
76
+ api_delete :destroy, id: option_type.id
77
+ assert_not_found!
78
+ expect { option_type.reload }.not_to raise_error
79
+ end
80
+
81
+ context "as an admin" do
82
+ sign_in_as_admin!
83
+
84
+ it "can create an option type" do
85
+ api_post :create, option_type: {
86
+ name: "Option Type",
87
+ presentation: "Option Type"
88
+ }
89
+ expect(json_response).to have_attributes(attributes)
90
+ expect(response.status).to eq(201)
91
+ end
92
+
93
+ it "cannot create an option type with invalid attributes" do
94
+ api_post :create, option_type: {}
95
+ expect(response.status).to eq(422)
96
+ end
97
+
98
+ it "can update an option type" do
99
+ original_name = option_type.name
100
+ api_put :update, id: option_type.id, option_type: {
101
+ name: "Option Type",
102
+ }
103
+ expect(response.status).to eq(200)
104
+
105
+ option_type.reload
106
+ expect(option_type.name).to eq("Option Type")
107
+ end
108
+
109
+ it "cannot update an option type with invalid attributes" do
110
+ api_put :update, id: option_type.id, option_type: {
111
+ name: ""
112
+ }
113
+ expect(response.status).to eq(422)
114
+ end
115
+
116
+ it "can delete an option type" do
117
+ api_delete :destroy, id: option_type.id
118
+ expect(response.status).to eq(204)
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,141 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Api::V1::OptionValuesController, type: :controller do
5
+ render_views
6
+
7
+ let(:attributes) { [:id, :name, :presentation, :option_type_name, :option_type_id, :option_type_presentation] }
8
+ let!(:option_value) { create(:option_value) }
9
+ let!(:option_type) { option_value.option_type }
10
+
11
+ before do
12
+ stub_authentication!
13
+ end
14
+
15
+ def check_option_values(option_values)
16
+ expect(option_values.count).to eq(1)
17
+ expect(option_values.first).to have_attributes([:id, :name, :presentation,
18
+ :option_type_name, :option_type_id])
19
+ end
20
+
21
+ context "without any option type scoping" do
22
+ before do
23
+ # Create another option value with a brand new option type
24
+ create(:option_value, option_type: create(:option_type))
25
+ end
26
+
27
+ it "can retrieve a list of all option values" do
28
+ api_get :index
29
+ expect(json_response.count).to eq(2)
30
+ expect(json_response.first).to have_attributes(attributes)
31
+ end
32
+ end
33
+
34
+ context "for a particular option type" do
35
+ let(:resource_scoping) { { option_type_id: option_type.id } }
36
+
37
+ it "can list all option values" do
38
+ api_get :index
39
+ expect(json_response.count).to eq(1)
40
+ expect(json_response.first).to have_attributes(attributes)
41
+ end
42
+
43
+ it "can search for an option type" do
44
+ create(:option_value, name: "buzz")
45
+ api_get :index, q: { name_cont: option_value.name }
46
+ expect(json_response.count).to eq(1)
47
+ expect(json_response.first).to have_attributes(attributes)
48
+ end
49
+
50
+ it "can retrieve a list of option types" do
51
+ option_value_1 = create(:option_value, option_type: option_type)
52
+ option_value_2 = create(:option_value, option_type: option_type)
53
+ api_get :index, ids: [option_value.id, option_value_1.id]
54
+ expect(json_response.count).to eq(2)
55
+ end
56
+
57
+ it "can list a single option value" do
58
+ api_get :show, id: option_value.id
59
+ expect(json_response).to have_attributes(attributes)
60
+ end
61
+
62
+ it "cannot create a new option value" do
63
+ api_post :create, option_value: {
64
+ name: "Option Value",
65
+ presentation: "Option Value"
66
+ }
67
+ assert_unauthorized!
68
+ end
69
+
70
+ it "cannot alter an option value" do
71
+ original_name = option_type.name
72
+ api_put :update, id: option_type.id,
73
+ option_value: {
74
+ name: "Option Value"
75
+ }
76
+ assert_not_found!
77
+ expect(option_type.reload.name).to eq(original_name)
78
+ end
79
+
80
+ it "cannot delete an option value" do
81
+ api_delete :destroy, id: option_type.id
82
+ assert_not_found!
83
+ expect { option_type.reload }.not_to raise_error
84
+ end
85
+
86
+ context "as an admin" do
87
+ sign_in_as_admin!
88
+
89
+ it "can learn how to create a new option value" do
90
+ api_get :new
91
+ expect(json_response["attributes"]).to eq(attributes.map(&:to_s))
92
+ expect(json_response["required_attributes"]).to_not be_empty
93
+ end
94
+
95
+ it "can create an option value" do
96
+ api_post :create, option_value: {
97
+ name: "Option Value",
98
+ presentation: "Option Value"
99
+ }
100
+ expect(json_response).to have_attributes(attributes)
101
+ expect(response.status).to eq(201)
102
+ end
103
+
104
+ it "cannot create an option type with invalid attributes" do
105
+ api_post :create, option_value: {}
106
+ expect(response.status).to eq(422)
107
+ end
108
+
109
+ it "can update an option value" do
110
+ original_name = option_value.name
111
+ api_put :update, id: option_value.id, option_value: {
112
+ name: "Option Value",
113
+ }
114
+ expect(response.status).to eq(200)
115
+
116
+ option_value.reload
117
+ expect(option_value.name).to eq("Option Value")
118
+ end
119
+
120
+ it "permits the correct attributes" do
121
+ expect(controller).to receive(:permitted_option_value_attributes)
122
+ api_put :update, id: option_value.id, option_value: {
123
+ name: ""
124
+ }
125
+ end
126
+
127
+ it "cannot update an option value with invalid attributes" do
128
+ api_put :update, id: option_value.id, option_value: {
129
+ name: ""
130
+ }
131
+ expect(response.status).to eq(422)
132
+ end
133
+
134
+ it "can delete an option value" do
135
+ api_delete :destroy, id: option_value.id
136
+ expect(response.status).to eq(204)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end