spree_api 3.2.9 → 3.3.0.rc1
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/app/controllers/spree/api/base_controller.rb +11 -12
- data/app/controllers/spree/api/v1/checkouts_controller.rb +5 -8
- data/app/controllers/spree/api/v1/customer_returns_controller.rb +24 -0
- data/app/controllers/spree/api/v1/orders_controller.rb +13 -24
- data/app/controllers/spree/api/v1/payments_controller.rb +2 -3
- data/app/controllers/spree/api/v1/reimbursements_controller.rb +24 -0
- data/app/controllers/spree/api/v1/shipments_controller.rb +4 -4
- data/app/controllers/spree/api/v1/zones_controller.rb +8 -3
- data/app/helpers/spree/api/api_helpers.rb +13 -1
- data/app/models/concerns/spree/user_api_authentication.rb +19 -0
- data/app/models/concerns/spree/user_api_methods.rb +7 -0
- data/app/views/spree/api/v1/customer_returns/index.v1.rabl +7 -0
- data/app/views/spree/api/v1/line_items/show.v1.rabl +0 -1
- data/app/views/spree/api/v1/reimbursements/index.v1.rabl +7 -0
- data/config/initializers/user_class_extensions.rb +7 -0
- data/config/routes.rb +3 -0
- data/spec/controllers/spree/api/base_controller_spec.rb +84 -0
- data/spec/controllers/spree/api/v1/addresses_controller_spec.rb +56 -0
- data/spec/controllers/spree/api/v1/checkouts_controller_spec.rb +361 -0
- data/spec/controllers/spree/api/v1/classifications_controller_spec.rb +48 -0
- data/spec/controllers/spree/api/v1/countries_controller_spec.rb +48 -0
- data/spec/controllers/spree/api/v1/credit_cards_controller_spec.rb +80 -0
- data/spec/controllers/spree/api/v1/customer_returns_controller_spec.rb +27 -0
- data/spec/controllers/spree/api/v1/images_controller_spec.rb +114 -0
- data/spec/controllers/spree/api/v1/inventory_units_controller_spec.rb +48 -0
- data/spec/controllers/spree/api/v1/line_items_controller_spec.rb +210 -0
- data/spec/controllers/spree/api/v1/option_types_controller_spec.rb +122 -0
- data/spec/controllers/spree/api/v1/option_values_controller_spec.rb +141 -0
- data/spec/controllers/spree/api/v1/orders_controller_spec.rb +735 -0
- data/spec/controllers/spree/api/v1/payments_controller_spec.rb +234 -0
- data/spec/controllers/spree/api/v1/product_properties_controller_spec.rb +156 -0
- data/spec/controllers/spree/api/v1/products_controller_spec.rb +409 -0
- data/spec/controllers/spree/api/v1/promotion_application_spec.rb +50 -0
- data/spec/controllers/spree/api/v1/promotions_controller_spec.rb +64 -0
- data/spec/controllers/spree/api/v1/properties_controller_spec.rb +102 -0
- data/spec/controllers/spree/api/v1/reimbursements_controller_spec.rb +24 -0
- data/spec/controllers/spree/api/v1/return_authorizations_controller_spec.rb +161 -0
- data/spec/controllers/spree/api/v1/shipments_controller_spec.rb +187 -0
- data/spec/controllers/spree/api/v1/states_controller_spec.rb +86 -0
- data/spec/controllers/spree/api/v1/stock_items_controller_spec.rb +151 -0
- data/spec/controllers/spree/api/v1/stock_locations_controller_spec.rb +113 -0
- data/spec/controllers/spree/api/v1/stock_movements_controller_spec.rb +84 -0
- data/spec/controllers/spree/api/v1/stores_controller_spec.rb +133 -0
- data/spec/controllers/spree/api/v1/tags_controller_spec.rb +102 -0
- data/spec/controllers/spree/api/v1/taxonomies_controller_spec.rb +114 -0
- data/spec/controllers/spree/api/v1/taxons_controller_spec.rb +177 -0
- data/spec/controllers/spree/api/v1/unauthenticated_products_controller_spec.rb +26 -0
- data/spec/controllers/spree/api/v1/users_controller_spec.rb +153 -0
- data/spec/controllers/spree/api/v1/variants_controller_spec.rb +205 -0
- data/spec/controllers/spree/api/v1/zones_controller_spec.rb +91 -0
- data/spec/models/spree/legacy_user_spec.rb +19 -0
- data/spec/requests/rabl_cache_spec.rb +32 -0
- data/spec/requests/ransackable_attributes_spec.rb +79 -0
- data/spec/requests/version_spec.rb +19 -0
- data/spec/shared_examples/protect_product_actions.rb +17 -0
- data/spec/spec_helper.rb +63 -0
- data/spec/support/controller_hacks.rb +40 -0
- data/spec/support/database_cleaner.rb +14 -0
- data/spec/support/have_attributes_matcher.rb +13 -0
- data/spree_api.gemspec +4 -3
- metadata +105 -13
- data/app/views/spree/api/v1/config/money.v1.rabl +0 -2
- data/app/views/spree/api/v1/config/show.v1.rabl +0 -2
@@ -0,0 +1,409 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared_examples/protect_product_actions'
|
3
|
+
|
4
|
+
module Spree
|
5
|
+
describe Api::V1::ProductsController, type: :controller do
|
6
|
+
render_views
|
7
|
+
|
8
|
+
let!(:product) { create(:product) }
|
9
|
+
let!(:inactive_product) { create(:product, available_on: Time.current.tomorrow, name: "inactive") }
|
10
|
+
let(:base_attributes) { Api::ApiHelpers.product_attributes }
|
11
|
+
let(:show_attributes) { base_attributes.dup.push(:has_variants) }
|
12
|
+
let(:new_attributes) { base_attributes }
|
13
|
+
|
14
|
+
let(:product_data) do
|
15
|
+
{ name: "The Other Product",
|
16
|
+
price: 19.99,
|
17
|
+
shipping_category_id: create(:shipping_category).id }
|
18
|
+
end
|
19
|
+
let(:attributes_for_variant) do
|
20
|
+
h = attributes_for(:variant).except(:option_values, :product)
|
21
|
+
h.merge({
|
22
|
+
options: [
|
23
|
+
{ name: "size", value: "small" },
|
24
|
+
{ name: "color", value: "black" }
|
25
|
+
]
|
26
|
+
})
|
27
|
+
end
|
28
|
+
|
29
|
+
before do
|
30
|
+
stub_authentication!
|
31
|
+
end
|
32
|
+
|
33
|
+
context "as a normal user" do
|
34
|
+
context "with caching enabled" do
|
35
|
+
let!(:product_2) { create(:product) }
|
36
|
+
|
37
|
+
before do
|
38
|
+
ActionController::Base.perform_caching = true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns unique products" do
|
42
|
+
api_get :index
|
43
|
+
product_ids = json_response["products"].map { |p| p["id"] }
|
44
|
+
expect(product_ids.uniq.count).to eq(product_ids.count)
|
45
|
+
end
|
46
|
+
|
47
|
+
after do
|
48
|
+
ActionController::Base.perform_caching = false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "retrieves a list of products" do
|
53
|
+
api_get :index
|
54
|
+
expect(json_response["products"].first).to have_attributes(show_attributes)
|
55
|
+
expect(json_response["total_count"]).to eq(1)
|
56
|
+
expect(json_response["current_page"]).to eq(1)
|
57
|
+
expect(json_response["pages"]).to eq(1)
|
58
|
+
expect(json_response["per_page"]).to eq(Kaminari.config.default_per_page)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "retrieves a list of products by id" do
|
62
|
+
api_get :index, ids: [product.id]
|
63
|
+
expect(json_response["products"].first).to have_attributes(show_attributes)
|
64
|
+
expect(json_response["total_count"]).to eq(1)
|
65
|
+
expect(json_response["current_page"]).to eq(1)
|
66
|
+
expect(json_response["pages"]).to eq(1)
|
67
|
+
expect(json_response["per_page"]).to eq(Kaminari.config.default_per_page)
|
68
|
+
end
|
69
|
+
|
70
|
+
context "product has more than one price" do
|
71
|
+
before { product.master.prices.create currency: "EUR", amount: 22 }
|
72
|
+
|
73
|
+
it "returns distinct products only" do
|
74
|
+
api_get :index
|
75
|
+
expect(assigns(:products).map(&:id).uniq).to eq assigns(:products).map(&:id)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "retrieves a list of products by ids string" do
|
80
|
+
second_product = create(:product)
|
81
|
+
api_get :index, ids: [product.id, second_product.id].join(",")
|
82
|
+
expect(json_response["products"].first).to have_attributes(show_attributes)
|
83
|
+
expect(json_response["products"][1]).to have_attributes(show_attributes)
|
84
|
+
expect(json_response["total_count"]).to eq(2)
|
85
|
+
expect(json_response["current_page"]).to eq(1)
|
86
|
+
expect(json_response["pages"]).to eq(1)
|
87
|
+
expect(json_response["per_page"]).to eq(Kaminari.config.default_per_page)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "does not return inactive products when queried by ids" do
|
91
|
+
api_get :index, ids: [inactive_product.id]
|
92
|
+
expect(json_response["count"]).to eq(0)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "does not list unavailable products" do
|
96
|
+
api_get :index
|
97
|
+
expect(json_response["products"].first["name"]).not_to eq("inactive")
|
98
|
+
end
|
99
|
+
|
100
|
+
context "pagination" do
|
101
|
+
it "can select the next page of products" do
|
102
|
+
second_product = create(:product)
|
103
|
+
api_get :index, page: 2, per_page: 1
|
104
|
+
expect(json_response["products"].first).to have_attributes(show_attributes)
|
105
|
+
expect(json_response["total_count"]).to eq(2)
|
106
|
+
expect(json_response["current_page"]).to eq(2)
|
107
|
+
expect(json_response["pages"]).to eq(2)
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'can control the page size through a parameter' do
|
111
|
+
create(:product)
|
112
|
+
api_get :index, per_page: 1
|
113
|
+
expect(json_response['count']).to eq(1)
|
114
|
+
expect(json_response['total_count']).to eq(2)
|
115
|
+
expect(json_response['current_page']).to eq(1)
|
116
|
+
expect(json_response['pages']).to eq(2)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
it "can search for products" do
|
121
|
+
create(:product, name: "The best product in the world")
|
122
|
+
api_get :index, q: { name_cont: "best" }
|
123
|
+
expect(json_response["products"].first).to have_attributes(show_attributes)
|
124
|
+
expect(json_response["count"]).to eq(1)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "gets a single product" do
|
128
|
+
product.master.images.create!(attachment: image("thinking-cat.jpg"))
|
129
|
+
create(:variant, product: product)
|
130
|
+
product.variants.first.images.create!(attachment: image("thinking-cat.jpg"))
|
131
|
+
product.set_property("spree", "rocks")
|
132
|
+
product.taxons << create(:taxon)
|
133
|
+
|
134
|
+
api_get :show, id: product.to_param
|
135
|
+
|
136
|
+
expect(json_response).to have_attributes(show_attributes)
|
137
|
+
expect(json_response['variants'].first).to have_attributes([:name,
|
138
|
+
:is_master,
|
139
|
+
:price,
|
140
|
+
:images,
|
141
|
+
:in_stock])
|
142
|
+
|
143
|
+
expect(json_response['variants'].first['images'].first).to have_attributes([:attachment_file_name,
|
144
|
+
:attachment_width,
|
145
|
+
:attachment_height,
|
146
|
+
:attachment_content_type,
|
147
|
+
:mini_url,
|
148
|
+
:small_url,
|
149
|
+
:product_url,
|
150
|
+
:large_url])
|
151
|
+
|
152
|
+
expect(json_response["product_properties"].first).to have_attributes([:value,
|
153
|
+
:product_id,
|
154
|
+
:property_name])
|
155
|
+
|
156
|
+
expect(json_response["classifications"].first).to have_attributes([:taxon_id, :position, :taxon])
|
157
|
+
expect(json_response["classifications"].first['taxon']).to have_attributes([:id, :name, :pretty_name, :permalink, :taxonomy_id, :parent_id])
|
158
|
+
end
|
159
|
+
|
160
|
+
context "tracking is disabled" do
|
161
|
+
before { Config.track_inventory_levels = false }
|
162
|
+
|
163
|
+
it "still displays valid json with total_on_hand Float::INFINITY" do
|
164
|
+
api_get :show, id: product.to_param
|
165
|
+
expect(response).to be_ok
|
166
|
+
expect(json_response[:total_on_hand]).to eq nil
|
167
|
+
end
|
168
|
+
|
169
|
+
after { Config.track_inventory_levels = true }
|
170
|
+
end
|
171
|
+
|
172
|
+
context "finds a product by slug first then by id" do
|
173
|
+
let!(:other_product) { create(:product, slug: "these-are-not-the-droids-you-are-looking-for") }
|
174
|
+
|
175
|
+
before do
|
176
|
+
product.update_column(:slug, "#{other_product.id}-and-1-ways")
|
177
|
+
end
|
178
|
+
|
179
|
+
specify do
|
180
|
+
api_get :show, id: product.to_param
|
181
|
+
expect(json_response["slug"]).to match(/and-1-ways/)
|
182
|
+
product.destroy
|
183
|
+
|
184
|
+
api_get :show, id: other_product.id
|
185
|
+
expect(json_response["slug"]).to match(/droids/)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
it "cannot see inactive products" do
|
190
|
+
api_get :show, id: inactive_product.to_param
|
191
|
+
assert_not_found!
|
192
|
+
end
|
193
|
+
|
194
|
+
it "returns a 404 error when it cannot find a product" do
|
195
|
+
api_get :show, id: "non-existant"
|
196
|
+
assert_not_found!
|
197
|
+
end
|
198
|
+
|
199
|
+
it "can learn how to create a new product" do
|
200
|
+
api_get :new
|
201
|
+
expect(json_response["attributes"]).to eq(new_attributes.map(&:to_s))
|
202
|
+
required_attributes = json_response["required_attributes"]
|
203
|
+
expect(required_attributes).to include("name")
|
204
|
+
expect(required_attributes).to include("price")
|
205
|
+
expect(required_attributes).to include("shipping_category")
|
206
|
+
end
|
207
|
+
|
208
|
+
it_behaves_like "modifying product actions are restricted"
|
209
|
+
end
|
210
|
+
|
211
|
+
context "as an admin" do
|
212
|
+
let(:taxon_1) { create(:taxon) }
|
213
|
+
let(:taxon_2) { create(:taxon) }
|
214
|
+
|
215
|
+
sign_in_as_admin!
|
216
|
+
|
217
|
+
it "can see all products" do
|
218
|
+
api_get :index
|
219
|
+
expect(json_response["products"].count).to eq(2)
|
220
|
+
expect(json_response["count"]).to eq(2)
|
221
|
+
expect(json_response["current_page"]).to eq(1)
|
222
|
+
expect(json_response["pages"]).to eq(1)
|
223
|
+
end
|
224
|
+
|
225
|
+
# Regression test for #1626
|
226
|
+
context "deleted products" do
|
227
|
+
before do
|
228
|
+
create(:product, deleted_at: 1.day.ago)
|
229
|
+
end
|
230
|
+
|
231
|
+
it "does not include deleted products" do
|
232
|
+
api_get :index
|
233
|
+
expect(json_response["products"].count).to eq(2)
|
234
|
+
end
|
235
|
+
|
236
|
+
it "can include deleted products" do
|
237
|
+
api_get :index, show_deleted: 1
|
238
|
+
expect(json_response["products"].count).to eq(3)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
describe "creating a product" do
|
243
|
+
it "can create a new product" do
|
244
|
+
api_post :create, product: { name: "The Other Product",
|
245
|
+
price: 19.99,
|
246
|
+
shipping_category_id: create(:shipping_category).id }
|
247
|
+
expect(json_response).to have_attributes(base_attributes)
|
248
|
+
expect(response.status).to eq(201)
|
249
|
+
end
|
250
|
+
|
251
|
+
it "creates with embedded variants" do
|
252
|
+
product_data.merge!({
|
253
|
+
variants: [attributes_for_variant, attributes_for_variant]
|
254
|
+
})
|
255
|
+
|
256
|
+
api_post :create, product: product_data
|
257
|
+
expect(response.status).to eq 201
|
258
|
+
|
259
|
+
variants = json_response['variants']
|
260
|
+
expect(variants.count).to eq(2)
|
261
|
+
expect(variants.last['option_values'][0]['name']).to eq('small')
|
262
|
+
expect(variants.last['option_values'][0]['option_type_name']).to eq('size')
|
263
|
+
|
264
|
+
expect(json_response['option_types'].count).to eq(2) # size, color
|
265
|
+
end
|
266
|
+
|
267
|
+
it "can create a new product with embedded product_properties" do
|
268
|
+
product_data.merge!({
|
269
|
+
product_properties_attributes: [{
|
270
|
+
property_name: "fabric",
|
271
|
+
value: "cotton"
|
272
|
+
}]
|
273
|
+
})
|
274
|
+
|
275
|
+
api_post :create, product: product_data
|
276
|
+
|
277
|
+
expect(json_response['product_properties'][0]['property_name']).to eq('fabric')
|
278
|
+
expect(json_response['product_properties'][0]['value']).to eq('cotton')
|
279
|
+
end
|
280
|
+
|
281
|
+
it "can create a new product with option_types" do
|
282
|
+
product_data.merge!({
|
283
|
+
option_types: ['size', 'color']
|
284
|
+
})
|
285
|
+
|
286
|
+
api_post :create, product: product_data
|
287
|
+
expect(json_response['option_types'].count).to eq(2)
|
288
|
+
end
|
289
|
+
|
290
|
+
it "creates product with option_types ids" do
|
291
|
+
option_type = create(:option_type)
|
292
|
+
product_data.merge!(option_type_ids: [option_type.id])
|
293
|
+
api_post :create, product: product_data
|
294
|
+
expect(json_response['option_types'].first['id']).to eq option_type.id
|
295
|
+
end
|
296
|
+
|
297
|
+
it "creates with shipping categories" do
|
298
|
+
hash = { name: "The Other Product",
|
299
|
+
price: 19.99,
|
300
|
+
shipping_category: "Free Ships" }
|
301
|
+
|
302
|
+
api_post :create, product: hash
|
303
|
+
expect(response.status).to eq 201
|
304
|
+
|
305
|
+
shipping_id = ShippingCategory.find_by_name("Free Ships").id
|
306
|
+
expect(json_response['shipping_category_id']).to eq shipping_id
|
307
|
+
end
|
308
|
+
|
309
|
+
it "puts the created product in the given taxons" do
|
310
|
+
product_data[:taxon_ids] = [taxon_1.id, taxon_2.id]
|
311
|
+
api_post :create, product: product_data
|
312
|
+
expect(json_response["taxon_ids"]).to eq([taxon_1.id, taxon_2.id])
|
313
|
+
end
|
314
|
+
|
315
|
+
# Regression test for #2140
|
316
|
+
context "with authentication_required set to false" do
|
317
|
+
before do
|
318
|
+
Spree::Api::Config.requires_authentication = false
|
319
|
+
end
|
320
|
+
|
321
|
+
after do
|
322
|
+
Spree::Api::Config.requires_authentication = true
|
323
|
+
end
|
324
|
+
|
325
|
+
it "can still create a product" do
|
326
|
+
api_post :create, product: product_data, token: "fake"
|
327
|
+
expect(json_response).to have_attributes(show_attributes)
|
328
|
+
expect(response.status).to eq(201)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
it "cannot create a new product with invalid attributes" do
|
333
|
+
api_post :create, product: { foo: :bar }
|
334
|
+
expect(response.status).to eq(422)
|
335
|
+
expect(json_response["error"]).to eq("Invalid resource. Please fix errors and try again.")
|
336
|
+
errors = json_response["errors"]
|
337
|
+
errors.delete("slug") # Don't care about this one.
|
338
|
+
expect(errors.keys).to match_array(["name", "price", "shipping_category"])
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
context 'updating a product' do
|
343
|
+
it "can update a product" do
|
344
|
+
api_put :update, id: product.to_param, product: { name: "New and Improved Product!" }
|
345
|
+
expect(response.status).to eq(200)
|
346
|
+
end
|
347
|
+
|
348
|
+
it "can create new option types on a product" do
|
349
|
+
api_put :update, id: product.to_param, product: { option_types: ['shape', 'color'] }
|
350
|
+
expect(json_response['option_types'].count).to eq(2)
|
351
|
+
end
|
352
|
+
|
353
|
+
it "can create new variants on a product" do
|
354
|
+
api_put :update, id: product.to_param, product: { variants: [attributes_for_variant, attributes_for_variant.merge(sku: "ABC-#{Kernel.rand(9999)}")] }
|
355
|
+
expect(response.status).to eq 200
|
356
|
+
expect(json_response['variants'].count).to eq(2) # 2 variants
|
357
|
+
|
358
|
+
variants = json_response['variants'].select { |v| !v['is_master'] }
|
359
|
+
expect(variants.last['option_values'][0]['name']).to eq('small')
|
360
|
+
expect(variants.last['option_values'][0]['option_type_name']).to eq('size')
|
361
|
+
|
362
|
+
expect(json_response['option_types'].count).to eq(2) # size, color
|
363
|
+
end
|
364
|
+
|
365
|
+
it "can update an existing variant on a product" do
|
366
|
+
variant_hash = {
|
367
|
+
sku: '123', price: 19.99, options: [{name: "size", value: "small"}]
|
368
|
+
}
|
369
|
+
variant_id = product.variants.create!({ product: product }.merge(variant_hash)).id
|
370
|
+
|
371
|
+
api_put :update, id: product.to_param, product: {
|
372
|
+
variants: [
|
373
|
+
variant_hash.merge(
|
374
|
+
id: variant_id.to_s,
|
375
|
+
sku: '456',
|
376
|
+
options: [{name: "size", value: "large" }]
|
377
|
+
)
|
378
|
+
]
|
379
|
+
}
|
380
|
+
|
381
|
+
expect(json_response['variants'].count).to eq(1)
|
382
|
+
variants = json_response['variants'].select { |v| !v['is_master'] }
|
383
|
+
expect(variants.last['option_values'][0]['name']).to eq('large')
|
384
|
+
expect(variants.last['sku']).to eq('456')
|
385
|
+
expect(variants.count).to eq(1)
|
386
|
+
end
|
387
|
+
|
388
|
+
it "cannot update a product with an invalid attribute" do
|
389
|
+
api_put :update, id: product.to_param, product: { name: "" }
|
390
|
+
expect(response.status).to eq(422)
|
391
|
+
expect(json_response["error"]).to eq("Invalid resource. Please fix errors and try again.")
|
392
|
+
expect(json_response["errors"]["name"]).to eq(["can't be blank"])
|
393
|
+
end
|
394
|
+
|
395
|
+
it "puts the updated product in the given taxons" do
|
396
|
+
api_put :update, id: product.to_param, product: { taxon_ids: [taxon_1.id, taxon_2.id] }
|
397
|
+
expect(json_response["taxon_ids"].to_set).to eql([taxon_1.id, taxon_2.id].to_set)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
it "can delete a product" do
|
402
|
+
expect(product.deleted_at).to be_nil
|
403
|
+
api_delete :destroy, id: product.to_param
|
404
|
+
expect(response.status).to eq(204)
|
405
|
+
expect(product.reload.deleted_at).not_to be_nil
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
describe Api::V1::OrdersController, type: :controller do
|
5
|
+
render_views
|
6
|
+
|
7
|
+
before do
|
8
|
+
stub_authentication!
|
9
|
+
end
|
10
|
+
|
11
|
+
context "with an available promotion" do
|
12
|
+
let!(:order) { create(:order_with_line_items, line_items_count: 1) }
|
13
|
+
let!(:promotion) do
|
14
|
+
promotion = Spree::Promotion.create(name: "10% off", code: "10off")
|
15
|
+
calculator = Spree::Calculator::FlatPercentItemTotal.create(preferred_flat_percent: "10")
|
16
|
+
action = Spree::Promotion::Actions::CreateItemAdjustments.create(calculator: calculator)
|
17
|
+
promotion.actions << action
|
18
|
+
promotion
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can apply a coupon code to the order" do
|
22
|
+
expect(order.total).to eq(110.00)
|
23
|
+
api_put :apply_coupon_code, id: order.to_param, coupon_code: "10off", order_token: order.guest_token
|
24
|
+
expect(response.status).to eq(200)
|
25
|
+
expect(order.reload.total).to eq(109.00)
|
26
|
+
expect(json_response["success"]).to eq("The coupon code was successfully applied to your order.")
|
27
|
+
expect(json_response["error"]).to be_blank
|
28
|
+
expect(json_response["successful"]).to be true
|
29
|
+
expect(json_response["status_code"]).to eq("coupon_code_applied")
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with an expired promotion" do
|
33
|
+
before do
|
34
|
+
promotion.starts_at = 2.weeks.ago
|
35
|
+
promotion.expires_at = 1.week.ago
|
36
|
+
promotion.save
|
37
|
+
end
|
38
|
+
|
39
|
+
it "fails to apply" do
|
40
|
+
api_put :apply_coupon_code, id: order.to_param, coupon_code: "10off", order_token: order.guest_token
|
41
|
+
expect(response.status).to eq(422)
|
42
|
+
expect(json_response["success"]).to be_blank
|
43
|
+
expect(json_response["error"]).to eq("The coupon code is expired")
|
44
|
+
expect(json_response["successful"]).to be false
|
45
|
+
expect(json_response["status_code"]).to eq("coupon_code_expired")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
describe Api::V1::PromotionsController, type: :controller do
|
5
|
+
render_views
|
6
|
+
|
7
|
+
shared_examples "a JSON response" do
|
8
|
+
it 'should be ok' do
|
9
|
+
expect(subject).to be_ok
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should return JSON' do
|
13
|
+
payload = HashWithIndifferentAccess.new(JSON.parse(subject.body))
|
14
|
+
expect(payload).to_not be_nil
|
15
|
+
Spree::Api::ApiHelpers.promotion_attributes.each do |attribute|
|
16
|
+
expect(payload.has_key?(attribute)).to be true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
before do
|
22
|
+
stub_authentication!
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:promotion) { create :promotion, :with_order_adjustment, code: '10off' }
|
26
|
+
|
27
|
+
describe 'GET #show' do
|
28
|
+
subject { api_get :show, id: id }
|
29
|
+
|
30
|
+
context 'when admin' do
|
31
|
+
sign_in_as_admin!
|
32
|
+
|
33
|
+
context 'when finding by id' do
|
34
|
+
let(:id) { promotion.id }
|
35
|
+
|
36
|
+
it_behaves_like "a JSON response"
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when finding by code' do
|
40
|
+
let(:id) { promotion.code }
|
41
|
+
|
42
|
+
it_behaves_like "a JSON response"
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when id does not exist' do
|
46
|
+
let(:id) { 'argh' }
|
47
|
+
|
48
|
+
it 'should be 404' do
|
49
|
+
expect(subject.status).to eq(404)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when non admin' do
|
55
|
+
let(:id) { promotion.id }
|
56
|
+
|
57
|
+
it 'should be unauthorized' do
|
58
|
+
subject
|
59
|
+
assert_unauthorized!
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Spree
|
3
|
+
describe Api::V1::PropertiesController, type: :controller do
|
4
|
+
render_views
|
5
|
+
|
6
|
+
let!(:property_1) { Property.create!(name: "foo", presentation: "Foo") }
|
7
|
+
let!(:property_2) { Property.create!(name: "bar", presentation: "Bar") }
|
8
|
+
|
9
|
+
let(:attributes) { [:id, :name, :presentation] }
|
10
|
+
|
11
|
+
before do
|
12
|
+
stub_authentication!
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can see a list of all properties" do
|
16
|
+
api_get :index
|
17
|
+
expect(json_response["properties"].count).to eq(2)
|
18
|
+
expect(json_response["properties"].first).to have_attributes(attributes)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can control the page size through a parameter" do
|
22
|
+
api_get :index, per_page: 1
|
23
|
+
expect(json_response['properties'].count).to eq(1)
|
24
|
+
expect(json_response['current_page']).to eq(1)
|
25
|
+
expect(json_response['pages']).to eq(2)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can query the results through a parameter' do
|
29
|
+
api_get :index, q: { name_cont: 'ba' }
|
30
|
+
expect(json_response['count']).to eq(1)
|
31
|
+
expect(json_response['properties'].first['presentation']).to eq property_2.presentation
|
32
|
+
end
|
33
|
+
|
34
|
+
it "retrieves a list of properties by id" do
|
35
|
+
api_get :index, ids: [property_1.id]
|
36
|
+
expect(json_response["properties"].first).to have_attributes(attributes)
|
37
|
+
expect(json_response["count"]).to eq(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "retrieves a list of properties by ids string" do
|
41
|
+
api_get :index, ids: [property_1.id, property_2.id].join(",")
|
42
|
+
expect(json_response["properties"].first).to have_attributes(attributes)
|
43
|
+
expect(json_response["properties"][1]).to have_attributes(attributes)
|
44
|
+
expect(json_response["count"]).to eq(2)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "can see a single property" do
|
48
|
+
api_get :show, id: property_1.id
|
49
|
+
expect(json_response).to have_attributes(attributes)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can see a property by name" do
|
53
|
+
api_get :show, id: property_1.name
|
54
|
+
expect(json_response).to have_attributes(attributes)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "can learn how to create a new property" do
|
58
|
+
api_get :new
|
59
|
+
expect(json_response["attributes"]).to eq(attributes.map(&:to_s))
|
60
|
+
expect(json_response["required_attributes"]).to be_empty
|
61
|
+
end
|
62
|
+
|
63
|
+
it "cannot create a new property if not an admin" do
|
64
|
+
api_post :create, property: { name: "My Property 3" }
|
65
|
+
assert_unauthorized!
|
66
|
+
end
|
67
|
+
|
68
|
+
it "cannot update a property" do
|
69
|
+
api_put :update, id: property_1.name, property: { presentation: "my value 456" }
|
70
|
+
assert_unauthorized!
|
71
|
+
end
|
72
|
+
|
73
|
+
it "cannot delete a property" do
|
74
|
+
api_delete :destroy, id: property_1.id
|
75
|
+
assert_unauthorized!
|
76
|
+
expect { property_1.reload }.not_to raise_error
|
77
|
+
end
|
78
|
+
|
79
|
+
context "as an admin" do
|
80
|
+
sign_in_as_admin!
|
81
|
+
|
82
|
+
it "can create a new property" do
|
83
|
+
expect(Spree::Property.count).to eq(2)
|
84
|
+
api_post :create, property: { name: "My Property 3", presentation: "my value 3" }
|
85
|
+
expect(json_response).to have_attributes(attributes)
|
86
|
+
expect(response.status).to eq(201)
|
87
|
+
expect(Spree::Property.count).to eq(3)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "can update a property" do
|
91
|
+
api_put :update, id: property_1.name, property: { presentation: "my value 456" }
|
92
|
+
expect(response.status).to eq(200)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "can delete a property" do
|
96
|
+
api_delete :destroy, id: property_1.name
|
97
|
+
expect(response.status).to eq(204)
|
98
|
+
expect { property_1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
describe Api::V1::ReimbursementsController, type: :controller do
|
5
|
+
render_views
|
6
|
+
|
7
|
+
before do
|
8
|
+
stub_authentication!
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#index' do
|
12
|
+
let!(:reimbursement) { create(:reimbursement) }
|
13
|
+
|
14
|
+
before do
|
15
|
+
api_get :index
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'loads reimbursements' do
|
19
|
+
expect(response.status).to eq(200)
|
20
|
+
expect(json_response['count']).to eq(1)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|