diff --git a/CHANGELOG b/CHANGELOG index a1ffe8791..7ab565134 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,36 @@ +== Version 4.11.0 + +* Added `ShopifyAPI::InventoryItem` +* Added `ShopifyAPI::InventoryLevel` +* Added `#inventory_levels` method to `ShopifyAPI::Location` + +== Version 4.10.0 + +* Added `ShopifyAPI::AccessScope` + +== Version 4.9.1 + +* Fix a bug with custom properties for orders + +== Version 4.9.0 + +* Added `ShopifyAPI::PriceRule` +* Added `ShopifyAPI::DiscountCode` + +== Version 4.8.0 + +* Added `add_engagements` to `ShopifyAPI::MarketingEvent` + +== Version 4.7.1 + +* Added support for URL parameter (e.g. limit & page) to ShopifyAPI::Metafields +* Added support for URL parameter (e.g. limit & page) to metafield operator in ShopifyAPI::Shop + +== Version 4.7.0 + +* Removed the mandatory `application_id` parameter from `ShopifyAPI::ProductListing` and `ShopifyAPI::CollectionListing` +* Fixed a bug related to the non-standard primary key for `ShopifyAPI::ProductListing` and `ShopifyAPI::CollectionListing` + == Version 4.6.0 * Added `ShopifyAPI::Report` diff --git a/README.md b/README.md index 6e0b0f65c..0dc5e571a 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ All API usage happens through Shopify applications, created by either shop owner * Shop owners can create applications for themselves through their own admin: https://docs.shopify.com/api/authentication/creating-a-private-app * Shopify Partners create applications through their admin: http://app.shopify.com/services/partners -For more information and detailed documentation about the API visit http://api.shopify.com +For more information and detailed documentation about the API visit https://developers.shopify.com/ #### Ruby version @@ -39,15 +39,6 @@ Or install via [gem](http://rubygems.org/) gem install shopify_api ``` -#### Rails 5 - -shopify_api is compatible with Rails 5 but since the latest ActiveResource release (4.1) is locked on Rails 4.x, you'll need to use the unreleased master version: - -```ruby -gem 'shopify_api' -gem 'activeresource', github: 'rails/activeresource' -``` - ### Getting Started ShopifyAPI uses ActiveResource to communicate with the REST web service. ActiveResource has to be configured with a fully authorized URL of a particular store first. To obtain that URL you can follow these steps: @@ -59,7 +50,7 @@ ShopifyAPI uses ActiveResource to communicate with the REST web service. ActiveR 2. For a private App you just need to set the base site url as follows: ```ruby - shop_url = "https://#{API_KEY}:#{PASSWORD}@SHOP_NAME.myshopify.com/admin" + shop_url = "https://#{API_KEY}:#{PASSWORD}@#{SHOP_NAME}.myshopify.com/admin" ShopifyAPI::Base.site = shop_url ``` @@ -246,7 +237,7 @@ rake install ## Additional Resources -API Docs: http://docs.shopify.com/api +API Reference: https://help.shopify.com/api/reference Ask questions on the forums: http://ecommerce.shopify.com/c/shopify-apis-and-technology diff --git a/lib/active_resource/connection_ext.rb b/lib/active_resource/connection_ext.rb index 22a8b8ba3..d4c9e3649 100644 --- a/lib/active_resource/connection_ext.rb +++ b/lib/active_resource/connection_ext.rb @@ -6,5 +6,6 @@ class Connection prepend ShopifyAPI::Connection::ResponseCapture prepend ShopifyAPI::Connection::RequestNotification + prepend ShopifyAPI::Connection::RedoIfTemporaryError end end diff --git a/lib/shopify_api.rb b/lib/shopify_api.rb index 801c5b1ac..d4139acae 100644 --- a/lib/shopify_api.rb +++ b/lib/shopify_api.rb @@ -21,6 +21,7 @@ module ShopifyAPI require 'shopify_api/countable' require 'shopify_api/resources' require 'shopify_api/session' +require 'shopify_api/message_enricher' require 'shopify_api/connection' if ShopifyAPI::Base.respond_to?(:connection_class) diff --git a/lib/shopify_api/connection.rb b/lib/shopify_api/connection.rb index 764ae886d..752ef91e3 100644 --- a/lib/shopify_api/connection.rb +++ b/lib/shopify_api/connection.rb @@ -4,7 +4,7 @@ class Connection < ActiveResource::Connection module ResponseCapture def handle_response(response) - @response = super + @response = super(ShopifyAPI::MessageEnricher.new(response)) end end @@ -29,5 +29,28 @@ def notify_about_request(response, arguments) end include RequestNotification + + module RedoIfTemporaryError + def request(*args) + super + rescue ActiveResource::ClientError, ActiveResource::ServerError => e + if should_retry? && e.response.class.in?([Net::HTTPTooManyRequests, Net::HTTPInternalServerError]) + wait + request *args + else + raise + end + end + + def wait + sleep 0.5 + end + + def should_retry? + [true, nil].include? Thread.current[:retry_temporary_errors] + end + end + + include RedoIfTemporaryError end end diff --git a/lib/shopify_api/limits.rb b/lib/shopify_api/limits.rb index 7db718cd8..0649828c0 100644 --- a/lib/shopify_api/limits.rb +++ b/lib/shopify_api/limits.rb @@ -39,8 +39,7 @@ def credit_maxed? # @return {Integer} # def credit_limit(scope=:shop) - @api_credit_limit ||= {} - @api_credit_limit[scope] ||= api_credit_limit_param(scope).pop.to_i - 1 + api_credit_limit_param(scope).pop.to_i - 1 end alias_method :call_limit, :credit_limit diff --git a/lib/shopify_api/message_enricher.rb b/lib/shopify_api/message_enricher.rb new file mode 100644 index 000000000..165926fd4 --- /dev/null +++ b/lib/shopify_api/message_enricher.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class ShopifyAPI::MessageEnricher < SimpleDelegator + def message + return super unless (400...500).include?(code.to_i) + + @_cached_message ||= begin + detailed_error = begin + parsed_body = JSON.parse(body) + + if parsed_body['error'] + parsed_body['error'].to_s + elsif parsed_body['errors'] + Array(parsed_body['errors']).join('; ') + end + rescue JSON::ParserError + nil + end + + detailed_error.present? ? "#{super} (#{detailed_error})" : super + end + end +end diff --git a/lib/shopify_api/metafields.rb b/lib/shopify_api/metafields.rb index 27e6db140..b4535cf4e 100644 --- a/lib/shopify_api/metafields.rb +++ b/lib/shopify_api/metafields.rb @@ -1,7 +1,9 @@ module ShopifyAPI module Metafields - def metafields - Metafield.find(:all, :params => {:resource => self.class.collection_name, :resource_id => id}) + def metafields(**options) + options.merge! resource: self.class.collection_name, resource_id: id + + Metafield.find :all, params: options end def add_metafield(metafield) diff --git a/lib/shopify_api/resources/access_scope.rb b/lib/shopify_api/resources/access_scope.rb new file mode 100644 index 000000000..287bddfbc --- /dev/null +++ b/lib/shopify_api/resources/access_scope.rb @@ -0,0 +1,5 @@ +module ShopifyAPI + class AccessScope < Base + self.prefix = '/admin/oauth/' + end +end diff --git a/lib/shopify_api/resources/asset.rb b/lib/shopify_api/resources/asset.rb index 96069bcf1..fe5f2f880 100644 --- a/lib/shopify_api/resources/asset.rb +++ b/lib/shopify_api/resources/asset.rb @@ -42,7 +42,7 @@ def self.element_path(id, prefix_options = {}, query_options = nil) #:nodoc: prefix_options, query_options = split_options(prefix_options) if query_options.nil? "#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}" end - + # find an asset by key: # ShopifyAPI::Asset.find('layout/theme.liquid', :params => {:theme_id => 99}) def self.find(*args) @@ -57,7 +57,7 @@ def self.find(*args) resource end end - + # For text assets, Shopify returns the data in the 'value' attribute. # For binary assets, the data is base-64-encoded and returned in the # 'attachment' attribute. This accessor returns the data in both cases. @@ -65,28 +65,28 @@ def value attributes['value'] || (attributes['attachment'] ? Base64.decode64(attributes['attachment']) : nil) end - + def attach(data) self.attachment = Base64.encode64(data) end - + def destroy connection.delete(element_path(prefix_options.merge(:asset => {:key => key})), self.class.headers) end - + def new? false end - + def method_missing(method_symbol, *arguments) #:nodoc: if %w{value= attachment= src= source_key=}.include?(method_symbol) wipe_value_attributes end super end - + private - + def wipe_value_attributes %w{value attachment src source_key}.each do |attr| attributes.delete(attr) diff --git a/lib/shopify_api/resources/billing_address.rb b/lib/shopify_api/resources/billing_address.rb index 5c747f7e4..818b93b49 100644 --- a/lib/shopify_api/resources/billing_address.rb +++ b/lib/shopify_api/resources/billing_address.rb @@ -1,4 +1,4 @@ module ShopifyAPI class BillingAddress < Base - end + end end diff --git a/lib/shopify_api/resources/collection_listing.rb b/lib/shopify_api/resources/collection_listing.rb index 1f9f40027..e25c3669f 100644 --- a/lib/shopify_api/resources/collection_listing.rb +++ b/lib/shopify_api/resources/collection_listing.rb @@ -1,9 +1,9 @@ module ShopifyAPI class CollectionListing < Base - init_prefix :application + self.primary_key = :collection_id - def product_ids(options = {}) - get("#{collection_id}/product_ids", options[:params]) + def product_ids + get(:product_ids) end end end diff --git a/lib/shopify_api/resources/custom_collection.rb b/lib/shopify_api/resources/custom_collection.rb index 99866cf99..de8e2b335 100644 --- a/lib/shopify_api/resources/custom_collection.rb +++ b/lib/shopify_api/resources/custom_collection.rb @@ -6,14 +6,14 @@ class CustomCollection < Base def products Product.find(:all, :params => {:collection_id => self.id}) end - + def add_product(product) Collect.create(:collection_id => self.id, :product_id => product.id) end - + def remove_product(product) collect = Collect.find(:first, :params => {:collection_id => self.id, :product_id => product.id}) collect.destroy if collect end - end + end end diff --git a/lib/shopify_api/resources/customer_invite_message.rb b/lib/shopify_api/resources/customer_invite.rb similarity index 100% rename from lib/shopify_api/resources/customer_invite_message.rb rename to lib/shopify_api/resources/customer_invite.rb diff --git a/lib/shopify_api/resources/discount.rb b/lib/shopify_api/resources/discount.rb deleted file mode 100644 index b40a62d59..000000000 --- a/lib/shopify_api/resources/discount.rb +++ /dev/null @@ -1,11 +0,0 @@ -module ShopifyAPI - class Discount < Base - def disable - load_attributes_from_response(post(:disable)) - end - - def enable - load_attributes_from_response(post(:enable)) - end - end -end diff --git a/lib/shopify_api/resources/discount_code.rb b/lib/shopify_api/resources/discount_code.rb new file mode 100644 index 000000000..65823427c --- /dev/null +++ b/lib/shopify_api/resources/discount_code.rb @@ -0,0 +1,9 @@ +module ShopifyAPI + class DiscountCode < Base + init_prefix :price_rule + + def price_rule_id + @prefix_options[:price_rule_id] + end + end +end diff --git a/lib/shopify_api/resources/image.rb b/lib/shopify_api/resources/image.rb index dde314c09..884d28f13 100644 --- a/lib/shopify_api/resources/image.rb +++ b/lib/shopify_api/resources/image.rb @@ -1,13 +1,13 @@ module ShopifyAPI class Image < Base init_prefix :product - + # generate a method for each possible image variant [:pico, :icon, :thumb, :small, :compact, :medium, :large, :grande, :original].each do |m| reg_exp_match = "/\\1_#{m}.\\2" define_method(m) { src.gsub(/\/(.*)\.(\w{2,4})/, reg_exp_match) } end - + def attach_image(data, filename = nil) attributes['attachment'] = Base64.encode64(data) attributes['filename'] = filename unless filename.nil? diff --git a/lib/shopify_api/resources/inventory_item.rb b/lib/shopify_api/resources/inventory_item.rb new file mode 100644 index 000000000..22fb32bf7 --- /dev/null +++ b/lib/shopify_api/resources/inventory_item.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module ShopifyAPI + class InventoryItem < Base + end +end diff --git a/lib/shopify_api/resources/inventory_level.rb b/lib/shopify_api/resources/inventory_level.rb new file mode 100644 index 000000000..809889735 --- /dev/null +++ b/lib/shopify_api/resources/inventory_level.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module ShopifyAPI + class InventoryLevel < Base + + # The default path structure in ActiveResource for delete would result in: + # /admin/inventory_levels/#{ inventory_level.id }.json?#{ params }, but since + # InventroyLevels are a second class resource made up of a Where and a What + # (Location and InventoryItem), it does not have a resource ID. Here we + # redefine element_path to remove the id so HTTP DELETE requests go to + # /admin/inventory_levels.json?#{ params } instead. + # + def self.element_path(prefix_options = {}, query_options = nil) + prefix_options, query_options = split_options(prefix_options) if query_options.nil? + "#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}" + end + + def destroy + load_attributes_from_response( + self.class.delete('/', location_id: location_id, inventory_item_id: inventory_item_id) + ) + end + + def connect(relocate_if_necessary: nil) + body = { location_id: location_id, inventory_item_id: inventory_item_id } + body[:relocate_if_necessary] = relocate_if_necessary unless relocate_if_necessary.nil? + load_attributes_from_response( + self.class.post(:connect, {}, body.to_json) + ) + end + + def set(new_available, disconnect_if_necessary: nil) + body = { + location_id: location_id, + inventory_item_id: inventory_item_id, + available: new_available + } + body[:disconnect_if_necessary] = disconnect_if_necessary unless disconnect_if_necessary.nil? + load_attributes_from_response( + self.class.post(:set, {}, body.to_json) + ) + end + + def adjust(available_adjustment) + body = { + location_id: location_id, + inventory_item_id: inventory_item_id, + available_adjustment: available_adjustment + } + load_attributes_from_response( + self.class.post(:adjust, {}, body.to_json) + ) + end + end +end diff --git a/lib/shopify_api/resources/line_item.rb b/lib/shopify_api/resources/line_item.rb index 248b2cf44..3d29b13e5 100644 --- a/lib/shopify_api/resources/line_item.rb +++ b/lib/shopify_api/resources/line_item.rb @@ -1,6 +1,14 @@ module ShopifyAPI - class LineItem < Base + class LineItem < Base class Property < Base + def initialize(*args) + attributes = args[0] || {} + persisted = args[1] || false + super + rescue NameError + attributes = attributes.to_hash + self + end end end end diff --git a/lib/shopify_api/resources/location.rb b/lib/shopify_api/resources/location.rb index 8b7be8890..ee73036b0 100644 --- a/lib/shopify_api/resources/location.rb +++ b/lib/shopify_api/resources/location.rb @@ -1,4 +1,8 @@ module ShopifyAPI class Location < Base + + def inventory_levels + ShopifyAPI::InventoryLevel.find(:all, from: "/admin/locations/#{id}/inventory_levels.json") + end end end diff --git a/lib/shopify_api/resources/marketing_event.rb b/lib/shopify_api/resources/marketing_event.rb index 6f5f764a8..62ab8f8fc 100644 --- a/lib/shopify_api/resources/marketing_event.rb +++ b/lib/shopify_api/resources/marketing_event.rb @@ -1,4 +1,8 @@ module ShopifyAPI class MarketingEvent < Base + def add_engagements(engagements) + engagements = { engagements: Array.wrap(engagements) } + post(:engagements, {}, engagements.to_json) + end end end diff --git a/lib/shopify_api/resources/order.rb b/lib/shopify_api/resources/order.rb index 984b731b7..5ad8f3d70 100644 --- a/lib/shopify_api/resources/order.rb +++ b/lib/shopify_api/resources/order.rb @@ -3,8 +3,13 @@ class Order < Base include Events include Metafields - def close; load_attributes_from_response(post(:close, {}, only_id)); end - def open; load_attributes_from_response(post(:open, {}, only_id)); end + def close + load_attributes_from_response(post(:close, {}, only_id)) + end + + def open + load_attributes_from_response(post(:open, {}, only_id)) + end def cancel(options = {}) load_attributes_from_response(post(:cancel, {}, options.to_json)) diff --git a/lib/shopify_api/resources/price_rule.rb b/lib/shopify_api/resources/price_rule.rb new file mode 100644 index 000000000..8c71dabe6 --- /dev/null +++ b/lib/shopify_api/resources/price_rule.rb @@ -0,0 +1,8 @@ +module ShopifyAPI + class PriceRule < Base + + def discount_codes + DiscountCode.find(:all, params: { price_rule_id: id }) + end + end +end diff --git a/lib/shopify_api/resources/product.rb b/lib/shopify_api/resources/product.rb index 3ed8d4618..4dfe9117a 100644 --- a/lib/shopify_api/resources/product.rb +++ b/lib/shopify_api/resources/product.rb @@ -13,19 +13,19 @@ def price_range format % prices.min end end - + def collections CustomCollection.find(:all, :params => {:product_id => self.id}) end - + def smart_collections SmartCollection.find(:all, :params => {:product_id => self.id}) end - + def add_to_collection(collection) collection.add_product(self) end - + def remove_from_collection(collection) collection.remove_product(self) end diff --git a/lib/shopify_api/resources/product_listing.rb b/lib/shopify_api/resources/product_listing.rb index 310632a86..3541d7cf1 100644 --- a/lib/shopify_api/resources/product_listing.rb +++ b/lib/shopify_api/resources/product_listing.rb @@ -1,9 +1,9 @@ module ShopifyAPI class ProductListing < Base - init_prefix :application + self.primary_key = :product_id - def self.product_ids(options = {}) - get(:product_ids, options[:params]) + def self.product_ids + get(:product_ids) end end end diff --git a/lib/shopify_api/resources/shipping_line.rb b/lib/shopify_api/resources/shipping_line.rb index 48ac8dbb6..42c06fb59 100644 --- a/lib/shopify_api/resources/shipping_line.rb +++ b/lib/shopify_api/resources/shipping_line.rb @@ -1,4 +1,4 @@ module ShopifyAPI class ShippingLine < Base - end + end end diff --git a/lib/shopify_api/resources/shop.rb b/lib/shopify_api/resources/shop.rb index 9af58106f..c5c7047da 100644 --- a/lib/shopify_api/resources/shop.rb +++ b/lib/shopify_api/resources/shop.rb @@ -1,23 +1,23 @@ module ShopifyAPI - # Shop object. Use Shop.current to receive + # Shop object. Use Shop.current to receive # the shop. class Shop < Base def self.current(options={}) find(:one, options.merge({from: "/admin/shop.#{format.extension}"})) end - def metafields - Metafield.find(:all) + def metafields(**options) + Metafield.find :all, params: options end - + def add_metafield(metafield) - raise ArgumentError, "You can only add metafields to resource that has been saved" if new? + raise ArgumentError, "You can only add metafields to resource that has been saved" if new? metafield.save metafield end - + def events Event.find(:all) end - end + end end diff --git a/lib/shopify_api/version.rb b/lib/shopify_api/version.rb index 5ef7eccdf..97a3c3721 100644 --- a/lib/shopify_api/version.rb +++ b/lib/shopify_api/version.rb @@ -1,3 +1,3 @@ module ShopifyAPI - VERSION = "4.6.0" + VERSION = "4.11.0" end diff --git a/test/collection_listing_test.rb b/test/collection_listing_test.rb index d58d9b876..5fc62f7de 100644 --- a/test/collection_listing_test.rb +++ b/test/collection_listing_test.rb @@ -3,23 +3,39 @@ class CollectionListingTest < Test::Unit::TestCase def test_get_collection_listings - fake "applications/999/collection_listings", method: :get, status: 201, body: load_fixture('collection_listings') + fake "collection_listings", method: :get, status: 201, body: load_fixture('collection_listings') - collection_listings = ShopifyAPI::CollectionListing.find(:all, params: { application_id: 999 }) + collection_listings = ShopifyAPI::CollectionListing.find(:all) assert_equal 1, collection_listings.count assert_equal 1, collection_listings.first.collection_id assert_equal 'Home page', collection_listings.first.title end - def test_get_collection_listing_for_collection_id - fake "applications/999/collection_listings/1", method: :get, status: 201, body: load_fixture('collection_listing') - fake "applications/999/collection_listings//1/product_ids", method: :get, status: 201, body: load_fixture('collection_listing_product_ids') + def test_get_collection_listing + fake "collection_listings/1", method: :get, status: 201, body: load_fixture('collection_listing') - collection_listing = ShopifyAPI::CollectionListing.find(1, params: { application_id: 999 }) + collection_listing = ShopifyAPI::CollectionListing.find(1) assert_equal 1, collection_listing.collection_id assert_equal 'Home page', collection_listing.title + end + + def test_get_collection_listing_reload + fake "collection_listings/1", method: :get, status: 201, body: load_fixture('collection_listing') + + collection_listing = ShopifyAPI::CollectionListing.new(collection_id: 1) + collection_listing.reload + + assert_equal 1, collection_listing.collection_id + assert_equal 'Home page', collection_listing.title + end + + def test_get_collection_listing_product_ids + fake "collection_listings/1/product_ids", method: :get, status: 201, body: load_fixture('collection_listing_product_ids') + + collection_listing = ShopifyAPI::CollectionListing.new(collection_id: 1) + assert_equal [1, 2], collection_listing.product_ids end end diff --git a/test/discount_code_test.rb b/test/discount_code_test.rb new file mode 100644 index 000000000..de14527aa --- /dev/null +++ b/test/discount_code_test.rb @@ -0,0 +1,53 @@ +require 'test_helper' + +class DiscountCodeTest < Test::Unit::TestCase + def setup + super + fake 'price_rules/102586120/discount_codes/1002091923', body: load_fixture('discount_code') + + @discount_code = ShopifyAPI::DiscountCode.find(1002091923, params: {price_rule_id: 102586120}) + end + + def test_get_discount_code + fake 'price_rules/102586120/discount_codes', method: :get, status: 200, body: load_fixture('discount_code') + discount_code = ShopifyAPI::DiscountCode.find 1002091923, params: { price_rule_id: 102586120 } + + assert_equal 1002091923, discount_code.id + end + + def test_get_all_discount_codes + fake 'price_rules/102586120/discount_codes', method: :get, status: 200, body: load_fixture('discount_codes') + discount_codes = ShopifyAPI::DiscountCode.all params: { price_rule_id: 102586120 } + + assert_equal 1, discount_codes.length + assert_equal 1002091923, discount_codes.first.id + end + + def test_create_discount_code + fake 'price_rules/102586120/discount_codes', method: :post, status: 201, body: load_fixture('discount_code') + discount_code = ShopifyAPI::DiscountCode.new + discount_code.prefix_options[:price_rule_id] = 102586120 + discount_code.code = "SUMMERSALE10" + discount_code.save + + assert_equal '{"discount_code":{"code":"SUMMERSALE10"}}', FakeWeb.last_request.body + end + + def test_update_discount_code + discount_code_response = ActiveSupport::JSON.decode(load_fixture('discount_code')) + discount_code_response['discount_code']['code'] = "WINTERSALE50" + @discount_code.code = "WINTERSALE50" + + fake 'price_rules/102586120/discount_codes/1002091923', method: :put, status: 200, body: ActiveSupport::JSON.encode(discount_code_response) + + @discount_code.save + + assert_equal discount_code_response['discount_code']['code'], @discount_code.code + end + + def test_delete_discount_code + fake 'price_rules/102586120/discount_codes/1002091923', method: :delete, body: 'destroyed' + + assert @discount_code.destroy + end +end diff --git a/test/discount_test.rb b/test/discount_test.rb deleted file mode 100644 index bc5843516..000000000 --- a/test/discount_test.rb +++ /dev/null @@ -1,52 +0,0 @@ -require 'test_helper' - -class DiscountTest < Test::Unit::TestCase - test 'get should get a discount' do - fake 'discounts/680866', method: :get, status: 200, body: load_fixture('discount') - - discount = ShopifyAPI::Discount.find(680866) - assert_equal 680866, discount.id - end - - test 'get should get all discounts' do - fake 'discounts', method: :get, status: 200, body: load_fixture('discounts') - - discounts = ShopifyAPI::Discount.all - assert_equal 'TENOFF', discounts.first.code - end - - test 'create should create a discount' do - fake 'discounts', method: :post, status: 201, body: load_fixture('discount') - - discount = ShopifyAPI::Discount.create(code: 'TENOFF', discount_type: 'percentage') - assert_equal 'TENOFF', discount.code - end - - test 'should disable discount' do - fake 'discounts/680866', method: :get, status: 200, body: load_fixture('discount') - fake 'discounts/680866/disable', method: :post, status: 201, body: load_fixture('discount_disabled') - - discount = ShopifyAPI::Discount.find(680866) - discount.disable - - assert_equal "disabled", discount.status - end - - test 'should enable discount' do - fake 'discounts/680866', method: :get, status: 200, body: load_fixture('discount') - fake 'discounts/680866/enable', method: :post, status: 201, body: load_fixture('discount') - - discount = ShopifyAPI::Discount.find(680866) - discount.enable - - assert_equal "enabled", discount.status - end - - test 'delete should delete discount' do - fake 'discounts/680866', method: :get, status: 200, body: load_fixture('discount') - fake 'discounts/680866', method: :delete, status: 200, body: 'destroyed' - - discount = ShopifyAPI::Discount.find(680866) - assert discount.destroy - end -end diff --git a/test/draft_order_test.rb b/test/draft_order_test.rb index 6de59ddaa..e5af7d9a4 100644 --- a/test/draft_order_test.rb +++ b/test/draft_order_test.rb @@ -103,15 +103,27 @@ def test_add_metafields_to_draft_order assert_equal '123@example.com', field.value end - def test_get_metafields_for_draft_order + def test_get_all_metafields_for_draft_order fake 'draft_orders/517119332/metafields', body: load_fixture('metafields') metafields = @draft_order.metafields - assert_equal 2, metafields.length + assert_equal 3, metafields.length assert metafields.all? { |m| m.is_a?(ShopifyAPI::Metafield) } end + def test_get_2_metafields_for_draft_order + body = ActiveSupport::JSON.decode load_fixture 'metafields' + body['metafields'].slice! 2, 1 + + fake 'draft_orders/517119332/metafields.json?limit=2', body: body.to_json, extension: false + + metafields = @draft_order.metafields limit: 2 + + assert_equal 2, metafields.length + assert metafields.all?{ |m| m.is_a? ShopifyAPI::Metafield } + end + def test_complete_draft_order_with_no_params completed_fixture = load_fixture('draft_order_completed') completed_draft = ActiveSupport::JSON.decode(completed_fixture)['draft_order'] diff --git a/test/fixtures/discount.json b/test/fixtures/discount.json deleted file mode 100644 index 889879ca3..000000000 --- a/test/fixtures/discount.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "discount": { - "id": 680866, - "code": "TENOFF", - "value": "10.0", - "ends_at": null, - "starts_at": null, - "status": "enabled", - "minimum_order_amount": "0.00", - "usage_limit": null, - "applies_to_id": null, - "applies_once": false, - "discount_type": "percentage", - "applies_to_resource": null, - "times_used": 1 - } -} diff --git a/test/fixtures/discount_code.json b/test/fixtures/discount_code.json new file mode 100644 index 000000000..80aa8f550 --- /dev/null +++ b/test/fixtures/discount_code.json @@ -0,0 +1,10 @@ +{ + "discount_code": { + "id": 1002091923, + "price_rule_id": 102586120, + "code": "SUMMERSALE10", + "usage_count": 5, + "created_at": "2017-03-09T19:22:49Z", + "updated_at": "2017-03-09T19:22:49Z" + } +} diff --git a/test/fixtures/discount_codes.json b/test/fixtures/discount_codes.json new file mode 100644 index 000000000..1ab2665ff --- /dev/null +++ b/test/fixtures/discount_codes.json @@ -0,0 +1,12 @@ +{ + "discount_codes": [ + { + "id": 1002091923, + "price_rule_id": 102586120, + "code": "SUMMERSALE10", + "usage_count": 5, + "created_at": "2017-03-09T19:22:49Z", + "updated_at": "2017-03-09T19:22:49Z" + } + ] +} diff --git a/test/fixtures/discount_disabled.json b/test/fixtures/discount_disabled.json deleted file mode 100644 index 83ff2d46c..000000000 --- a/test/fixtures/discount_disabled.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "discount": { - "id": 680866, - "code": "TENOFF", - "value": "10.0", - "ends_at": null, - "starts_at": null, - "status": "disabled", - "minimum_order_amount": "0.00", - "usage_limit": null, - "applies_to_id": null, - "applies_once": false, - "discount_type": "percentage", - "applies_to_resource": null, - "times_used": 1 - } -} diff --git a/test/fixtures/discounts.json b/test/fixtures/discounts.json deleted file mode 100644 index 48573c186..000000000 --- a/test/fixtures/discounts.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "discounts": [ - { - "id": 680866, - "code": "TENOFF", - "value": "10.0", - "ends_at": null, - "starts_at": null, - "status": "enabled", - "minimum_order_amount": "0.00", - "usage_limit": null, - "applies_to_id": null, - "applies_once": false, - "discount_type": "percentage", - "applies_to_resource": null, - "times_used": 1 - }, - { - "id": 949676421, - "code": "xyz", - "value": "10.00", - "ends_at": null, - "starts_at": null, - "status": "disabled", - "minimum_order_amount": "0.00", - "usage_limit": null, - "applies_to_id": null, - "applies_once": false, - "discount_type": "fixed_amount", - "applies_to_resource": null, - "times_used": 0 - } - ] -} diff --git a/test/fixtures/engagement.json b/test/fixtures/engagement.json new file mode 100644 index 000000000..4f0c9c4d5 --- /dev/null +++ b/test/fixtures/engagement.json @@ -0,0 +1,15 @@ +{ + "engagements": [ + { + "occurred_on": "2017-04-20", + "impressions_count": null, + "views_count": null, + "clicks_count": 10, + "shares_count": null, + "favorites_count": null, + "comments_count": null, + "ad_spend": null, + "is_cumulative": true + } + ] +} diff --git a/test/fixtures/inventory_level.json b/test/fixtures/inventory_level.json new file mode 100644 index 000000000..fbc002493 --- /dev/null +++ b/test/fixtures/inventory_level.json @@ -0,0 +1,7 @@ +{ + "inventory_level" : { + "inventory_item_id": 808950810, + "location_id": 905684977, + "available": 1 + } +} diff --git a/test/fixtures/inventory_levels.json b/test/fixtures/inventory_levels.json new file mode 100644 index 000000000..628c9b550 --- /dev/null +++ b/test/fixtures/inventory_levels.json @@ -0,0 +1,24 @@ +{ + "inventory_levels": [ + { + "inventory_item_id": 39072856, + "location_id": 487838322, + "available": 27 + }, + { + "inventory_item_id": 808950810, + "location_id": 905684977, + "available": 1 + }, + { + "inventory_item_id": 808950810, + "location_id": 487838322, + "available": 9 + }, + { + "inventory_item_id": 39072856, + "location_id": 905684977, + "available": 3 + } + ] +} diff --git a/test/fixtures/metafields.json b/test/fixtures/metafields.json index 78995109c..5a5fefc7f 100644 --- a/test/fixtures/metafields.json +++ b/test/fixtures/metafields.json @@ -19,6 +19,16 @@ "description": null, "key": "phone", "value_type": "string" + }, + { + "created_at": "2017-04-24T20:14:24.031-04:00", + "updated_at": "2017-04-24T20:14:24.031-04:00", + "namespace": "contact", + "id": "72544103001", + "value": "Ottawa", + "description": null, + "key": "City", + "value_type": "string" } ] } diff --git a/test/fixtures/order_with_properties.json b/test/fixtures/order_with_properties.json new file mode 100644 index 000000000..b391807a4 --- /dev/null +++ b/test/fixtures/order_with_properties.json @@ -0,0 +1,373 @@ +{ + "order": { + "buyer_accepts_marketing": false, + "cancel_reason": null, + "cancelled_at": null, + "cart_token": "68778783ad298f1c80c3bafcddeea02f", + "checkout_token": null, + "closed_at": null, + "confirmed": false, + "created_at": "2008-01-10T11:00:00-05:00", + "currency": "USD", + "email": "bob.norman@hostmail.com", + "financial_status": "authorized", + "fulfillment_status": null, + "gateway": "authorize_net", + "id": 450789469, + "landing_site": "http://www.example.com?source=abc", + "location_id": null, + "name": "#1001", + "note": "Test note", + "number": 1, + "reference": "fhwdgads", + "referring_site": "http://www.otherexample.com", + "source": null, + "source_identifier": "fhwdgads", + "source_name": "web", + "source_url": null, + "subtotal_price": "398.00", + "taxes_included": false, + "test": false, + "token": "b1946ac92492d2347c6235b4d2611184", + "total_discounts": "0.00", + "total_line_items_price": "398.00", + "total_price": "409.94", + "total_price_usd": "409.94", + "total_tax": "11.94", + "total_weight": 0, + "updated_at": "2008-01-10T11:00:00-05:00", + "user_id": null, + "browser_ip": null, + "landing_site_ref": "abc", + "order_number": 1001, + "discount_codes": [], + "note_attributes": [], + "processing_method": "direct", + "checkout_id": 450789469, + "tax_lines": [ + { + "price": "11.94", + "rate": 0.06, + "title": "State Tax" + } + ], + "tags": "", + "line_items": [ + { + "fulfillment_service": "manual", + "fulfillment_status": null, + "grams": 1361, + "id": 466157049, + "price": "45.00", + "product_id": 632910392, + "quantity": 1, + "requires_shipping": true, + "sku": "", + "taxable": true, + "title": "Create Your Own Coffee 3 Pack", + "variant_id": 39072856, + "variant_title": "", + "vendor": "VCR", + "name": "Create Your Own Coffee 3 Pack", + "variant_inventory_management": null, + "properties": [ + { + "name": "1st Coffee", + "value": "Coffee1" + }, + { + "name": "2nd Coffee", + "value": "Coffee2" + }, + { + "name": "3rd Coffee", + "value": "Coffee3" + }, + { + "name": "Select Your Grind", + "value": "Ground" + } + ], + "product_exists": true, + "tax_lines": [ + + ] + }, + { + "fulfillment_service": "manual", + "fulfillment_status": null, + "grams": 680, + "id": 641254555689, + "price": "24.00", + "product_id": 288331137065, + "quantity": 1, + "requires_shipping": true, + "sku": "", + "taxable": true, + "title": "Create Your Own Coffee 3 Pack (8oz bags)", + "variant_id": 4107806867497, + "variant_title": "", + "vendor": "OMC", + "name": "Create Your Own Coffee 3 Pack (8oz bags)", + "variant_inventory_management": null, + "properties": [ + { + "name": "By default may label with \"Roasted for ", + "value": { + "Your First Name": { + "\". If you want something specific on the label, enter it here:": "" + } + } + }, + { + "name": "Select Your Grind", + "value": "Ground" + }, + { + "name": "Coffees", + "value": "Coffee blend 1" + }, + { + "name": "Coffees", + "value": "Coffee blend 2" + }, + { + "name": "Coffees", + "value": "Coffee blend 3" + } + ], + "product_exists": true, + "tax_lines": [ + + ] + } + ], + "shipping_lines": [ + { + "code": "Free Shipping", + "price": "0.00", + "source": "shopify", + "title": "Free Shipping", + "tax_lines": [ + + ] + } + ], + "payment_details": { + "avs_result_code": null, + "credit_card_bin": null, + "cvv_result_code": null, + "credit_card_number": "XXXX-XXXX-XXXX-4242", + "credit_card_company": "Visa" + }, + "billing_address": { + "address1": "Chestnut Street 92", + "address2": "", + "city": "Louisville", + "company": null, + "country": "United States", + "first_name": "Bob", + "last_name": "Norman", + "latitude": "45.41634", + "longitude": "-75.6868", + "phone": "555-625-1199", + "province": "Kentucky", + "zip": "40202", + "name": "Bob Norman", + "country_code": "US", + "province_code": "KY" + }, + "shipping_address": { + "address1": "Chestnut Street 92", + "address2": "", + "city": "Louisville", + "company": null, + "country": "United States", + "first_name": "Bob", + "last_name": "Norman", + "latitude": "45.41634", + "longitude": "-75.6868", + "phone": "555-625-1199", + "province": "Kentucky", + "zip": "40202", + "name": "Bob Norman", + "country_code": "US", + "province_code": "KY" + }, + "fulfillments": [ + { + "created_at": "2014-03-07T16:14:08-05:00", + "id": 255858046, + "order_id": 450789469, + "service": "manual", + "status": "failure", + "tracking_company": null, + "updated_at": "2014-03-07T16:14:08-05:00", + "tracking_number": "1Z2345", + "tracking_numbers": [ + "1Z2345" + ], + "tracking_url": "http://wwwapps.ups.com/etracking/tracking.cgi?InquiryNumber1=1Z2345&TypeOfInquiryNumber=T&AcceptUPSLicenseAgreement=yes&submit=Track", + "tracking_urls": [ + "http://wwwapps.ups.com/etracking/tracking.cgi?InquiryNumber1=1Z2345&TypeOfInquiryNumber=T&AcceptUPSLicenseAgreement=yes&submit=Track" + ], + "receipt": { + "testcase": true, + "authorization": "123456" + }, + "line_items": [ + { + "fulfillment_service": "manual", + "fulfillment_status": null, + "grams": 680, + "id": 641254555689, + "price": "24.00", + "product_id": 288331137065, + "quantity": 1, + "requires_shipping": true, + "sku": "", + "taxable": true, + "title": "Create Your Own Coffee 3 Pack (8oz bags)", + "variant_id": 4107806867497, + "variant_title": "", + "vendor": "OMC", + "name": "Create Your Own Coffee 3 Pack (8oz bags)", + "variant_inventory_management": null, + "properties": [ + { + "name": "By default may label with \"Roasted for ", + "value": { + "Your First Name": { + "\". If you want something specific on the label, enter it here:": "" + } + } + }, + { + "name": "Select Your Grind", + "value": "Ground" + }, + { + "name": "Coffees", + "value": "Coffee blend 1" + }, + { + "name": "Coffees", + "value": "Coffee blend 2" + }, + { + "name": "Coffees", + "value": "Coffee blend 3" + } + ], + "product_exists": true, + "tax_lines": [ + + ] + } + ] + }, + { + "created_at": "2014-03-07T16:14:08-05:00", + "id": 255858046, + "order_id": 450789469, + "service": "manual", + "status": "failure", + "tracking_company": null, + "updated_at": "2014-03-07T16:14:08-05:00", + "tracking_number": "1Z2345", + "tracking_numbers": [ + "1Z2345" + ], + "tracking_url": "http://wwwapps.ups.com/etracking/tracking.cgi?InquiryNumber1=1Z2345&TypeOfInquiryNumber=T&AcceptUPSLicenseAgreement=yes&submit=Track", + "tracking_urls": [ + "http://wwwapps.ups.com/etracking/tracking.cgi?InquiryNumber1=1Z2345&TypeOfInquiryNumber=T&AcceptUPSLicenseAgreement=yes&submit=Track" + ], + "receipt": {}, + "line_items": [ + { + "fulfillment_service": "manual", + "fulfillment_status": null, + "grams": 1361, + "id": 466157049, + "price": "45.00", + "product_id": 632910392, + "quantity": 1, + "requires_shipping": true, + "sku": "", + "taxable": true, + "title": "Create Your Own Coffee 3 Pack", + "variant_id": 39072856, + "variant_title": "", + "vendor": "VCR", + "name": "Create Your Own Coffee 3 Pack", + "variant_inventory_management": null, + "properties": [ + { + "name": "1st Coffee", + "value": "Coffee1" + }, + { + "name": "2nd Coffee", + "value": "Coffee2" + }, + { + "name": "3rd Coffee", + "value": "Coffee3" + }, + { + "name": "Select Your Grind", + "value": "Ground" + } + ], + "product_exists": true, + "tax_lines": [ + + ] + } + ] + } + ], + "client_details": { + "accept_language": null, + "browser_ip": "0.0.0.0", + "session_hash": null, + "user_agent": null + }, + "customer": { + "accepts_marketing": false, + "created_at": "2014-03-07T16:14:08-05:00", + "email": "bob.norman@hostmail.com", + "first_name": "Bob", + "id": 207119551, + "last_name": "Norman", + "last_order_id": null, + "multipass_identifier": null, + "note": null, + "orders_count": 0, + "state": "disabled", + "total_spent": "0.00", + "updated_at": "2014-03-07T16:14:08-05:00", + "verified_email": true, + "tags": "", + "last_order_name": null, + "default_address": { + "address1": "Chestnut Street 92", + "address2": "", + "city": "Louisville", + "company": null, + "country": "United States", + "first_name": null, + "id": 207119551, + "last_name": null, + "phone": "555-625-1199", + "province": "Kentucky", + "zip": "40202", + "name": null, + "province_code": "KY", + "country_code": "US", + "country_name": "United States", + "default": true + } + } + } +} diff --git a/test/fixtures/price_rule.json b/test/fixtures/price_rule.json new file mode 100644 index 000000000..5d1f407a3 --- /dev/null +++ b/test/fixtures/price_rule.json @@ -0,0 +1,27 @@ +{ + "price_rule": { + "id": 102586120, + "target_type": "line_item", + "target_selection": "entitled", + "allocation_method": "across", + "value_type": "fixed_amount", + "value": -10.0, + "customer_selection": "all", + "once_per_customer": false, + "usage_limit": 10, + "created_at": "2016-09-11T09:00:00-04:00", + "updated_at": "2016-09-11T09:30:00-04:00", + "starts_at": "2016-09-12T0:00:00-04:00", + "ends_at": "2016-09-12T00:00:00-04:00", + "entitled_product_ids": [22,278,293], + "entitled_variant_ids": [], + "entitled_collection_ids": [], + "entitled_country_ids": [], + "prerequisite_subtotal_range": { + "greater_than_or_equal_to": 10 + }, + "prerequisite_shipping_price_range": {}, + "prerequisite_saved_search_ids": [34,88], + "title": "Summer Sale Event 2017" + } +} diff --git a/test/fixtures/price_rules.json b/test/fixtures/price_rules.json new file mode 100644 index 000000000..33544722e --- /dev/null +++ b/test/fixtures/price_rules.json @@ -0,0 +1,28 @@ +{ + "price_rules": [ + { + "id": 102586120, + "target_type": "line_items", + "target_selection": "entitled", + "allocation_method": "each", + "value_type": "fixed_amount", + "value": -10, + "once_per_customer": false, + "usage_limit": 10, + "created_at": "2016-09-11T09:00:00-04:00", + "updated_at": "2016-09-11T09:30:00-04:00", + "starts_at": "2016-09-12T0:00:00-04:00", + "ends_at": "2016-09-12T00:00:00-04:00", + "entitled_product_ids": [22,278,293], + "entitled_variant_ids": [], + "entitled_collection_ids": [], + "entitled_country_ids": [], + "prerequisite_subtotal_range": { + "greater_than_or_equal_to": 10 + }, + "prerequisite_shipping_price_range": {}, + "prerequisite_saved_search_ids": [34,88], + "title": "Summer Sale Event 2017" + } + ] +} diff --git a/test/inventory_level_test.rb b/test/inventory_level_test.rb new file mode 100644 index 000000000..ceb214b96 --- /dev/null +++ b/test/inventory_level_test.rb @@ -0,0 +1,59 @@ +require 'test_helper' + +class InventoryLevelTest < Test::Unit::TestCase + def setup + super + @inventory_level_response = ActiveSupport::JSON.decode load_fixture('inventory_level') + @inventory_level = ShopifyAPI::InventoryLevel.new(@inventory_level_response['inventory_level']) + end + + test ".find with inventory_item_ids and location_ids returns expected inventory levels" do + params = { inventory_item_ids: [808950810, 39072856], location_ids: [905684977, 487838322] } + fake "inventory_levels.json?#{params.to_param}", extension: false, method: :get, + status: 200, body: load_fixture('inventory_levels') + inventory_levels = ShopifyAPI::InventoryLevel.find(:all, params: params) + + assert inventory_levels.all? { |item| + params[:location_ids].include?(item.location_id) && + params[:inventory_item_ids].include?(item.inventory_item_id) + }, message: 'Response contained inventory_items or locations not requested.' + end + + test '#adjust with adjustment value returns inventory_level with available increased by adjustment value' do + adjustment = 5 + updated_available = @inventory_level.available + adjustment + @inventory_level_response[:available] = updated_available + + fake 'inventory_levels/adjust', method: :post, body: ActiveSupport::JSON.encode(@inventory_level_response) + @inventory_level.adjust(adjustment) + assert_equal updated_available, @inventory_level.available + end + + test '#connect saves an inventory_level associated with inventory_item and location_id' do + params = { inventory_item_id: 808950810, location_id: 99999999 } + response = params.clone + response[:available] = 0 + + fake 'inventory_levels/connect', method: :post, body: ActiveSupport::JSON.encode(response) + inventory_level = ShopifyAPI::InventoryLevel.new(params) + inventory_level.connect + assert_equal 0, inventory_level.available, message: 'expected newly connected location to have 0 inventory' + end + + test '#destroy removes inventory_level and returns nil' do + params = { inventory_item_id: @inventory_level.inventory_item_id, location_id: @inventory_level.location_id } + fake "inventory_levels.json?#{params.to_param}", extension: false, method: :delete, status: 204, body: nil + assert_nil @inventory_level.destroy + end + + test '#set with available value returns inventory_level with available as the available value' do + available = 13 + response = @inventory_level_response.clone + response['inventory_level']['available'] = available + + fake 'inventory_levels/set', method: :post, body: ActiveSupport::JSON.encode(response) + @inventory_level.set(available) + + assert_equal available, @inventory_level.available + end +end diff --git a/test/location_test.rb b/test/location_test.rb new file mode 100644 index 000000000..8fec86c99 --- /dev/null +++ b/test/location_test.rb @@ -0,0 +1,14 @@ +require 'test_helper' + +class LocationTest < Test::Unit::TestCase + test '#inventory_levels returns all inventory_levels associated with this location' do + location = ShopifyAPI::Location.new(id: 487838322) + expected_body = JSON.parse(load_fixture('inventory_levels')) + expected_body['inventory_levels'].delete_if {|level| level['location_id'] != location.id } + fake "locations/#{location.id}/inventory_levels", method: :get, status: 200, body: JSON(expected_body).to_s + inventory_levels = location.inventory_levels + + assert inventory_levels.all? { |item| item.location_id == location.id }, + message: 'Response contained locations other than the current location.' + end +end diff --git a/test/marketing_event_test.rb b/test/marketing_event_test.rb index 2a85e93b1..b7cb112a1 100644 --- a/test/marketing_event_test.rb +++ b/test/marketing_event_test.rb @@ -46,4 +46,23 @@ def test_count_marketing_events marketing_events_count = ShopifyAPI::MarketingEvent.get(:count) assert_equal 2, marketing_events_count end + + def test_add_engagements + fake "marketing_events/1", method: :get, body: load_fixture('marketing_event') + marketing_event = ShopifyAPI::MarketingEvent.find(1) + fake "marketing_events/1/engagements", method: :post, status: 201, body: load_fixture('engagement') + engagement = { + occurred_on: "2017-04-20", + impressions_count: nil, + views_count: nil, + clicks_count: 10, + shares_count: nil, + favorites_count: nil, + comments_count: nil, + ad_spend: nil, + is_cumulative: true + } + marketing_event.add_engagements(engagement) + assert "2017-04-20", engagement[:occurred_on] + end end diff --git a/test/message_enricher_test.rb b/test/message_enricher_test.rb new file mode 100644 index 000000000..d503a821b --- /dev/null +++ b/test/message_enricher_test.rb @@ -0,0 +1,45 @@ +require 'test_helper' + +class MessageEnricherTest < Test::Unit::TestCase + + def test_enriches_initial_message_when_body_contains_error + response = enriched_response(422, 'InitialMessage', { error: 'My Error' }) + + assert_equal 'InitialMessage (My Error)', response.message + end + + def test_enriches_initial_message_when_body_contains_errors_array + response = enriched_response(422, 'InitialMessage', { errors: ['My Error1', 'My Error2'] }) + + assert_equal 'InitialMessage (My Error1; My Error2)', response.message + end + + def test_enriches_initial_message_when_body_contains_errors_single_value + response = enriched_response(422, 'InitialMessage', { errors: 'My Error1' }) + + assert_equal 'InitialMessage (My Error1)', response.message + end + + def test_returns_initial_message_when_code_is_200 + response = enriched_response(200, 'InitialMessage', { result: 'Success' }) + + assert_equal 'InitialMessage', response.message + end + + def test_returns_initial_message_when_body_cant_be_parsed + response = enriched_response(422, 'InitialMessage', 'not a json') + + assert_equal 'InitialMessage', response.message + end + + private + + def enriched_response(code, message, body) + mock_response = + Struct + .new(:code, :message, :body) + .new(code.to_s, message.to_s, body.to_json) + + ShopifyAPI::MessageEnricher.new(mock_response) + end +end diff --git a/test/order_test.rb b/test/order_test.rb index 5dbf3df38..cc3724d4f 100644 --- a/test/order_test.rb +++ b/test/order_test.rb @@ -8,12 +8,25 @@ class OrderTest < Test::Unit::TestCase assert_equal 39072856, order.line_items.first.variant_id end + test "create should create an order with custom properties" do + props = [{ :"By default may label with \"Roasted for " => { :"Your First Name" => { :"\". If you want something specific on the label, enter it here:" => "" }}}] + fake 'orders', :method => :post, :status => 201, :body => load_fixture('order_with_properties') + order = ShopifyAPI::Order.create(line_items: [{quantity:1, variant_id:39072856, properties:props}], financial_status:"authorized") + assert_equal 39072856, order.line_items.first.variant_id + end + test "get should get an order" do fake 'orders/450789469', :method => :get, :status => 200, :body => load_fixture('order') order = ShopifyAPI::Order.find(450789469) assert_equal 450789469, order.id end + test "get should get an order with custom properties" do + fake 'orders/450789469', :method => :get, :status => 200, :body => load_fixture('order_with_properties') + order = ShopifyAPI::Order.find(450789469) + assert_equal 450789469, order.id + end + test "get all should get all orders" do fake 'orders', :method => :get, :status => 200, :body => load_fixture('orders') order = ShopifyAPI::Order.all @@ -44,4 +57,3 @@ class OrderTest < Test::Unit::TestCase assert_request_body({'email' => false, 'restock' => true}.to_json) end end - diff --git a/test/price_rule_test.rb b/test/price_rule_test.rb new file mode 100644 index 000000000..1ef0d88cb --- /dev/null +++ b/test/price_rule_test.rb @@ -0,0 +1,65 @@ +require 'test_helper' + +class PriceRuleTest < Test::Unit::TestCase + def setup + super + fake 'price_rules/102586120', body: load_fixture('price_rule') + + @price_rule = ShopifyAPI::PriceRule.find(102586120) + end + + def test_get_price_rule + fake 'price_rules/102586120', method: :get, status: 200, body: load_fixture('price_rule') + price_rule = ShopifyAPI::PriceRule.find(102586120) + + assert_equal 102586120, price_rule.id + end + + def test_get_all_price_rules + fake 'price_rules', method: :get, status: 200, body: load_fixture('price_rules') + price_rules = ShopifyAPI::PriceRule.all + + assert_equal 1, price_rules.length + assert_equal 102586120, price_rules.first.id + end + + def test_get_all_discount_codes_for_a_price_rule + fake 'price_rules/102586120/discount_codes', method: :get, status: 200, body: load_fixture('discount_codes') + price_rule = ShopifyAPI::PriceRule.find(102586120) + + assert_equal "SUMMERSALE10", price_rule.discount_codes.first.code + end + + def test_create_price_rule + fake 'price_rules', method: :post, status: 201, body: load_fixture('price_rule') + + price_rule = ShopifyAPI::PriceRule.create( + target_type: "line_item", + allocation_method: "across", + value_type: "fixed_amount", + value: -10.0, + customer_selection: "all", + starts_at: "2017-01-19T00:00:00Z" + ) + + assert_equal '{"price_rule":{"target_type":"line_item","allocation_method":"across","value_type":"fixed_amount","value":-10.0,"customer_selection":"all","starts_at":"2017-01-19T00:00:00Z"}}', FakeWeb.last_request.body + assert_equal -10, price_rule.value + end + + def test_update_price_rule + price_rule_response = ActiveSupport::JSON.decode(load_fixture('price_rule')) + price_rule_response['price_rule']['value'] = -50.0 + @price_rule.value = -50.0 + fake 'price_rules/102586120', method: :put, status: 200, body: ActiveSupport::JSON.encode(price_rule_response) + + @price_rule.save + + assert_equal price_rule_response['price_rule']['value'], @price_rule.value + end + + def test_delete_price_rule + fake 'price_rules/102586120', method: :delete, body: 'destroyed' + + assert @price_rule.destroy + end +end diff --git a/test/product_listing_test.rb b/test/product_listing_test.rb index d86d9a48d..0cfcf817e 100644 --- a/test/product_listing_test.rb +++ b/test/product_listing_test.rb @@ -3,9 +3,9 @@ class ProductListingTest < Test::Unit::TestCase def test_get_product_listings - fake "applications/999/product_listings", method: :get, status: 201, body: load_fixture('product_listings') + fake "product_listings", method: :get, status: 201, body: load_fixture('product_listings') - product_listings = ShopifyAPI::ProductListing.find(:all, params: { application_id: 999 }) + product_listings = ShopifyAPI::ProductListing.find(:all) assert_equal 2, product_listings.count assert_equal 2, product_listings.first.product_id assert_equal 1, product_listings.last.product_id @@ -13,17 +13,26 @@ def test_get_product_listings assert_equal 'Rustic Copper Bottle', product_listings.last.title end - def test_get_product_listing_for_product_id - fake "applications/999/product_listings/2", method: :get, status: 201, body: load_fixture('product_listing') + def test_get_product_listing + fake "product_listings/2", method: :get, status: 201, body: load_fixture('product_listing') + + product_listing = ShopifyAPI::ProductListing.find(2) + assert_equal 'Synergistic Silk Chair', product_listing.title + end + + def test_reload_product_listing + fake "product_listings/2", method: :get, status: 201, body: load_fixture('product_listing') + + product_listing = ShopifyAPI::ProductListing.new(product_id: 2) + product_listing.reload - product_listing = ShopifyAPI::ProductListing.find(2, params: { application_id: 999 }) assert_equal 'Synergistic Silk Chair', product_listing.title end def test_get_product_listing_product_ids - fake "applications/999/product_listings/product_ids", method: :get, status: 201, body: load_fixture('product_listing_product_ids') + fake "product_listings/product_ids", method: :get, status: 201, body: load_fixture('product_listing_product_ids') - product_ids = ShopifyAPI::ProductListing.product_ids(params: { application_id: 999 }) + product_ids = ShopifyAPI::ProductListing.product_ids assert_equal 2, product_ids.count assert_equal 2, product_ids.first assert_equal 1, product_ids.last diff --git a/test/product_test.rb b/test/product_test.rb index cc58fe987..fc0706f45 100644 --- a/test/product_test.rb +++ b/test/product_test.rb @@ -19,13 +19,25 @@ def test_add_metafields_to_product assert_equal "123@example.com", field.value end - def test_get_metafields_for_product + def test_get_all_metafields_for_product fake "products/632910392/metafields", :body => load_fixture('metafields') metafields = @product.metafields + assert_equal 3, metafields.length + assert metafields.all?{ |m| m.is_a? ShopifyAPI::Metafield } + end + + def test_get_2_metafields_for_product + body = ActiveSupport::JSON.decode load_fixture 'metafields' + body['metafields'].slice! 2, 1 + + fake 'products/632910392/metafields.json?limit=2', body: body.to_json, extension: false + + metafields = @product.metafields limit: 2 + assert_equal 2, metafields.length - assert metafields.all?{|m| m.is_a?(ShopifyAPI::Metafield)} + assert metafields.all?{ |m| m.is_a? ShopifyAPI::Metafield } end def test_update_loaded_variant diff --git a/test/shop_test.rb b/test/shop_test.rb index 22223d8c1..fc91d0430 100644 --- a/test/shop_test.rb +++ b/test/shop_test.rb @@ -25,15 +25,27 @@ def test_current_with_options_should_return_current_shop assert_equal "apple.myshopify.com", @shop.myshopify_domain end - def test_get_metafields_for_shop + def test_get_all_metafields_for_shop fake "metafields" metafields = @shop.metafields - assert_equal 2, metafields.length + assert_equal 3, metafields.length assert metafields.all?{|m| m.is_a?(ShopifyAPI::Metafield)} end + def test_get_2_metafields_for_shop + body = ActiveSupport::JSON.decode load_fixture 'metafields' + body['metafields'].slice! 2, 1 + + fake 'metafields.json?limit=2', body: body.to_json, extension: false + + metafields = @shop.metafields limit: 2 + + assert_equal 2, metafields.length + assert metafields.all?{ |m| m.is_a? ShopifyAPI::Metafield } + end + def test_add_metafield fake "metafields", :method => :post, :status => 201, :body =>load_fixture('metafield')