shopify_api 9.0.4 → 9.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +36 -0
  3. data/.github/workflows/build.yml +41 -0
  4. data/.gitignore +2 -1
  5. data/.rubocop.yml +23 -3
  6. data/.rubocop_todo.yml +75 -0
  7. data/CHANGELOG.md +37 -0
  8. data/CONTRIBUTING.md +1 -1
  9. data/Gemfile +5 -0
  10. data/Gemfile.lock +151 -0
  11. data/Gemfile_ar51 +1 -1
  12. data/README.md +42 -32
  13. data/RELEASING +10 -6
  14. data/Rakefile +16 -5
  15. data/SECURITY.md +59 -0
  16. data/docs/_config.yml +1 -0
  17. data/docs/_includes/footer.html +28 -0
  18. data/docs/_includes/head.html +28 -0
  19. data/docs/_layouts/index.html +57 -0
  20. data/docs/graphql.md +47 -2
  21. data/docs/index.md +639 -0
  22. data/lib/active_resource/connection_ext.rb +1 -0
  23. data/lib/active_resource/detailed_log_subscriber.rb +10 -7
  24. data/lib/active_resource/json_errors.rb +8 -2
  25. data/lib/shopify_api.rb +8 -1
  26. data/lib/shopify_api/api_access.rb +57 -0
  27. data/lib/shopify_api/api_version.rb +6 -5
  28. data/lib/shopify_api/connection.rb +1 -0
  29. data/lib/shopify_api/countable.rb +3 -2
  30. data/lib/shopify_api/disable_prefix_check.rb +2 -2
  31. data/lib/shopify_api/events.rb +2 -1
  32. data/lib/shopify_api/graphql.rb +28 -8
  33. data/lib/shopify_api/limits.rb +3 -2
  34. data/lib/shopify_api/message_enricher.rb +11 -9
  35. data/lib/shopify_api/meta.rb +0 -1
  36. data/lib/shopify_api/metafields.rb +5 -4
  37. data/lib/shopify_api/pagination_link_headers.rb +5 -4
  38. data/lib/shopify_api/resources.rb +1 -0
  39. data/lib/shopify_api/resources/access_scope.rb +1 -1
  40. data/lib/shopify_api/resources/access_token.rb +1 -0
  41. data/lib/shopify_api/resources/address.rb +1 -0
  42. data/lib/shopify_api/resources/announcement.rb +2 -1
  43. data/lib/shopify_api/resources/application_charge.rb +1 -0
  44. data/lib/shopify_api/resources/application_credit.rb +1 -0
  45. data/lib/shopify_api/resources/article.rb +3 -2
  46. data/lib/shopify_api/resources/asset.rb +6 -5
  47. data/lib/shopify_api/resources/assigned_fulfillment_order.rb +1 -1
  48. data/lib/shopify_api/resources/base.rb +12 -8
  49. data/lib/shopify_api/resources/billing_address.rb +1 -0
  50. data/lib/shopify_api/resources/blog.rb +2 -1
  51. data/lib/shopify_api/resources/carrier_service.rb +1 -0
  52. data/lib/shopify_api/resources/cart.rb +2 -1
  53. data/lib/shopify_api/resources/collect.rb +1 -0
  54. data/lib/shopify_api/resources/collection_listing.rb +1 -0
  55. data/lib/shopify_api/resources/comment.rb +20 -5
  56. data/lib/shopify_api/resources/country.rb +1 -0
  57. data/lib/shopify_api/resources/custom_collection.rb +4 -3
  58. data/lib/shopify_api/resources/customer.rb +2 -1
  59. data/lib/shopify_api/resources/customer_group.rb +1 -0
  60. data/lib/shopify_api/resources/customer_invite.rb +1 -0
  61. data/lib/shopify_api/resources/customer_saved_search.rb +2 -1
  62. data/lib/shopify_api/resources/discount_code.rb +1 -0
  63. data/lib/shopify_api/resources/discount_code_batch.rb +4 -2
  64. data/lib/shopify_api/resources/draft_order.rb +1 -0
  65. data/lib/shopify_api/resources/draft_order_invoice.rb +1 -0
  66. data/lib/shopify_api/resources/event.rb +1 -0
  67. data/lib/shopify_api/resources/fulfillment.rb +12 -3
  68. data/lib/shopify_api/resources/fulfillment_event.rb +1 -0
  69. data/lib/shopify_api/resources/fulfillment_order.rb +30 -16
  70. data/lib/shopify_api/resources/fulfillment_order_locations_for_move.rb +1 -0
  71. data/lib/shopify_api/resources/fulfillment_request.rb +1 -0
  72. data/lib/shopify_api/resources/fulfillment_service.rb +1 -0
  73. data/lib/shopify_api/resources/fulfillment_v2.rb +3 -2
  74. data/lib/shopify_api/resources/gift_card.rb +1 -0
  75. data/lib/shopify_api/resources/image.rb +2 -1
  76. data/lib/shopify_api/resources/inventory_level.rb +3 -4
  77. data/lib/shopify_api/resources/line_item.rb +4 -3
  78. data/lib/shopify_api/resources/location.rb +1 -1
  79. data/lib/shopify_api/resources/marketing_event.rb +1 -0
  80. data/lib/shopify_api/resources/metafield.rb +1 -0
  81. data/lib/shopify_api/resources/note_attribute.rb +1 -0
  82. data/lib/shopify_api/resources/option.rb +1 -0
  83. data/lib/shopify_api/resources/order.rb +2 -1
  84. data/lib/shopify_api/resources/order_risk.rb +1 -0
  85. data/lib/shopify_api/resources/page.rb +1 -0
  86. data/lib/shopify_api/resources/payment_details.rb +1 -0
  87. data/lib/shopify_api/resources/policy.rb +1 -0
  88. data/lib/shopify_api/resources/price_rule.rb +1 -1
  89. data/lib/shopify_api/resources/product.rb +27 -3
  90. data/lib/shopify_api/resources/product_listing.rb +1 -0
  91. data/lib/shopify_api/resources/province.rb +1 -0
  92. data/lib/shopify_api/resources/receipt.rb +1 -0
  93. data/lib/shopify_api/resources/recurring_application_charge.rb +4 -1
  94. data/lib/shopify_api/resources/redirect.rb +1 -0
  95. data/lib/shopify_api/resources/refund.rb +2 -1
  96. data/lib/shopify_api/resources/report.rb +1 -0
  97. data/lib/shopify_api/resources/resource_feedback.rb +1 -1
  98. data/lib/shopify_api/resources/rule.rb +1 -0
  99. data/lib/shopify_api/resources/script_tag.rb +1 -0
  100. data/lib/shopify_api/resources/shipping_address.rb +1 -0
  101. data/lib/shopify_api/resources/shipping_line.rb +1 -0
  102. data/lib/shopify_api/resources/shipping_zone.rb +1 -0
  103. data/lib/shopify_api/resources/shop.rb +2 -1
  104. data/lib/shopify_api/resources/smart_collection.rb +4 -8
  105. data/lib/shopify_api/resources/storefront_access_token.rb +1 -0
  106. data/lib/shopify_api/resources/tax_line.rb +1 -0
  107. data/lib/shopify_api/resources/tax_service.rb +1 -0
  108. data/lib/shopify_api/resources/theme.rb +1 -0
  109. data/lib/shopify_api/resources/transaction.rb +1 -0
  110. data/lib/shopify_api/resources/usage_charge.rb +1 -0
  111. data/lib/shopify_api/resources/user.rb +1 -0
  112. data/lib/shopify_api/resources/variant.rb +35 -0
  113. data/lib/shopify_api/resources/webhook.rb +1 -0
  114. data/lib/shopify_api/session.rb +51 -15
  115. data/lib/shopify_api/version.rb +2 -1
  116. data/lib/verify_docs.rb +8 -0
  117. data/service.yml +1 -1
  118. data/shopify_api.gemspec +11 -6
  119. data/test/access_token_test.rb +6 -5
  120. data/test/active_resource/json_errors_test.rb +6 -6
  121. data/test/api_access_test.rb +153 -0
  122. data/test/api_version_test.rb +3 -3
  123. data/test/application_charge_test.rb +30 -27
  124. data/test/application_credit_test.rb +10 -9
  125. data/test/article_test.rb +34 -35
  126. data/test/asset_test.rb +14 -6
  127. data/test/assigned_fulfillment_order_test.rb +5 -4
  128. data/test/base_test.rb +64 -49
  129. data/test/blog_test.rb +4 -3
  130. data/test/carrier_service_test.rb +7 -6
  131. data/test/cart_test.rb +2 -1
  132. data/test/collect_test.rb +4 -3
  133. data/test/collection_listing_test.rb +21 -16
  134. data/test/collection_publication_test.rb +8 -8
  135. data/test/collection_test.rb +20 -19
  136. data/test/countable_test.rb +3 -2
  137. data/test/currency_test.rb +5 -5
  138. data/test/custom_collection_test.rb +4 -3
  139. data/test/customer_saved_search_test.rb +18 -8
  140. data/test/customer_test.rb +22 -14
  141. data/test/detailed_log_subscriber_test.rb +16 -12
  142. data/test/discount_code_batch_test.rb +11 -10
  143. data/test/discount_code_test.rb +21 -15
  144. data/test/draft_order_test.rb +68 -52
  145. data/test/fixtures/assigned_fulfillment_orders.json +2 -0
  146. data/test/fixtures/fulfillment_order.json +1 -0
  147. data/test/fixtures/fulfillment_orders.json +2 -0
  148. data/test/fulfillment_event_test.rb +31 -26
  149. data/test/fulfillment_order_test.rb +215 -147
  150. data/test/fulfillment_order_test_helper.rb +1 -0
  151. data/test/fulfillment_request_test.rb +10 -8
  152. data/test/fulfillment_service_test.rb +13 -12
  153. data/test/fulfillment_test.rb +81 -66
  154. data/test/fulfillment_v2_test.rb +16 -12
  155. data/test/gift_card_test.rb +6 -4
  156. data/test/graphql_test.rb +55 -23
  157. data/test/image_test.rb +19 -17
  158. data/test/inventory_level_test.rb +24 -15
  159. data/test/lib/webmock_extensions/last_request.rb +1 -1
  160. data/test/limits_test.rb +2 -1
  161. data/test/location_test.rb +2 -1
  162. data/test/marketing_event_test.rb +20 -20
  163. data/test/message_enricher_test.rb +6 -6
  164. data/test/meta_test.rb +7 -9
  165. data/test/metafield_test.rb +30 -20
  166. data/test/order_risk_test.rb +17 -16
  167. data/test/order_test.rb +43 -28
  168. data/test/pagination_test.rb +89 -56
  169. data/test/policy_test.rb +6 -5
  170. data/test/price_rule_test.rb +20 -15
  171. data/test/product_listing_test.rb +20 -20
  172. data/test/product_publication_test.rb +8 -8
  173. data/test/product_test.rb +71 -20
  174. data/test/publication_test.rb +3 -3
  175. data/test/recurring_application_charge_test.rb +104 -42
  176. data/test/redirect_test.rb +4 -3
  177. data/test/refund_test.rb +22 -17
  178. data/test/report_test.rb +12 -10
  179. data/test/resource_feedback_test.rb +14 -13
  180. data/test/script_tag_test.rb +10 -9
  181. data/test/session_test.rb +313 -43
  182. data/test/shipping_zone_test.rb +4 -3
  183. data/test/shop_test.rb +47 -33
  184. data/test/smart_collection_test.rb +5 -29
  185. data/test/storefront_access_token_test.rb +13 -15
  186. data/test/tax_service_test.rb +7 -4
  187. data/test/tender_transaction_test.rb +3 -3
  188. data/test/test_helper.rb +14 -12
  189. data/test/transaction_test.rb +4 -3
  190. data/test/usage_charge_test.rb +12 -8
  191. data/test/user_test.rb +4 -3
  192. data/test/variant_test.rb +50 -23
  193. data/test/webhook_test.rb +10 -7
  194. metadata +24 -14
  195. data/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml +0 -1027
  196. data/.travis.yml +0 -23
  197. data/bin/shopify +0 -3
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
 
3
4
  class RedirectTest < Test::Unit::TestCase
4
5
  test "#create should create a redirect" do
5
- fake "redirects", :method => :post, :status => 201, :body => load_fixture('redirect')
6
- redirect = ShopifyAPI::Redirect.create(:path => "/ipod", :target => "/pages/itunes")
7
- assert_equal 979034150, redirect.id
6
+ fake("redirects", method: :post, status: 201, body: load_fixture('redirect'))
7
+ redirect = ShopifyAPI::Redirect.create(path: "/ipod", target: "/pages/itunes")
8
+ assert_equal(979034150, redirect.id)
8
9
  end
9
10
  end
data/test/refund_test.rb CHANGED
@@ -1,32 +1,37 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
 
3
4
  class RefundTest < Test::Unit::TestCase
4
-
5
5
  test '#create should create a refund' do
6
- fake "orders/450789469/refunds", :method => :post, :status => 201, :body => load_fixture('refund')
6
+ fake("orders/450789469/refunds", method: :post, status: 201, body: load_fixture('refund'))
7
7
  refund = ShopifyAPI::Refund.create(
8
- :order_id => 450789469,
9
- :restock => true,
10
- :note => "wrong size",
11
- :shipping => { :full_refund => true },
12
- :refund_line_items => [{ :line_item_id => 518995019, :quantity => 1 }]
8
+ order_id: 450789469,
9
+ restock: true,
10
+ note: "wrong size",
11
+ shipping: { full_refund: true },
12
+ refund_line_items: [{ line_item_id: 518995019, quantity: 1 }]
13
13
  )
14
- assert_equal 703073504, refund.refund_line_items.first.line_item_id
14
+ assert_equal(703073504, refund.refund_line_items.first.line_item_id)
15
15
  end
16
16
 
17
17
  test '#find should return a refund' do
18
- fake "orders/450789469/refunds/509562969.json?order_id=450789469", :extension => false, :method => :get, :body => load_fixture('refund')
19
- fake "orders/450789469/refunds/509562969", :method => :get, :body => load_fixture('refund')
20
- refund = ShopifyAPI::Refund.find(509562969, :params => {:order_id => 450789469})
21
- assert_equal 509562969, refund.id
18
+ fake(
19
+ "orders/450789469/refunds/509562969.json?order_id=450789469",
20
+ extension: false,
21
+ method: :get,
22
+ body: load_fixture('refund')
23
+ )
24
+ fake("orders/450789469/refunds/509562969", method: :get, body: load_fixture('refund'))
25
+ refund = ShopifyAPI::Refund.find(509562969, params: { order_id: 450789469 })
26
+ assert_equal(509562969, refund.id)
22
27
  end
23
28
 
24
29
  test '#calculate a refund' do
25
- fake "orders/450789469/refunds/calculate", :method => :post, :body => load_fixture('refund')
26
- data = { :shipping => { :amount => 0 } }
30
+ fake("orders/450789469/refunds/calculate", method: :post, body: load_fixture('refund'))
31
+ data = { shipping: { amount: 0 } }
27
32
 
28
- refund = ShopifyAPI::Refund.calculate(data, :params => {:order_id => 450789469})
29
- assert_equal 2, refund.refund_line_items.count
30
- assert_equal 703073504, refund.refund_line_items.first.line_item_id
33
+ refund = ShopifyAPI::Refund.calculate(data, params: { order_id: 450789469 })
34
+ assert_equal(2, refund.refund_line_items.count)
35
+ assert_equal(703073504, refund.refund_line_items.first.line_item_id)
31
36
  end
32
37
  end
data/test/report_test.rb CHANGED
@@ -1,35 +1,37 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
 
3
4
  class ReportTest < Test::Unit::TestCase
4
5
  test 'get should get a report' do
5
- fake 'reports/987', method: :get, status: 200, body: load_fixture('report')
6
+ fake('reports/987', method: :get, status: 200, body: load_fixture('report'))
6
7
 
7
8
  report = ShopifyAPI::Report.find(987)
8
- assert_equal 987, report.id
9
+ assert_equal(987, report.id)
9
10
  end
10
11
 
11
12
  test 'get all should get all reports' do
12
- fake 'reports', method: :get, status: 200, body: load_fixture('reports')
13
+ fake('reports', method: :get, status: 200, body: load_fixture('reports'))
13
14
 
14
15
  reports = ShopifyAPI::Report.all
15
- assert_equal 'custom_app_reports', reports.first.category
16
+ assert_equal('custom_app_reports', reports.first.category)
16
17
  end
17
18
 
18
19
  test 'create should create a report' do
19
- fake 'reports', method: :post, status: 201, body: load_fixture('report')
20
+ fake('reports', method: :post, status: 201, body: load_fixture('report'))
20
21
 
21
22
  report = ShopifyAPI::Report.create(
22
23
  name: 'Custom App Report',
23
- shopify_ql: 'SHOW quantity_count, total_sales BY product_type, vendor, product_title FROM products SINCE -1m UNTIL -0m ORDER BY total_sales DESC'
24
+ shopify_ql: 'SHOW quantity_count, total_sales BY product_type, vendor, product_title ' \
25
+ 'FROM products SINCE -1m UNTIL -0m ORDER BY total_sales DESC'
24
26
  )
25
- assert_equal 'custom_app_reports', report.category
27
+ assert_equal('custom_app_reports', report.category)
26
28
  end
27
29
 
28
30
  test 'delete should delete report' do
29
- fake 'reports/987', method: :get, status: 200, body: load_fixture('report')
30
- fake 'reports/987', method: :delete, status: 200, body: '[]'
31
+ fake('reports/987', method: :get, status: 200, body: load_fixture('report'))
32
+ fake('reports/987', method: :delete, status: 200, body: '[]')
31
33
 
32
34
  report = ShopifyAPI::Report.find(987)
33
- assert report.destroy
35
+ assert(report.destroy)
34
36
  end
35
37
  end
@@ -1,41 +1,42 @@
1
+ # frozen_string_literal: true
1
2
  class ResourceFeedbackTest < Test::Unit::TestCase
2
3
  def test_get_resource_feedback
3
- body = { resource_feedback: [ { resource_type: 'Shop' } ] }.to_json
4
- fake 'resource_feedback', method: :get, body: body
4
+ body = { resource_feedback: [{ resource_type: 'Shop' }] }.to_json
5
+ fake('resource_feedback', method: :get, body: body)
5
6
  resource_feedback = ShopifyAPI::ResourceFeedback.find(:all)
6
- assert_equal 'Shop', resource_feedback.first.resource_type
7
+ assert_equal('Shop', resource_feedback.first.resource_type)
7
8
  end
8
9
 
9
10
  def test_save_with_resource_feedback_endpoint
10
11
  body = { resource_feedback: {} }.to_json
11
- fake 'resource_feedback', method: :post, body: body
12
+ fake('resource_feedback', method: :post, body: body)
12
13
  ShopifyAPI::ResourceFeedback.new.save
13
- assert_request_body body
14
+ assert_request_body(body)
14
15
  end
15
16
 
16
17
  def test_get_resource_feedback_with_product_id
17
- body = { resource_feedback: [ { resource_type: 'Product' } ] }.to_json
18
- fake 'products/42/resource_feedback', method: :get, body: body
18
+ body = { resource_feedback: [{ resource_type: 'Product' }] }.to_json
19
+ fake('products/42/resource_feedback', method: :get, body: body)
19
20
  resource_feedback = ShopifyAPI::ResourceFeedback.find(:all, params: { product_id: 42 })
20
- assert_equal 'Product', resource_feedback.first.resource_type
21
+ assert_equal('Product', resource_feedback.first.resource_type)
21
22
  end
22
23
 
23
24
  def test_save_with_product_id_resource_feedback_endpoint
24
25
  body = { resource_feedback: {} }.to_json
25
- fake 'products/42/resource_feedback', method: :post, body: body
26
+ fake('products/42/resource_feedback', method: :post, body: body)
26
27
  ShopifyAPI::ResourceFeedback.new(product_id: 42).save
27
- assert_request_body body
28
+ assert_request_body(body)
28
29
  end
29
30
 
30
31
  def test_save_raises_exception_when_already_persisted
31
32
  body = { resource_feedback: {} }.to_json
32
- fake 'resource_feedback', method: :post, body: body
33
+ fake('resource_feedback', method: :post, body: body)
33
34
  resource_feedback = ShopifyAPI::ResourceFeedback.new
34
35
  resource_feedback.save
35
- assert_request_body body
36
+ assert_request_body(body)
36
37
 
37
38
  ShopifyAPI::ResourceFeedback.any_instance.expects(:persisted?).returns(true)
38
- assert_raises ShopifyAPI::ResourceFeedback::ExistingFeedbackSaved do
39
+ assert_raises(ShopifyAPI::ResourceFeedback::ExistingFeedbackSaved) do
39
40
  resource_feedback.save
40
41
  end
41
42
  end
@@ -1,30 +1,31 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
 
3
4
  class ScriptTagTest < Test::Unit::TestCase
4
5
  test "get all should get all script tags" do
5
- fake 'script_tags', :method => :get, :status => 200, :body => load_fixture('script_tags')
6
+ fake('script_tags', method: :get, status: 200, body: load_fixture('script_tags'))
6
7
  script_tags = ShopifyAPI::ScriptTag.all
7
- assert_equal "http://js-aplenty.com/bar.js", script_tags.first.src
8
+ assert_equal("http://js-aplenty.com/bar.js", script_tags.first.src)
8
9
  end
9
10
 
10
11
  test "get should get a script tag" do
11
- fake 'script_tags/421379493', :method => :get, :status => 200, :body => load_fixture('script_tag')
12
+ fake('script_tags/421379493', method: :get, status: 200, body: load_fixture('script_tag'))
12
13
  script_tag = ShopifyAPI::ScriptTag.find(421379493)
13
- assert_equal "http://js-aplenty.com/bar.js", script_tag.src
14
+ assert_equal("http://js-aplenty.com/bar.js", script_tag.src)
14
15
  end
15
16
 
16
17
  test "create should create a new script tag" do
17
- fake 'script_tags', :method => :post, :status => 201, :body => load_fixture('script_tag')
18
+ fake('script_tags', method: :post, status: 201, body: load_fixture('script_tag'))
18
19
  script_tag = ShopifyAPI::ScriptTag.create(event: "onload", src: "http://js-aplenty.com/bar.js")
19
- assert_equal "http://js-aplenty.com/bar.js", script_tag.src
20
+ assert_equal("http://js-aplenty.com/bar.js", script_tag.src)
20
21
  end
21
22
 
22
23
  test "editing script tag should update script tag" do
23
- fake 'script_tags/421379493', :method => :get, :status => 200, :body => load_fixture('script_tag')
24
+ fake('script_tags/421379493', method: :get, status: 200, body: load_fixture('script_tag'))
24
25
  script_tag = ShopifyAPI::ScriptTag.find(421379493)
25
26
  script_tag.src = "http://js-aplenty.com/bar.js"
26
- fake 'script_tags/421379493', :method => :put, :status => 200, :body => load_fixture('script_tag')
27
+ fake('script_tags/421379493', method: :put, status: 200, body: load_fixture('script_tag'))
27
28
  script_tag.save
28
- assert_equal "http://js-aplenty.com/bar.js", script_tag.src
29
+ assert_equal("http://js-aplenty.com/bar.js", script_tag.src)
29
30
  end
30
31
  end
data/test/session_test.rb CHANGED
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
  require 'timecop'
3
4
 
4
5
  class SessionTest < Test::Unit::TestCase
6
+ SECONDS_IN_A_DAY = 24 * 60 * 60
5
7
 
6
8
  def setup
7
9
  super
@@ -10,20 +12,37 @@ class SessionTest < Test::Unit::TestCase
10
12
 
11
13
  test "not be valid without a url" do
12
14
  session = ShopifyAPI::Session.new(domain: nil, token: "any-token", api_version: any_api_version)
13
- assert_not session.valid?
15
+ assert_not(session.valid?)
14
16
  end
15
17
 
16
18
  test "not be valid without token" do
17
19
  session = ShopifyAPI::Session.new(domain: "testshop.myshopify.com", token: nil, api_version: any_api_version)
18
- assert_not session.valid?
20
+ assert_not(session.valid?)
19
21
  end
20
22
 
21
- test "not be valid without an api version" do
23
+ test "not be valid without an API version" do
22
24
  session = ShopifyAPI::Session.new(domain: "testshop.myshopify.com", token: "any-token", api_version: nil)
23
- assert_not session.valid?
25
+ assert_not(session.valid?)
24
26
 
25
- session = ShopifyAPI::Session.new(domain: "testshop.myshopify.com", token: "any-token", api_version: ShopifyAPI::ApiVersion::NullVersion)
26
- assert_not session.valid?
27
+ session = ShopifyAPI::Session.new(
28
+ domain: "testshop.myshopify.com", token: "any-token", api_version: ShopifyAPI::ApiVersion::NullVersion
29
+ )
30
+ assert_not(session.valid?)
31
+ end
32
+
33
+ test "default to base API version" do
34
+ session = ShopifyAPI::Session.new(domain: "testshop.myshopify.com", token: "any-token")
35
+ assert(session.valid?)
36
+ assert_equal(session.api_version, ShopifyAPI::Base.api_version)
37
+ end
38
+
39
+ test "can override the base API version" do
40
+ different_api_version = '2020-01'
41
+ session = ShopifyAPI::Session.new(
42
+ domain: "testshop.myshopify.com", token: "any-token", api_version: different_api_version
43
+ )
44
+ assert(session.valid?)
45
+ assert_equal(session.api_version, ShopifyAPI::ApiVersion.find_version(different_api_version))
27
46
  end
28
47
 
29
48
  test "be valid with any token, any url and version" do
@@ -32,7 +51,40 @@ class SessionTest < Test::Unit::TestCase
32
51
  token: "any-token",
33
52
  api_version: any_api_version
34
53
  )
35
- assert session.valid?
54
+ assert(session.valid?)
55
+ end
56
+
57
+ test "be valid with nil access_scopes" do
58
+ session = ShopifyAPI::Session.new(
59
+ domain: "testshop.myshopify.com",
60
+ token: "any-token",
61
+ api_version: any_api_version,
62
+ access_scopes: nil
63
+ )
64
+
65
+ assert(session.valid?)
66
+ end
67
+
68
+ test "be valid with string of access_scopes" do
69
+ session = ShopifyAPI::Session.new(
70
+ domain: "testshop.myshopify.com",
71
+ token: "any-token",
72
+ api_version: any_api_version,
73
+ access_scopes: "read_products, write_orders"
74
+ )
75
+
76
+ assert(session.valid?)
77
+ end
78
+
79
+ test "be valid with a collection of access_scopes" do
80
+ session = ShopifyAPI::Session.new(
81
+ domain: "testshop.myshopify.com",
82
+ token: "any-token",
83
+ api_version: any_api_version,
84
+ access_scopes: %w(read_products write_orders)
85
+ )
86
+
87
+ assert(session.valid?)
36
88
  end
37
89
 
38
90
  test "not raise error without params" do
@@ -65,26 +117,60 @@ class SessionTest < Test::Unit::TestCase
65
117
  end
66
118
  end
67
119
 
120
+ test "provides default nil access_scopes attribute" do
121
+ session = ShopifyAPI::Session.new(
122
+ domain: "testshop.myshopify.com",
123
+ token: "any-token",
124
+ api_version: any_api_version
125
+ )
126
+ assert_nil session.access_scopes
127
+ end
128
+
129
+ test "provides specified nil access_scopes attribute" do
130
+ session = ShopifyAPI::Session.new(
131
+ domain: "testshop.myshopify.com",
132
+ token: "any-token",
133
+ access_scopes: "read_products",
134
+ api_version: any_api_version
135
+ )
136
+ assert_equal "read_products", session.access_scopes.to_s
137
+ end
138
+
139
+ test "session instantiation raises error if bad access scopes are provided" do
140
+ assert_raises NoMethodError do
141
+ ShopifyAPI::Session.new(
142
+ domain: "testshop.myshopify.com",
143
+ token: "any-token",
144
+ access_scopes: { bad_input: "bad_input" },
145
+ api_version: any_api_version
146
+ )
147
+ end
148
+ end
149
+
68
150
  test "raise error if params passed but signature omitted" do
69
151
  assert_raises(ShopifyAPI::ValidationException) do
70
152
  session = ShopifyAPI::Session.new(domain: "testshop.myshopify.com", token: nil, api_version: any_api_version)
71
- session.request_token({'code' => 'any-code'})
153
+ session.request_token({ 'code' => 'any-code' })
72
154
  end
73
155
  end
74
156
 
75
157
  test "setup api_key and secret for all sessions" do
76
- ShopifyAPI::Session.setup(:api_key => "My test key", :secret => "My test secret")
77
- assert_equal "My test key", ShopifyAPI::Session.api_key
78
- assert_equal "My test secret", ShopifyAPI::Session.secret
158
+ ShopifyAPI::Session.setup(api_key: "My test key", secret: "My test secret")
159
+ assert_equal("My test key", ShopifyAPI::Session.api_key)
160
+ assert_equal("My test secret", ShopifyAPI::Session.secret)
79
161
  end
80
162
 
81
- test "#temp reset ShopifyAPI::Base.site to original value" do
163
+ test "#temp reset ShopifyAPI::Base values to original value" do
82
164
  session1 = ShopifyAPI::Session.new(domain: 'fakeshop.myshopify.com', token: 'token1', api_version: '2019-01')
165
+ ShopifyAPI::Base.user = 'foo'
166
+ ShopifyAPI::Base.password = 'bar'
83
167
  ShopifyAPI::Base.activate_session(session1)
84
168
 
85
169
  ShopifyAPI::Session.temp(domain: "testshop.myshopify.com", token: "any-token", api_version: :unstable) do
86
170
  @assigned_site = ShopifyAPI::Base.site
87
171
  @assigned_version = ShopifyAPI::Base.api_version
172
+ @assigned_user = ShopifyAPI::Base.user
173
+ @assigned_password = ShopifyAPI::Base.password
88
174
  end
89
175
 
90
176
  assert_equal('https://testshop.myshopify.com', @assigned_site.to_s)
@@ -92,6 +178,31 @@ class SessionTest < Test::Unit::TestCase
92
178
 
93
179
  assert_equal(ShopifyAPI::ApiVersion.new(handle: :unstable), @assigned_version)
94
180
  assert_equal(ShopifyAPI::ApiVersion.new(handle: '2019-01'), ShopifyAPI::Base.api_version)
181
+
182
+ assert_nil(@assigned_user)
183
+ assert_equal('foo', ShopifyAPI::Base.user)
184
+
185
+ assert_nil(@assigned_password)
186
+ assert_equal('bar', ShopifyAPI::Base.password)
187
+ end
188
+
189
+ test "#temp does not use basic auth values from Base.site" do
190
+ ShopifyAPI::Base.site = 'https://user:pass@fakeshop.myshopify.com'
191
+
192
+ ShopifyAPI::Session.temp(domain: "testshop.myshopify.com", token: "any-token", api_version: :unstable) do
193
+ @assigned_site = ShopifyAPI::Base.site
194
+ @assigned_user = ShopifyAPI::Base.user
195
+ @assigned_password = ShopifyAPI::Base.password
196
+ end
197
+
198
+ assert_equal('https://testshop.myshopify.com', @assigned_site.to_s)
199
+ assert_equal('https://fakeshop.myshopify.com', ShopifyAPI::Base.site.to_s)
200
+
201
+ assert_nil(@assigned_user)
202
+ assert_equal('user', ShopifyAPI::Base.user)
203
+
204
+ assert_nil(@assigned_password)
205
+ assert_equal('pass', ShopifyAPI::Base.password)
95
206
  end
96
207
 
97
208
  test "#with_session activates the session for the duration of the block" do
@@ -126,7 +237,7 @@ class SessionTest < Test::Unit::TestCase
126
237
  api_version: :unstable
127
238
  )
128
239
 
129
- assert_raises StandardError do
240
+ assert_raises(StandardError) do
130
241
  ShopifyAPI::Session.with_session(other_session) { raise StandardError, "" }
131
242
  end
132
243
 
@@ -172,7 +283,11 @@ class SessionTest < Test::Unit::TestCase
172
283
  )
173
284
  scope = ["write_products"]
174
285
  permission_url = session.create_permission_url(scope, "http://my_redirect_uri.com")
175
- assert_equal "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&scope=write_products&redirect_uri=http://my_redirect_uri.com", permission_url
286
+ assert_equal(
287
+ "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&" \
288
+ "scope=write_products&redirect_uri=http://my_redirect_uri.com",
289
+ permission_url
290
+ )
176
291
  end
177
292
 
178
293
  test "create_permission_url returns correct url with dual scope" do
@@ -182,9 +297,13 @@ class SessionTest < Test::Unit::TestCase
182
297
  token: 'any-token',
183
298
  api_version: any_api_version
184
299
  )
185
- scope = ["write_products","write_customers"]
300
+ scope = ["write_products", "write_customers"]
186
301
  permission_url = session.create_permission_url(scope, "http://my_redirect_uri.com")
187
- assert_equal "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&scope=write_products,write_customers&redirect_uri=http://my_redirect_uri.com", permission_url
302
+ assert_equal(
303
+ "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&" \
304
+ "scope=write_products,write_customers&redirect_uri=http://my_redirect_uri.com",
305
+ permission_url
306
+ )
188
307
  end
189
308
 
190
309
  test "create_permission_url returns correct url with no scope" do
@@ -196,7 +315,11 @@ class SessionTest < Test::Unit::TestCase
196
315
  )
197
316
  scope = []
198
317
  permission_url = session.create_permission_url(scope, "http://my_redirect_uri.com")
199
- assert_equal "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&scope=&redirect_uri=http://my_redirect_uri.com", permission_url
318
+ assert_equal(
319
+ "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&" \
320
+ "scope=&redirect_uri=http://my_redirect_uri.com",
321
+ permission_url
322
+ )
200
323
  end
201
324
 
202
325
  test "create_permission_url returns correct url with state" do
@@ -208,11 +331,31 @@ class SessionTest < Test::Unit::TestCase
208
331
  )
209
332
  scope = []
210
333
  permission_url = session.create_permission_url(scope, "http://my_redirect_uri.com", state: "My nonce")
211
- assert_equal "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&scope=&redirect_uri=http://my_redirect_uri.com&state=My%20nonce", permission_url
334
+ assert_equal(
335
+ "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&" \
336
+ "scope=&redirect_uri=http://my_redirect_uri.com&state=My%20nonce",
337
+ permission_url
338
+ )
339
+ end
340
+
341
+ test "create_permission_url returns correct url with grant_options[]" do
342
+ ShopifyAPI::Session.setup(api_key: "My_test_key", secret: "My test secret")
343
+ session = ShopifyAPI::Session.new(
344
+ domain: 'http://localhost.myshopify.com',
345
+ token: 'any-token',
346
+ api_version: any_api_version
347
+ )
348
+ scope = []
349
+ permission_url = session.create_permission_url(scope, "http://my_redirect_uri.com", grant_options: "per-user")
350
+ assert_equal(
351
+ "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&" \
352
+ "scope=&redirect_uri=http://my_redirect_uri.com&grant_options[]=per-user",
353
+ permission_url
354
+ )
212
355
  end
213
356
 
214
357
  test "raise exception if code invalid in request token" do
215
- ShopifyAPI::Session.setup(:api_key => "My test key", :secret => "My test secret")
358
+ ShopifyAPI::Session.setup(api_key: "My test key", secret: "My test secret")
216
359
  session = ShopifyAPI::Session.new(
217
360
  domain: 'http://localhost.myshopify.com',
218
361
  token: nil,
@@ -228,7 +371,7 @@ class SessionTest < Test::Unit::TestCase
228
371
  assert_raises(ShopifyAPI::ValidationException) do
229
372
  session.request_token(code: "bad-code")
230
373
  end
231
- assert_equal false, session.valid?
374
+ assert_equal(false, session.valid?)
232
375
  end
233
376
 
234
377
  test "return site for session" do
@@ -237,87 +380,93 @@ class SessionTest < Test::Unit::TestCase
237
380
  token: "any-token",
238
381
  api_version: any_api_version
239
382
  )
240
- assert_equal "https://testshop.myshopify.com", session.site
383
+ assert_equal("https://testshop.myshopify.com", session.site)
241
384
  end
242
385
 
243
386
  test "return_token_if_signature_is_valid" do
244
387
  api_version = any_api_version
245
- fake nil,
388
+ fake(
389
+ nil,
246
390
  url: "https://testshop.myshopify.com/admin/oauth/access_token",
247
391
  method: :post,
248
392
  body: '{"access_token":"any-token"}'
393
+ )
249
394
  session = ShopifyAPI::Session.new(domain: "testshop.myshopify.com", token: nil, api_version: api_version)
250
395
 
251
396
  params = { code: 'any-code', timestamp: Time.now }
252
397
  token = session.request_token(params.merge(hmac: generate_signature(params)))
253
398
 
254
- assert_equal "any-token", token
255
- assert_equal "any-token", session.token
399
+ assert_equal("any-token", token)
400
+ assert_equal("any-token", session.token)
256
401
  end
257
402
 
258
403
  test "extra parameters are stored in session" do
259
404
  api_version = ShopifyAPI::ApiVersion.new(handle: :unstable)
260
- fake nil,
405
+ fake(
406
+ nil,
261
407
  url: "https://testshop.myshopify.com/admin/oauth/access_token",
262
408
  method: :post,
263
409
  body: '{"access_token":"any-token","foo":"example"}'
410
+ )
264
411
  session = ShopifyAPI::Session.new(domain: "testshop.myshopify.com", token: nil, api_version: api_version)
265
412
 
266
413
  params = { code: 'any-code', timestamp: Time.now }
267
- assert session.request_token(params.merge(hmac: generate_signature(params)))
414
+ assert(session.request_token(params.merge(hmac: generate_signature(params))))
268
415
 
269
- assert_equal ({ "foo" => "example" }), session.extra
416
+ assert_equal({ "foo" => "example" }, session.extra)
270
417
  end
271
418
 
272
419
  test "expires_in is automatically converted in expires_at" do
273
420
  api_version = any_api_version
274
- fake nil,
421
+ fake(
422
+ nil,
275
423
  url: "https://testshop.myshopify.com/admin/oauth/access_token",
276
424
  method: :post,
277
425
  body: '{"access_token":"any-token","expires_in":86393}'
426
+ )
278
427
  session = ShopifyAPI::Session.new(domain: "testshop.myshopify.com", token: nil, api_version: api_version)
279
428
 
280
429
  Timecop.freeze do
281
430
  params = { code: 'any-code', timestamp: Time.now }
282
- assert session.request_token(params.merge(hmac: generate_signature(params)))
431
+ assert(session.request_token(params.merge(hmac: generate_signature(params))))
283
432
 
284
433
  expires_at = Time.now.utc + 86393
285
- assert_equal ({ "expires_at" => expires_at.to_i }), session.extra
286
- assert session.expires_at.is_a?(Time)
287
- assert_equal expires_at.to_i, session.expires_at.to_i
288
- assert_equal 86393, session.expires_in
289
- assert_equal false, session.expired?
434
+ assert_equal({ "expires_at" => expires_at.to_i }, session.extra)
435
+ assert(session.expires_at.is_a?(Time))
436
+ assert_equal(expires_at.to_i, session.expires_at.to_i)
437
+ assert_equal(86393, session.expires_in)
438
+ assert_equal(false, session.expired?)
290
439
 
291
440
  Timecop.travel(session.expires_at) do
292
- assert_equal true, session.expired?
441
+ assert_equal(true, session.expired?)
293
442
  end
294
443
  end
295
444
  end
296
445
 
297
446
  test "raise error if signature does not match expected" do
298
- params = {:code => "any-code", :timestamp => Time.now}
447
+ params = { code: "any-code", timestamp: Time.now }
299
448
  signature = generate_signature(params)
300
449
  params[:foo] = 'world'
301
450
  assert_raises(ShopifyAPI::ValidationException) do
302
451
  session = ShopifyAPI::Session.new(domain: "testshop.myshopify.com", token: nil, api_version: any_api_version)
303
- session.request_token(params.merge(:hmac => signature))
452
+ session.request_token(params.merge(hmac: signature))
304
453
  end
305
454
  end
306
455
 
307
456
  test "raise error if timestamp is too old" do
308
- params = {:code => "any-code", :timestamp => Time.now - 2.days}
457
+ params = { code: "any-code", timestamp: Time.now - 2 * SECONDS_IN_A_DAY }
309
458
  signature = generate_signature(params)
310
459
  params[:foo] = 'world'
311
460
  assert_raises(ShopifyAPI::ValidationException) do
312
461
  session = ShopifyAPI::Session.new(domain: "testshop.myshopify.com", token: nil, api_version: any_api_version)
313
- session.request_token(params.merge(:hmac => signature))
462
+ session.request_token(params.merge(hmac: signature))
314
463
  end
315
464
  end
316
465
 
317
466
  test "return true when the signature is valid and the keys of params are strings" do
318
467
  params = { 'code' => 'any-code', 'timestamp' => Time.now }
319
468
  params[:hmac] = generate_signature(params)
320
- assert_equal true, ShopifyAPI::Session.validate_signature(params)
469
+ assert_equal(true, ShopifyAPI::Session.validate_signature(params))
321
470
  end
322
471
 
323
472
  test "return true when validating signature of params with ampersand and equal sign characters" do
@@ -325,7 +474,7 @@ class SessionTest < Test::Unit::TestCase
325
474
  params = { 'a' => '1&b=2', 'c=3&d' => '4' }
326
475
  to_sign = 'a=1%26b=2&c%3D3%26d=4'
327
476
  params[:hmac] = generate_signature(to_sign)
328
- assert_equal true, ShopifyAPI::Session.validate_signature(params)
477
+ assert_equal(true, ShopifyAPI::Session.validate_signature(params))
329
478
  end
330
479
 
331
480
  test "return true when validating signature of params with percent sign characters" do
@@ -333,7 +482,7 @@ class SessionTest < Test::Unit::TestCase
333
482
  params = { 'a%3D1%26b' => '2%26c%3D3' }
334
483
  to_sign = 'a%253D1%2526b=2%2526c%253D3'
335
484
  params[:hmac] = generate_signature(to_sign)
336
- assert_equal true, ShopifyAPI::Session.validate_signature(params)
485
+ assert_equal(true, ShopifyAPI::Session.validate_signature(params))
337
486
  end
338
487
 
339
488
  test "url is aliased to domain to minimize the upgrade changes" do
@@ -346,6 +495,127 @@ class SessionTest < Test::Unit::TestCase
346
495
  assert_equal('testshop.myshopify.com', session.url)
347
496
  end
348
497
 
498
+ test "#hash returns the same value for equal Sessions" do
499
+ session = ShopifyAPI::Session.new(
500
+ domain: "http://testshop.myshopify.com",
501
+ token: "any-token",
502
+ api_version: '2019-01',
503
+ extra: { foo: "bar" }
504
+ )
505
+ other_session = ShopifyAPI::Session.new(
506
+ domain: "http://testshop.myshopify.com",
507
+ token: "any-token",
508
+ api_version: '2019-01',
509
+ extra: { foo: "bar" }
510
+ )
511
+ assert_equal(session.hash, other_session.hash)
512
+ end
513
+
514
+ test "equality verifies domain" do
515
+ session = ShopifyAPI::Session.new(
516
+ domain: "http://testshop.myshopify.com",
517
+ token: "any-token",
518
+ api_version: '2019-01',
519
+ extra: { foo: "bar" }
520
+ )
521
+ other_session = ShopifyAPI::Session.new(
522
+ domain: "http://testshop.myshopify.com",
523
+ token: "any-token",
524
+ api_version: '2019-01',
525
+ extra: { foo: "bar" }
526
+ )
527
+ different_session = ShopifyAPI::Session.new(
528
+ domain: "http://another_testshop.myshopify.com",
529
+ token: "any-token",
530
+ api_version: '2019-01',
531
+ extra: { foo: "bar" }
532
+ )
533
+ assert_equal(session, other_session)
534
+ refute_equal(session, different_session)
535
+ end
536
+
537
+ test "equality verifies token" do
538
+ session = ShopifyAPI::Session.new(
539
+ domain: "http://testshop.myshopify.com",
540
+ token: "any-token",
541
+ api_version: '2019-01',
542
+ extra: { foo: "bar" }
543
+ )
544
+ different_session = ShopifyAPI::Session.new(
545
+ domain: "http://testshop.myshopify.com",
546
+ token: "very-different-token",
547
+ api_version: '2019-01',
548
+ extra: { foo: "bar" }
549
+ )
550
+ refute_equal(session, different_session)
551
+ end
552
+
553
+ test "equality verifies api_version" do
554
+ session = ShopifyAPI::Session.new(
555
+ domain: "http://testshop.myshopify.com",
556
+ token: "any-token",
557
+ api_version: '2019-01',
558
+ extra: { foo: "bar" }
559
+ )
560
+ different_session = ShopifyAPI::Session.new(
561
+ domain: "http://testshop.myshopify.com",
562
+ token: "any-token",
563
+ api_version: :unstable,
564
+ extra: { foo: "bar" }
565
+ )
566
+ refute_equal(session, different_session)
567
+ end
568
+
569
+ test "equality verifies extra" do
570
+ session = ShopifyAPI::Session.new(
571
+ domain: "http://testshop.myshopify.com",
572
+ token: "any-token",
573
+ api_version: '2019-01',
574
+ extra: { foo: "bar" }
575
+ )
576
+ different_session = ShopifyAPI::Session.new(
577
+ domain: "http://testshop.myshopify.com",
578
+ token: "any-token",
579
+ api_version: '2019-01',
580
+ extra: { bar: "other-bar" }
581
+ )
582
+ refute_equal(session, different_session)
583
+ end
584
+
585
+ test "equality verifies other is a Session" do
586
+ session = ShopifyAPI::Session.new(
587
+ domain: "http://testshop.myshopify.com",
588
+ token: "any-token",
589
+ api_version: '2019-01',
590
+ extra: { foo: "bar" }
591
+ )
592
+ different_session = nil
593
+ refute_equal(session, different_session)
594
+ end
595
+
596
+ test "#eql? and #hash are implemented" do
597
+ session = ShopifyAPI::Session.new(
598
+ domain: "http://testshop.myshopify.com",
599
+ token: "any-token",
600
+ api_version: '2019-01',
601
+ extra: { foo: "bar" }
602
+ )
603
+ other_session = ShopifyAPI::Session.new(
604
+ domain: "http://testshop.myshopify.com",
605
+ token: "any-token",
606
+ api_version: '2019-01',
607
+ extra: { foo: "bar" }
608
+ )
609
+ different_session = ShopifyAPI::Session.new(
610
+ domain: "http://another_testshop.myshopify.com",
611
+ token: "any-token",
612
+ api_version: '2019-01',
613
+ extra: { foo: "bar" }
614
+ )
615
+
616
+ assert_equal([session, different_session], [session, other_session, different_session].uniq)
617
+ end
618
+
349
619
  private
350
620
 
351
621
  def make_sorted_params(params)
@@ -356,7 +626,7 @@ class SessionTest < Test::Unit::TestCase
356
626
 
357
627
  def generate_signature(params)
358
628
  params = make_sorted_params(params) if params.is_a?(Hash)
359
- OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, ShopifyAPI::Session.secret, params)
629
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('SHA256'), ShopifyAPI::Session.secret, params)
360
630
  end
361
631
 
362
632
  def any_api_version