From 9c07aa1770d4b0faefb098b0930e198ecedf2976 Mon Sep 17 00:00:00 2001 From: MJ Rossetti Date: Tue, 25 Sep 2018 18:45:35 -0400 Subject: [PATCH] Support for latest API version --- .gitignore | 2 +- .travis.yml | 9 +- lib/stripe_mock/api/webhooks.rb | 3 + lib/stripe_mock/data.rb | 40 +- .../request_handlers/helpers/token_helpers.rb | 2 +- lib/stripe_mock/request_handlers/invoices.rb | 7 +- lib/stripe_mock/request_handlers/products.rb | 1 + .../request_handlers/subscriptions.rb | 20 +- .../validators/param_validators.rb | 107 ++++- lib/stripe_mock/test_strategies/base.rb | 48 +- lib/stripe_mock/test_strategies/live.rb | 35 +- lib/stripe_mock/test_strategies/mock.rb | 8 +- lib/stripe_mock/version.rb | 2 +- .../webhook_fixtures/product.created.json | 34 ++ .../webhook_fixtures/product.deleted.json | 34 ++ .../webhook_fixtures/product.updated.json | 38 ++ spec/instance_spec.rb | 12 +- spec/server_spec.rb | 3 +- .../customer_examples.rb | 48 +- .../error_mock_examples.rb | 2 +- .../invoice_examples.rb | 66 +-- spec/shared_stripe_examples/plan_examples.rb | 221 +++++---- .../shared_stripe_examples/product_example.rb | 65 --- .../product_examples.rb | 156 ++++++ .../subscription_examples.rb | 451 ++++++++---------- .../subscription_items_examples.rb | 5 +- .../transfer_examples.rb | 4 +- spec/spec_helper.rb | 7 +- .../shared_contexts/stripe_validator_spec.rb | 8 + 29 files changed, 901 insertions(+), 537 deletions(-) create mode 100644 lib/stripe_mock/webhook_fixtures/product.created.json create mode 100644 lib/stripe_mock/webhook_fixtures/product.deleted.json create mode 100644 lib/stripe_mock/webhook_fixtures/product.updated.json delete mode 100644 spec/shared_stripe_examples/product_example.rb create mode 100644 spec/shared_stripe_examples/product_examples.rb create mode 100644 spec/support/shared_contexts/stripe_validator_spec.rb diff --git a/.gitignore b/.gitignore index 4a33f32e0..c053d63b6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ stripe-mock-server.pid Gemfile.lock stripe-mock-server.log .idea -.ruby-version \ No newline at end of file +.ruby-version diff --git a/.travis.yml b/.travis.yml index ddf506aef..dae526655 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,9 @@ group: deprecated-2017Q2 sudo: required language: ruby rvm: - - 2.0.0 - - 2.1.10 - - 2.2.7 - - 2.3.4 + - 2.4.6 + - 2.5.5 + - 2.6.3 before_install: - rvm 2.1.10 do gem install mime-types -v 2.6.2 - gem install bundler -v '< 2' @@ -17,7 +16,7 @@ script: "bundle exec rspec && bundle exec rspec -t live" env: global: - - IS_TRAVIS=true STRIPE_TEST_SECRET_KEY_A=sk_test_Ut2MSlZANdT3iDALdGhyLymy STRIPE_TEST_SECRET_KEY_B=sk_test_JXtzss9tHOG1ofIyEZgoUP4Q STRIPE_TEST_SECRET_KEY_C=sk_test_ZR5nVz9p3ivsqVa7mYB0sFep STRIPE_TEST_SECRET_KEY_D=sk_test_ZR5nVz9p3ivsqVa7mYB0sFep + - IS_TRAVIS=true STRIPE_TEST_SECRET_KEY_A=sk_test_BsztzqQjzd7lqkgo1LjEG5DF00KzH7tWKF STRIPE_TEST_SECRET_KEY_B=sk_test_rKCEu0x8jzg6cKPqoey8kUPQ00usQO3KYE STRIPE_TEST_SECRET_KEY_C=sk_test_qeaB7R6Ywp8sC9pzd1ZIABH700YLC7nhmZ notifications: webhooks: diff --git a/lib/stripe_mock/api/webhooks.rb b/lib/stripe_mock/api/webhooks.rb index 5ceba9e13..8f4a4c694 100644 --- a/lib/stripe_mock/api/webhooks.rb +++ b/lib/stripe_mock/api/webhooks.rb @@ -75,6 +75,9 @@ def self.event_list 'plan.created', 'plan.updated', 'plan.deleted', + 'product.created', + 'product.updated', + 'product.deleted', 'coupon.created', 'coupon.deleted', 'transfer.created', diff --git a/lib/stripe_mock/data.rb b/lib/stripe_mock/data.rb index 98664a4ba..b70862d0c 100644 --- a/lib/stripe_mock/data.rb +++ b/lib/stripe_mock/data.rb @@ -358,6 +358,7 @@ def self.mock_invoice(lines, params={}) created: 1349738950, period_end: 1349738950, period_start: 1349738950, + due_date: nil, lines: { object: "list", total_count: lines.count, @@ -385,7 +386,7 @@ def self.mock_invoice(lines, params={}) amount_paid: 0, currency: currency, starting_balance: 0, - ending_balance: nil, + ending_balance: 0, next_payment_attempt: 1349825350, charge: nil, discount: nil, @@ -399,6 +400,7 @@ def self.mock_invoice(lines, params={}) end due = invoice[:total] + invoice[:starting_balance] invoice[:amount_due] = due < 0 ? 0 : due + invoice[:ending_balance] = invoice[:starting_balance] + invoice[:total] if invoice[:amount_due] == 0 invoice end @@ -521,33 +523,49 @@ def self.mock_order_item(params={}) def self.mock_plan(params={}) currency = params[:currency] || StripeMock.default_currency { - id: "2", + id: "mock_plan_123", object: "plan", + active: true, + aggregate_usage: nil, amount: 2300, + billing_scheme: "per_unit", created: 1466698898, currency: currency, interval: "month", interval_count: 1, livemode: false, metadata: {}, - name: "The Basic Plan", - statement_descriptor: nil, - trial_period_days: nil + nickname: "My Mock Plan", + product: "mock_prod_NONEXIST", # override this with your own existing product id + tiers: nil, + tiers_mode: nil, + transform_usage: nil, + trial_period_days: nil, + usage_type: "licensed" }.merge(params) end - def self.mock_product(params = {}) + def self.mock_product(params={}) { - id: "default_test_prod", + id: "mock_prod_abc123", object: "product", active: true, - created: 1556896214, + attributes:[], + caption: nil, + created: 1466698000, + deactivate_on: [], + description: nil, + images: [], livemode: false, metadata: {}, - name: "Default Test Product", - statement_descriptor: "PRODUCT", + name: "The Mock Product", + package_dimensions: nil, + shippable: nil, + statement_descriptor: nil, type: "service", - updated: 1556918200, + unit_label: "my_unit", + updated: 1537939442, + url: nil }.merge(params) end diff --git a/lib/stripe_mock/request_handlers/helpers/token_helpers.rb b/lib/stripe_mock/request_handlers/helpers/token_helpers.rb index 82840cee0..666ddcb9d 100644 --- a/lib/stripe_mock/request_handlers/helpers/token_helpers.rb +++ b/lib/stripe_mock/request_handlers/helpers/token_helpers.rb @@ -36,7 +36,7 @@ def get_card_by_token(token) def get_card_or_bank_by_token(token) token_id = token['id'] || token - @card_tokens[token_id] || @bank_tokens[token_id] || raise(Stripe::InvalidRequestError.new("Invalid token id: #{token_id}", 'tok', http_status: 404)) + @card_tokens[token_id] || @bank_tokens[token_id] || raise(Stripe::InvalidRequestError.new("Invalid token id: #{token_id}", 'tok', http_status: 404)) end end diff --git a/lib/stripe_mock/request_handlers/invoices.rb b/lib/stripe_mock/request_handlers/invoices.rb index 866907658..aa91ba0a0 100644 --- a/lib/stripe_mock/request_handlers/invoices.rb +++ b/lib/stripe_mock/request_handlers/invoices.rb @@ -99,7 +99,12 @@ def upcoming_invoice(route, method_url, params, headers) invoice_lines = [] if prorating - unused_amount = subscription[:plan][:amount] * subscription[:quantity] * (subscription[:current_period_end] - subscription_proration_date.to_i) / (subscription[:current_period_end] - subscription[:current_period_start]) + unused_amount = ( + subscription[:plan][:amount].to_f * + subscription[:quantity] * + (subscription[:current_period_end] - subscription_proration_date.to_i) / (subscription[:current_period_end] - subscription[:current_period_start]) + ).ceil + invoice_lines << Data.mock_line_item( id: new_id('ii'), amount: -unused_amount, diff --git a/lib/stripe_mock/request_handlers/products.rb b/lib/stripe_mock/request_handlers/products.rb index a25835745..a75461c32 100644 --- a/lib/stripe_mock/request_handlers/products.rb +++ b/lib/stripe_mock/request_handlers/products.rb @@ -11,6 +11,7 @@ def self.included(base) def create_product(_route, _method_url, params, _headers) params[:id] ||= new_id('prod') + validate_create_product_params(params) products[params[:id]] = Data.mock_product(params) end diff --git a/lib/stripe_mock/request_handlers/subscriptions.rb b/lib/stripe_mock/request_handlers/subscriptions.rb index 3adee007f..a9fd404ec 100644 --- a/lib/stripe_mock/request_handlers/subscriptions.rb +++ b/lib/stripe_mock/request_handlers/subscriptions.rb @@ -102,7 +102,7 @@ def create_subscription(route, method_url, params, headers) customer[:default_source] = new_card[:id] end - allowed_params = %w(customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days current_period_start created prorate billing_cycle_anchor billing days_until_due idempotency_key) + allowed_params = %w(customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days current_period_start created prorate billing_cycle_anchor billing days_until_due idempotency_key enable_incomplete_payments cancel_at_period_end) unknown_params = params.keys - allowed_params.map(&:to_sym) if unknown_params.length > 0 raise Stripe::InvalidRequestError.new("Received unknown parameter: #{unknown_params.join}", unknown_params.first.to_s, http_status: 400) @@ -133,6 +133,11 @@ def create_subscription(route, method_url, params, headers) end end + if params[:cancel_at_period_end] + subscription[:cancel_at_period_end] = true + subscription[:canceled_at] = Time.now.utc.to_i + end + subscriptions[subscription[:id]] = subscription add_subscription_to_customer(customer, subscription) @@ -191,17 +196,24 @@ def update_subscription(route, method_url, params, headers) raise Stripe::InvalidRequestError.new("No such coupon: #{coupon_id}", 'coupon', http_status: 400) end end - verify_card_present(customer, subscription_plans.first, subscription) - if subscription[:cancel_at_period_end] + if params[:cancel_at_period_end] + subscription[:cancel_at_period_end] = true + subscription[:canceled_at] = Time.now.utc.to_i + elsif params.has_key?(:cancel_at_period_end) subscription[:cancel_at_period_end] = false subscription[:canceled_at] = nil end params[:current_period_start] = subscription[:current_period_start] params[:trial_end] = params[:trial_end] || subscription[:trial_end] + + plan_amount_was = subscription.dig(:plan, :amount) + subscription = resolve_subscription_changes(subscription, subscription_plans, customer, params) + verify_card_present(customer, subscription_plans.first, subscription, params) if plan_amount_was == 0 && subscription.dig(:plan, :amount) && subscription.dig(:plan, :amount) > 0 + # delete the old subscription, replace with the new subscription customer[:subscriptions][:data].reject! { |sub| sub[:id] == subscription[:id] } customer[:subscriptions][:data] << subscription @@ -281,7 +293,7 @@ def verify_card_present(customer, plan, subscription, params={}) return if params[:billing] == 'send_invoice' - raise Stripe::InvalidRequestError.new('You must supply a valid card xoxo', nil, http_status: 400) + raise Stripe::InvalidRequestError.new('This customer has no attached payment source', nil, http_status: 400) end def verify_active_status(subscription) diff --git a/lib/stripe_mock/request_handlers/validators/param_validators.rb b/lib/stripe_mock/request_handlers/validators/param_validators.rb index f6251514c..9bf670cdc 100644 --- a/lib/stripe_mock/request_handlers/validators/param_validators.rb +++ b/lib/stripe_mock/request_handlers/validators/param_validators.rb @@ -2,7 +2,28 @@ module StripeMock module RequestHandlers module ParamValidators - def validate_create_plan_params(params) + def already_exists_message(obj_class) + "#{obj_class.to_s.split("::").last} already exists." + end + + def not_found_message(obj_class, obj_id) + "No such #{obj_class.to_s.split("::").last.downcase}: #{obj_id}" + end + + def missing_param_message(attr_name) + "Missing required param: #{attr_name}." + end + + def invalid_integer_message(my_val) + "Invalid integer: #{my_val}" + end + + # + # ProductValidator + # + + + def validate_create_product_params(params) params[:id] = params[:id].to_s required_product_fields = @base_strategy.create_plan_params[:product].keys @@ -14,25 +35,91 @@ def validate_create_plan_params(params) raise Stripe::InvalidRequestError.new(message, name) if params[:product][name].nil? end - @base_strategy.create_plan_params.keys.each do |name| + @base_strategy.create_product_params.keys.reject{ |k,_| k == :id }.each do |k| + raise Stripe::InvalidRequestError.new(missing_param_message(k), k) if params[k].nil? + end + + if !%w[good service].include?(params[:type]) + raise Stripe::InvalidRequestError.new("Invalid type: must be one of good or service", :type) + end + + if products[ params[:id] ] + raise Stripe::InvalidRequestError.new(already_exists_message(Stripe::Product), :id) + end + end + + # + # PlanValidator + # + + def missing_plan_amount_message + "Plans require an `amount` parameter to be set." + end + + SUPPORTED_PLAN_INTERVALS = ["month", "year", "week", "day"] + + def invalid_plan_interval_message + "Invalid interval: must be one of month, year, week, or day" + end + + SUPPORTED_CURRENCIES = [ + "usd", "aed", "afn", "all", "amd", "ang", "aoa", "ars", "aud", "awg", "azn", "bam", "bbd", "bdt", "bgn", + "bif", "bmd", "bnd", "bob", "brl", "bsd", "bwp", "bzd", "cad", "cdf", "chf", "clp", "cny", "cop", "crc", + "cve", "czk", "djf", "dkk", "dop", "dzd", "egp", "etb", "eur", "fjd", "fkp", "gbp", "gel", "gip", "gmd", + "gnf", "gtq", "gyd", "hkd", "hnl", "hrk", "htg", "huf", "idr", "ils", "inr", "isk", "jmd", "jpy", "kes", + "kgs", "khr", "kmf", "krw", "kyd", "kzt", "lak", "lbp", "lkr", "lrd", "lsl", "mad", "mdl", "mga", "mkd", + "mmk", "mnt", "mop", "mro", "mur", "mvr", "mwk", "mxn", "myr", "mzn", "nad", "ngn", "nio", "nok", "npr", + "nzd", "pab", "pen", "pgk", "php", "pkr", "pln", "pyg", "qar", "ron", "rsd", "rub", "rwf", "sar", "sbd", + "scr", "sek", "sgd", "shp", "sll", "sos", "srd", "std", "szl", "thb", "tjs", "top", "try", "ttd", "twd", + "tzs", "uah", "ugx", "uyu", "uzs", "vnd", "vuv", "wst", "xaf", "xcd", "xof", "xpf", "yer", "zar", "zmw", + "eek", "lvl", "svc", "vef" + ] + + def invalid_currency_message(my_val) + "Invalid currency: #{my_val.downcase}. Stripe currently supports these currencies: #{SUPPORTED_CURRENCIES.join(", ")}" + end + + def validate_create_plan_params(params) + plan_id = params[:id].to_s + product_id = params[:product] + + @base_strategy.create_plan_params.keys.each do |attr_name| message = - if name == :amount - "Plans require an `#{name}` parameter to be set." - elsif name == :product + if attr_name == :amount + "Plans require an `#{attr_name}` parameter to be set." + elsif attr_name == :product "Missing required param: name." else - "Missing required param: #{name}." + "Missing required param: #{attr_name}." end - raise Stripe::InvalidRequestError.new(message, name) if params[name].nil? + raise Stripe::InvalidRequestError.new(message, attr_name) if params[attr_name].nil? end - if plans[ params[:id] ] - raise Stripe::InvalidRequestError.new("Plan already exists.", :id) + if plans[plan_id] + message = already_exists_message(Stripe::Plan) + raise Stripe::InvalidRequestError.new(message, :id) + end + + unless products[product_id] + message = not_found_message(Stripe::Product, product_id) + raise Stripe::InvalidRequestError.new(message, :product) + end + + unless SUPPORTED_PLAN_INTERVALS.include?(params[:interval]) + message = invalid_plan_interval_message + raise Stripe::InvalidRequestError.new(message, :interval) + end + + unless SUPPORTED_CURRENCIES.include?(params[:currency]) + message = invalid_currency_message(params[:currency]) + raise Stripe::InvalidRequestError.new(message, :currency) end unless params[:amount].integer? - raise Stripe::InvalidRequestError.new("Invalid integer: #{params[:amount]}", :amount) + message = invalid_integer_message(params[:amount]) + raise Stripe::InvalidRequestError.new(message, :amount) end + end def require_param(param_name) diff --git a/lib/stripe_mock/test_strategies/base.rb b/lib/stripe_mock/test_strategies/base.rb index 60625a344..1dd36c31d 100644 --- a/lib/stripe_mock/test_strategies/base.rb +++ b/lib/stripe_mock/test_strategies/base.rb @@ -2,19 +2,51 @@ module StripeMock module TestStrategies class Base + def list_products(limit) + Stripe::Product.list(limit: limit) + end + + def create_product(params = {}) + Stripe::Product.create create_product_params(params) + end + + def create_product_params(params={}) + { + :id => 'stripe_mock_default_product_id', + :name => 'Default Product', + :type => 'service' + }.merge(params) + end + + def retrieve_product(product_id) + Stripe::Product.retrieve(product_id) + end + + + def list_plans(limit) + Stripe::Plan.list(limit: limit) + end + + def create_plan(params={}) + Stripe::Plan.create create_plan_params(params) + end + def create_plan_params(params={}) - currency = params[:currency] || StripeMock.default_currency { :id => 'stripe_mock_default_plan_id', - :product => { - :name => 'StripeMock Default Plan ID' - }, - :amount => 1337, - :currency => currency, - :interval => 'month' + :interval => 'month', + :currency => StripeMock.default_currency, + :product => nil, # need to override yourself to pass validations + :amount => 1337 }.merge(params) end + + def list_subscriptions(limit) + Stripe::Subscription.list(limit: limit) + end + + def generate_card_token(card_params={}) card_data = { :number => "4242424242424242", :exp_month => 9, :exp_year => (Time.now.year + 5), :cvc => "999", :tokenization_method => nil } card = StripeMock::Util.card_merge(card_data, card_params) @@ -40,6 +72,7 @@ def generate_bank_token(bank_account_params={}) stripe_token.id end + def create_coupon_params(params = {}) currency = params[:currency] || StripeMock.default_currency { @@ -76,6 +109,7 @@ def delete_all_coupons def prepare_card_error StripeMock.prepare_card_error(:card_error, :new_customer) if StripeMock.state == 'local' end + end end end diff --git a/lib/stripe_mock/test_strategies/live.rb b/lib/stripe_mock/test_strategies/live.rb index a9fe024b7..afe51f03c 100644 --- a/lib/stripe_mock/test_strategies/live.rb +++ b/lib/stripe_mock/test_strategies/live.rb @@ -2,6 +2,21 @@ module StripeMock module TestStrategies class Live < Base + def create_product(params={}) + params = create_product_params(params) + raise "create_product requires an :id" if params[:id].nil? + delete_product(params[:id]) + Stripe::Product.create params + end + + def delete_product(product_id) + product = Stripe::Product.retrieve(product_id) + Stripe::Plan.all(product: product_id).each(&:delete) if product.type == 'service' + product.delete + rescue Stripe::StripeError => e + # do nothing + end + def create_plan(params={}) raise "create_plan requires an :id" if params[:id].nil? delete_plan(params[:id]) @@ -9,12 +24,10 @@ def create_plan(params={}) end def delete_plan(plan_id) - begin - plan = Stripe::Plan.retrieve(plan_id) - plan.delete - rescue Stripe::StripeError => e - # Do nothing; we just want to make sure this plan ceases to exists - end + plan = Stripe::Plan.retrieve(plan_id) + plan.delete + rescue Stripe::StripeError => e + # do nothing end def create_coupon(params={}) @@ -23,12 +36,10 @@ def create_coupon(params={}) end def delete_coupon(id) - begin - coupon = Stripe::Coupon.retrieve(id) - coupon.delete - rescue Stripe::StripeError - # do nothing - end + coupon = Stripe::Coupon.retrieve(id) + coupon.delete + rescue Stripe::StripeError + # do nothing end def upsert_stripe_object(object, attributes) diff --git a/lib/stripe_mock/test_strategies/mock.rb b/lib/stripe_mock/test_strategies/mock.rb index c3af9ada3..4241d7835 100644 --- a/lib/stripe_mock/test_strategies/mock.rb +++ b/lib/stripe_mock/test_strategies/mock.rb @@ -2,8 +2,12 @@ module StripeMock module TestStrategies class Mock < Base - def create_plan(params={}) - Stripe::Plan.create create_plan_params(params) + def delete_product(product_id) + if StripeMock.state == 'remote' + StripeMock.client.destroy_resource('products', product_id) + elsif StripeMock.state == 'local' + StripeMock.instance.products.delete(product_id) + end end def delete_plan(plan_id) diff --git a/lib/stripe_mock/version.rb b/lib/stripe_mock/version.rb index 462006886..b7f5cc30c 100644 --- a/lib/stripe_mock/version.rb +++ b/lib/stripe_mock/version.rb @@ -1,4 +1,4 @@ module StripeMock # stripe-ruby-mock version - VERSION = "2.5.8" + VERSION = "2.6.0" end diff --git a/lib/stripe_mock/webhook_fixtures/product.created.json b/lib/stripe_mock/webhook_fixtures/product.created.json new file mode 100644 index 000000000..5dc5ec97d --- /dev/null +++ b/lib/stripe_mock/webhook_fixtures/product.created.json @@ -0,0 +1,34 @@ +{ + "created": 1326853478, + "livemode": false, + "id": "evt_00000000000000", + "type": "product.created", + "object": "event", + "data": { + "object": { + "id": "prod_00000000000000", + "object": "product", + "active": true, + "attributes": [ + ], + "caption": null, + "created": 1558795883, + "deactivate_on": [ + ], + "description": null, + "images": [ + ], + "livemode": false, + "metadata": { + }, + "name": "Test Product", + "package_dimensions": null, + "shippable": null, + "statement_descriptor": null, + "type": "service", + "unit_label": null, + "updated": 1558795883, + "url": null + } + } +} diff --git a/lib/stripe_mock/webhook_fixtures/product.deleted.json b/lib/stripe_mock/webhook_fixtures/product.deleted.json new file mode 100644 index 000000000..a0499c50b --- /dev/null +++ b/lib/stripe_mock/webhook_fixtures/product.deleted.json @@ -0,0 +1,34 @@ +{ + "created": 1326853478, + "livemode": false, + "id": "evt_00000000000000", + "type": "product.deleted", + "object": "event", + "data": { + "object": { + "id": "prod_00000000000000", + "object": "product", + "active": true, + "attributes": [ + ], + "caption": null, + "created": 1558795883, + "deactivate_on": [ + ], + "description": null, + "images": [ + ], + "livemode": false, + "metadata": { + }, + "name": "Test Product", + "package_dimensions": null, + "shippable": null, + "statement_descriptor": null, + "type": "service", + "unit_label": null, + "updated": 1558795883, + "url": null + } + } +} diff --git a/lib/stripe_mock/webhook_fixtures/product.updated.json b/lib/stripe_mock/webhook_fixtures/product.updated.json new file mode 100644 index 000000000..37c802448 --- /dev/null +++ b/lib/stripe_mock/webhook_fixtures/product.updated.json @@ -0,0 +1,38 @@ +{ + "created": 1326853478, + "livemode": false, + "id": "evt_00000000000000", + "type": "product.updated", + "object": "event", + "data": { + "object": { + "id": "prod_00000000000000", + "object": "product", + "active": true, + "attributes": [ + ], + "caption": null, + "created": 1558795883, + "deactivate_on": [ + ], + "description": null, + "images": [ + ], + "livemode": false, + "metadata": { + }, + "name": "Test Product", + "package_dimensions": null, + "shippable": null, + "statement_descriptor": null, + "type": "service", + "unit_label": null, + "updated": 1558795883, + "url": null + }, + "previous_attributes": { + "name": "Product Test", + "updated": 1558873981 + } + } +} diff --git a/spec/instance_spec.rb b/spec/instance_spec.rb index eed16be82..5c321fc60 100644 --- a/spec/instance_spec.rb +++ b/spec/instance_spec.rb @@ -13,13 +13,13 @@ def test_data_source(type); StripeMock.instance.send(type); end after { StripeMock.stop } it "handles both string and symbol hash keys" do - string_params = stripe_helper.create_plan_params( - "id" => "str_abcde", - :name => "String Plan" + symbol_params = stripe_helper.create_product_params( + :name => "Symbol Product", + "type" => "service" ) - res, api_key = StripeMock.instance.mock_request('post', '/v1/plans', api_key: 'api_key', params: string_params) - expect(res.data[:id]).to eq('str_abcde') - expect(res.data[:name]).to eq('String Plan') + res, api_key = StripeMock.instance.mock_request('post', '/v1/products', api_key: 'api_key', params: symbol_params) + expect(res.data[:name]).to eq('Symbol Product') + expect(res.data[:type]).to eq('service') end it "exits gracefully on an unrecognized handler url" do diff --git a/spec/server_spec.rb b/spec/server_spec.rb index d2fc6f2ab..fb056c9c4 100644 --- a/spec/server_spec.rb +++ b/spec/server_spec.rb @@ -19,6 +19,7 @@ def test_data_source(type); StripeMock.client.get_server_data(type); end after { StripeMock.stop_client(:clear_server_data => true) } + let(:product) { stripe_helper.create_product } it "uses an RPC client for mock requests" do charge = Stripe::Charge.create( @@ -51,7 +52,7 @@ def test_data_source(type); StripeMock.client.get_server_data(type); end it "returns a response with symbolized hash keys" do - stripe_helper.create_plan(id: 'x') + stripe_helper.create_plan(id: 'x', product: product.id) response, api_key = StripeMock.redirect_to_mock_server('get', '/v1/plans/x', api_key: 'xxx') response.data.keys.each {|k| expect(k).to be_a(Symbol) } end diff --git a/spec/shared_stripe_examples/customer_examples.rb b/spec/shared_stripe_examples/customer_examples.rb index d4d5d6e07..e51b1f092 100644 --- a/spec/shared_stripe_examples/customer_examples.rb +++ b/spec/shared_stripe_examples/customer_examples.rb @@ -1,6 +1,8 @@ require 'spec_helper' shared_examples 'Customer API' do + let(:product_params) { {id: "prod_CCC", name: "My Product", type: "service"} } + let(:product) { stripe_helper.create_product(product_params) } def gen_card_tk stripe_helper.generate_card_token @@ -88,7 +90,7 @@ def gen_card_tk end it 'creates a customer with a plan' do - plan = stripe_helper.create_plan(id: 'silver') + plan = stripe_helper.create_plan(id: 'silver', product: product.id) customer = Stripe::Customer.create(id: 'test_cus_plan', source: gen_card_tk, :plan => 'silver') customer = Stripe::Customer.retrieve('test_cus_plan') @@ -101,23 +103,29 @@ def gen_card_tk end it "creates a customer with a plan (string/symbol agnostic)" do - plan = stripe_helper.create_plan(id: 'string_id') - customer = Stripe::Customer.create(id: 'test_cus_plan', source: gen_card_tk, :plan => :string_id) + stripe_helper.create_plan(id: 'silver', product: product.id) - customer = Stripe::Customer.retrieve('test_cus_plan') - expect(customer.subscriptions.first.plan.id).to eq('string_id') - - plan = stripe_helper.create_plan(:id => :sym_id) - customer = Stripe::Customer.create(id: 'test_cus_plan', source: gen_card_tk, :plan => 'sym_id') + Stripe::Customer.create(id: 'cust_SLV1', source: gen_card_tk, :plan => 'silver') + customer = Stripe::Customer.retrieve('cust_SLV1') + expect(customer.subscriptions.count).to eq(1) + expect(customer.subscriptions.data.length).to eq(1) + expect(customer.subscriptions).to_not be_nil + expect(customer.subscriptions.first.plan.id).to eq('silver') + expect(customer.subscriptions.first.customer).to eq(customer.id) - customer = Stripe::Customer.retrieve('test_cus_plan') - expect(customer.subscriptions.first.plan.id).to eq('sym_id') + Stripe::Customer.create(id: 'cust_SLV2', source: gen_card_tk, :plan => :silver) + customer = Stripe::Customer.retrieve('cust_SLV2') + expect(customer.subscriptions.count).to eq(1) + expect(customer.subscriptions.data.length).to eq(1) + expect(customer.subscriptions).to_not be_nil + expect(customer.subscriptions.first.plan.id).to eq('silver') + expect(customer.subscriptions.first.customer).to eq(customer.id) end context "create customer" do it "with a trial when trial_end is set" do - plan = stripe_helper.create_plan(id: 'no_trial', amount: 999) + plan = stripe_helper.create_plan(id: 'no_trial', product: product.id, amount: 999) trial_end = Time.now.utc.to_i + 3600 customer = Stripe::Customer.create(id: 'test_cus_trial_end', source: gen_card_tk, plan: 'no_trial', trial_end: trial_end) @@ -133,7 +141,7 @@ def gen_card_tk end it 'overrides trial period length when trial_end is set' do - plan = stripe_helper.create_plan(id: 'silver', amount: 999, trial_period_days: 14) + plan = stripe_helper.create_plan(id: 'silver', product: product.id, amount: 999, trial_period_days: 14) trial_end = Time.now.utc.to_i + 3600 customer = Stripe::Customer.create(id: 'test_cus_trial_end', source: gen_card_tk, plan: 'silver', trial_end: trial_end) @@ -148,7 +156,7 @@ def gen_card_tk end it 'creates a customer when trial_end is set and no source', live: true do - plan = stripe_helper.create_plan(id: 'silver', amount: 999) + plan = stripe_helper.create_plan(id: 'silver', product: product.id, amount: 999) trial_end = Time.now.utc.to_i + 3600 customer = Stripe::Customer.create(plan: 'silver', trial_end: trial_end) expect(customer.subscriptions.count).to eq(1) @@ -161,7 +169,7 @@ def gen_card_tk end it "returns no trial when trial_end is set to 'now'" do - plan = stripe_helper.create_plan(id: 'silver', amount: 999, trial_period_days: 14) + plan = stripe_helper.create_plan(id: 'silver', product: product.id, amount: 999, trial_period_days: 14) customer = Stripe::Customer.create(id: 'test_cus_trial_end', source: gen_card_tk, plan: 'silver', trial_end: "now") customer = Stripe::Customer.retrieve('test_cus_trial_end') @@ -176,7 +184,7 @@ def gen_card_tk end it "returns an error if trial_end is set to a past time" do - plan = stripe_helper.create_plan(id: 'silver', amount: 999) + plan = stripe_helper.create_plan(id: 'silver', product: product.id, amount: 999) expect { Stripe::Customer.create(id: 'test_cus_trial_end', source: gen_card_tk, plan: 'silver', trial_end: Time.now.utc.to_i - 3600) }.to raise_error {|e| @@ -206,7 +214,7 @@ def gen_card_tk end it 'cannot create a customer with an existing plan, but no card token' do - plan = stripe_helper.create_plan(id: 'p') + plan = stripe_helper.create_plan(id: 'p', product: product.id) expect { customer = Stripe::Customer.create(id: 'test_cus_no_plan', :plan => 'p') }.to raise_error {|e| @@ -235,7 +243,7 @@ def gen_card_tk discount = Stripe::Customer.retrieve(customer.id).discount expect(discount).to_not be_nil expect(discount.coupon).to_not be_nil - expect(discount.end).to be_within(1).of (Time.now.to_datetime >> 12).to_time.to_i + expect(discount.end).to be_within(10).of (DateTime.now >> 12).to_time.to_i end after { Stripe::Coupon.retrieve(coupon.id).delete } after { Stripe::Customer.retrieve(customer.id).delete } @@ -391,7 +399,7 @@ def gen_card_tk end it "still has subscriptions after save when subscriptions unchanged" do - plan = stripe_helper.create_plan(id: 'silver') + plan = stripe_helper.create_plan(id: 'silver', product: product.id) original = Stripe::Customer.create(source: gen_card_tk, plan: 'silver') subscription = original.subscriptions.data.first subscription_id = subscription.id @@ -404,7 +412,7 @@ def gen_card_tk end it "should add a customer to a subscription" do - plan = stripe_helper.create_plan(id: 'silver') + plan = stripe_helper.create_plan(id: 'silver', product: product.id) customer = Stripe::Customer.create(source: gen_card_tk) customer.subscriptions.create(plan: plan.id) @@ -418,7 +426,7 @@ def gen_card_tk end it 'works with the update_subscription method' do - stripe_helper.create_plan(id: 'silver') + stripe_helper.create_plan(id: 'silver', product: product.id) cus = Stripe::Customer.create(source: gen_card_tk) expect { cus.update_subscription(plan: 'silver') diff --git a/spec/shared_stripe_examples/error_mock_examples.rb b/spec/shared_stripe_examples/error_mock_examples.rb index 3dc9d4354..7aecfa811 100644 --- a/spec/shared_stripe_examples/error_mock_examples.rb +++ b/spec/shared_stripe_examples/error_mock_examples.rb @@ -49,7 +49,7 @@ def expect_card_error(code, param) error = Stripe::AuthenticationError.new('Bad Auth', http_status: 499, http_body: 'abody', json_body: 'json abody') StripeMock.prepare_error(error) - expect { stripe_helper.create_plan() }.to raise_error {|e| + expect { stripe_helper.create_plan(id: "test_plan") }.to raise_error {|e| expect(e).to be_a(Stripe::AuthenticationError) expect(e.message).to eq('Bad Auth') diff --git a/spec/shared_stripe_examples/invoice_examples.rb b/spec/shared_stripe_examples/invoice_examples.rb index 79a138012..ec65f48d0 100644 --- a/spec/shared_stripe_examples/invoice_examples.rb +++ b/spec/shared_stripe_examples/invoice_examples.rb @@ -52,7 +52,7 @@ end it "stores all invoices in memory" do - expect(Stripe::Invoice.all.map(&:id).sort).to eq([@invoice.id, @invoice2.id].sort) + expect(Stripe::Invoice.all.map(&:id)).to match_array([@invoice.id, @invoice2.id]) end it "defaults count to 10 invoices" do @@ -109,8 +109,9 @@ context "retrieving upcoming invoice" do let(:customer) { Stripe::Customer.create(source: stripe_helper.generate_card_token) } let(:coupon_amtoff) { stripe_helper.create_coupon(id: '100OFF', currency: 'usd', amount_off: 100_00, duration: 'repeating', duration_in_months: 6) } - let(:coupon_pctoff) { stripe_helper.create_coupon(id: '50%OFF', currency: 'usd', percent_off: 50, amount_off: nil, duration: 'repeating', duration_in_months: 6) } - let(:plan) { stripe_helper.create_plan(id: '50m', amount: 50_00, interval: 'month', product: { name: '50m' }, currency: 'usd') } + let(:coupon_pctoff) { stripe_helper.create_coupon(id: '50OFF', currency: 'usd', percent_off: 50, amount_off: nil, duration: 'repeating', duration_in_months: 6) } + let(:product) { stripe_helper.create_product(id: "prod_123") } + let(:plan) { stripe_helper.create_plan(id: '50m', product: product.id, amount: 50_00, interval: 'month', nickname: '50m', currency: 'usd') } let(:quantity) { 3 } let(:subscription) { Stripe::Subscription.create(plan: plan.id, customer: customer.id, quantity: quantity) } @@ -198,8 +199,8 @@ expect(upcoming.discount).not_to be_nil expect(upcoming.discount.coupon.id).to eq '100OFF' expect(upcoming.discount.customer).to eq customer.id - expect(upcoming.discount.start).to be_within(5).of Time.now.to_i - expect(upcoming.discount.end).to be_within(5).of (Time.now.to_datetime >> 6).to_time.to_i + expect(upcoming.discount.start).to be_within(60).of Time.now.to_i + expect(upcoming.discount.end).to be_within(60).of (Time.now.to_datetime >> 6).to_time.to_i expect(upcoming.amount_due).to eq plan.amount * quantity - 100_00 expect(upcoming.subtotal).to eq(upcoming.lines.data[0].amount) expect(upcoming.total).to eq upcoming.subtotal - 100_00 @@ -211,10 +212,10 @@ # Then expect(upcoming.discount).not_to be_nil - expect(upcoming.discount.coupon.id).to eq '50%OFF' + expect(upcoming.discount.coupon.id).to eq '50OFF' expect(upcoming.discount.customer).to eq customer.id - expect(upcoming.discount.start).to be_within(5).of Time.now.to_i - expect(upcoming.discount.end).to be_within(5).of (Time.now.to_datetime >> 6).to_time.to_i + expect(upcoming.discount.start).to be_within(60).of Time.now.to_i + expect(upcoming.discount.end).to be_within(60).of (Time.now.to_datetime >> 6).to_time.to_i expect(upcoming.amount_due).to eq (plan.amount * quantity) * 0.5 expect(upcoming.subtotal).to eq(upcoming.lines.data[0].amount) expect(upcoming.total).to eq upcoming.subtotal * 0.5 @@ -223,7 +224,7 @@ describe 'proration' do shared_examples 'failing when proration date is outside of the subscription current period' do - it 'fails', live: true do + it 'fails', live: true, skip: 'Stripe does not raise error anymore' do expect { Stripe::Invoice.upcoming( customer: customer.id, subscription: subscription.id, @@ -248,9 +249,9 @@ [false, true].each do |with_trial| describe "prorating a subscription with a new plan, with_trial: #{with_trial}" do - let(:new_monthly_plan) { stripe_helper.create_plan(id: '100m', amount: 100_00, interval: 'month', product: { name: '100m' }, currency: 'usd') } - let(:new_yearly_plan) { stripe_helper.create_plan(id: '100y', amount: 100_00, interval: 'year', product: { name: '100y' }, currency: 'usd') } - let(:plan) { stripe_helper.create_plan(id: '50m', amount: 50_00, interval: 'month', product: { name: '50m' }, currency: 'usd') } + let(:new_monthly_plan) { stripe_helper.create_plan(id: '100m', product: product.id, amount: 100_00, interval: 'month', nickname: '100m', currency: 'usd') } + let(:new_yearly_plan) { stripe_helper.create_plan(id: '100y', product: product.id, amount: 100_00, interval: 'year', nickname: '100y', currency: 'usd') } + let(:plan) { stripe_helper.create_plan(id: '50m', product: product.id, amount: 50_00, interval: 'month', nickname: '50m', currency: 'usd') } it 'prorates while maintaining billing interval', live: true do # Given @@ -271,18 +272,17 @@ # Then expect(upcoming).to be_a Stripe::Invoice expect(upcoming.customer).to eq(customer.id) - if with_trial - expect(upcoming.amount_due).to be_within(1).of 0 - else - expect(upcoming.amount_due).to be_within(1).of prorated_amount_due - credit_balance - end expect(upcoming.starting_balance).to eq -credit_balance expect(upcoming.subscription).to eq(subscription.id) if with_trial + expect(upcoming.amount_due).to be_within(1).of 0 expect(upcoming.lines.data.length).to eq(2) + expect(upcoming.ending_balance).to be_within(50).of -13540 else + expect(upcoming.amount_due).to be_within(1).of prorated_amount_due - credit_balance expect(upcoming.lines.data.length).to eq(3) + expect(upcoming.ending_balance).to eq 0 end expect(upcoming.lines.data[0].proration).to be_truthy @@ -307,7 +307,7 @@ # Given proration_date = Time.now + 5 * 24 * 3600 # 5 days later new_quantity = 2 - unused_amount = plan.amount * quantity * (subscription.current_period_end - proration_date.to_i) / (subscription.current_period_end - subscription.current_period_start) + unused_amount = (plan.amount.to_f * quantity * (subscription.current_period_end - proration_date.to_i) / (subscription.current_period_end - subscription.current_period_start)).round prorated_amount_due = new_yearly_plan.amount * new_quantity - unused_amount credit_balance = 1000 customer.account_balance = -credit_balance @@ -322,16 +322,18 @@ expect(upcoming).to be_a Stripe::Invoice expect(upcoming.customer).to eq(customer.id) if with_trial + expect(upcoming.ending_balance).to be_within(50).of -13540 expect(upcoming.amount_due).to eq 0 else - expect(upcoming.amount_due).to be_within(1).of prorated_amount_due - credit_balance + expect(upcoming.ending_balance).to eq 0 + expect(upcoming.amount_due).to eq prorated_amount_due - credit_balance end expect(upcoming.starting_balance).to eq -credit_balance expect(upcoming.subscription).to eq(subscription.id) expect(upcoming.lines.data[0].proration).to be_truthy expect(upcoming.lines.data[0].plan.id).to eq '50m' - expect(upcoming.lines.data[0].amount).to be_within(1).of -unused_amount + expect(upcoming.lines.data[0].amount).to eq -unused_amount expect(upcoming.lines.data[0].quantity).to eq quantity expect(upcoming.lines.data[1].proration).to be_falsey @@ -349,7 +351,7 @@ it 'generates a preview without performing an actual proration', live: true do expect(preview.subtotal).to eq 150_00 # this is a future invoice (generted at the end of the current subscription cycle), rather than a proration invoice - expect(preview.created).to be_within(1).of subscription.current_period_end + expect(preview.due_date).to be_nil expect(preview.period_start).to eq subscription.current_period_start expect(preview.period_end).to eq subscription.current_period_end expect(preview.lines.count).to eq 1 @@ -391,7 +393,7 @@ end it 'sets the start and end of billing periods correctly when plan has an interval_count' do - @oddplan = stripe_helper.create_plan(interval: "week", interval_count: 11) + @oddplan = stripe_helper.create_plan(product: product.id, interval: "week", interval_count: 11, id: "weekly_pl") @subscription = Stripe::Subscription.create(plan: @oddplan.id, customer: customer.id) @upcoming = Stripe::Invoice.upcoming(customer: customer.id) @@ -402,9 +404,9 @@ end it 'chooses the most recent of multiple subscriptions' do - @shortplan = stripe_helper.create_plan(id: 'a', interval: "week") # 1 week sub - @plainplan = stripe_helper.create_plan(id: 'b') # 1 month sub - @longplan = stripe_helper.create_plan(id: 'c', interval: "year") # 1 year sub + @shortplan = stripe_helper.create_plan(id: 'a', product: product.id, interval: "week") # 1 week sub + @plainplan = stripe_helper.create_plan(id: 'b', product: product.id, interval: "month") # 1 month sub + @longplan = stripe_helper.create_plan(id: 'c', product: product.id, interval: "year") # 1 year sub @plainsub = Stripe::Subscription.create(plan: @plainplan.id, customer: customer.id) @shortsub = Stripe::Subscription.create(plan: @shortplan.id, customer: customer.id) @@ -436,7 +438,7 @@ end it 'returns all line items for upcoming invoice' do - plan = stripe_helper.create_plan() + plan = stripe_helper.create_plan(product: product.id, id: "silver_pl") subscription = Stripe::Subscription.create(plan: plan.id, customer: customer.id) upcoming = Stripe::Invoice.upcoming(customer: customer.id) line_items = upcoming.lines @@ -452,7 +454,7 @@ context 'calculates month and year offsets correctly' do it 'for one month plan on the 1st' do - @plan = stripe_helper.create_plan() + @plan = stripe_helper.create_plan(product: product.id, id: "one_mo_plan") @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2014,1,1,12).to_i) @upcoming = Stripe::Invoice.upcoming(customer: customer.id) @@ -463,7 +465,7 @@ end it 'for one year plan on the 1st' do - @plan = stripe_helper.create_plan(interval: "year") + @plan = stripe_helper.create_plan(interval: "year", product: product.id, id: "year_plan") @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2012,1,1,12).to_i) @upcoming = Stripe::Invoice.upcoming(customer: customer.id) @@ -474,7 +476,7 @@ end it 'for one month plan on the 31st' do - @plan = stripe_helper.create_plan() + @plan = stripe_helper.create_plan(product: product.id, id: "one_mo_plan") @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2014,1,31,12).to_i) @upcoming = Stripe::Invoice.upcoming(customer: customer.id) @@ -485,7 +487,7 @@ end it 'for one year plan on feb. 29th' do - @plan = stripe_helper.create_plan(interval: "year") + @plan = stripe_helper.create_plan(product: product.id, interval: "year", id: "year_plan") @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2012,2,29,12).to_i) @upcoming = Stripe::Invoice.upcoming(customer: customer.id) @@ -496,7 +498,7 @@ end it 'for two month plan on dec. 31st' do - @plan = stripe_helper.create_plan(interval_count: 2) + @plan = stripe_helper.create_plan(product: product.id, interval_count: 2, id: 'two_mo_plan') @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2013,12,31,12).to_i) @upcoming = Stripe::Invoice.upcoming(customer: customer.id) @@ -507,7 +509,7 @@ end it 'for three month plan on nov. 30th' do - @plan = stripe_helper.create_plan(interval_count: 3) + @plan = stripe_helper.create_plan(product: product.id, interval_count: 3) @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2013,11,30,12).to_i) @upcoming = Stripe::Invoice.upcoming(customer: customer.id) diff --git a/spec/shared_stripe_examples/plan_examples.rb b/spec/shared_stripe_examples/plan_examples.rb index 1993dbb1e..7a549b53f 100644 --- a/spec/shared_stripe_examples/plan_examples.rb +++ b/spec/shared_stripe_examples/plan_examples.rb @@ -1,89 +1,73 @@ require 'spec_helper' shared_examples 'Plan API' do + let(:product) { stripe_helper.create_product } + let(:product_id) { product.id } + + let(:plan_attributes) { { + :id => "plan_abc123", + :product => product_id, + :nickname => "My Mock Plan", + :amount => 9900, + :currency => "usd", + :interval => "month" + } } + let(:plan) { Stripe::Plan.create(plan_attributes) } + + let(:plan_attributes_without_id){ plan_attributes.merge(id: nil) } + let(:plan_without_id){ Stripe::Plan.create(plan_attributes_without_id) } + + let(:plan_attributes_with_trial) { plan_attributes.merge(id: "prod_TRIAL", :trial_period_days => 30) } + let(:plan_with_trial) { Stripe::Plan.create(plan_attributes_with_trial) } + + let(:metadata) { {:description => "desc text", :info => "info text"} } + let(:plan_attributes_with_metadata) { plan_attributes.merge(id: "prod_META", metadata: metadata) } + let(:plan_with_metadata) { Stripe::Plan.create(plan_attributes_with_metadata) } + + before(:each) do + product + end it "creates a stripe plan" do - plan = Stripe::Plan.create( - :id => 'pid_1', - :amount => 9900, - :currency => 'USD', - :interval => 1, - :product => { - :name => 'A product' - }, - :metadata => { - :description => "desc text", - :info => "info text" - }, - :trial_period_days => 30 - ) - - expect(plan.id).to eq('pid_1') - expect(plan.product.name).to eq('A product') + expect(plan.id).to eq('plan_abc123') + expect(plan.nickname).to eq('My Mock Plan') expect(plan.amount).to eq(9900) - expect(plan.currency).to eq('USD') - expect(plan.interval).to eq(1) + expect(plan.currency).to eq('usd') + expect(plan.interval).to eq("month") - expect(plan.metadata.description).to eq('desc text') - expect(plan.metadata.info).to eq('info text') + expect(plan_with_metadata.metadata.description).to eq('desc text') + expect(plan_with_metadata.metadata.info).to eq('info text') - expect(plan.trial_period_days).to eq(30) + expect(plan_with_trial.trial_period_days).to eq(30) end - it "creates a stripe plan without specifying ID" do - plan = Stripe::Plan.create( - :amount => 9900, - :currency => 'USD', - :interval => 1, - :product => { - :name => 'A product' - } - ) - - expect(plan.id).to match(/^test_plan/) + expect(plan_attributes_without_id[:id]).to be_nil + expect(plan_without_id.id).to match(/^test_plan_1/) end it "stores a created stripe plan in memory" do - plan = Stripe::Plan.create( - :id => 'pid_2', - :amount => 1100, - :currency => 'USD', - :interval => 1, - :product => { - :name => 'A product' - } - ) - plan2 = Stripe::Plan.create( - :id => 'pid_3', - :amount => 7777, - :currency => 'USD', - :interval => 1, - :product => { - :name => 'A product' - } - ) + plan + plan2 = Stripe::Plan.create(plan_attributes.merge(id: "plan_def456", amount: 299)) + data = test_data_source(:plans) expect(data[plan.id]).to_not be_nil - expect(data[plan.id][:amount]).to eq(1100) - + expect(data[plan.id][:amount]).to eq(9900) expect(data[plan2.id]).to_not be_nil - expect(data[plan2.id][:amount]).to eq(7777) + expect(data[plan2.id][:amount]).to eq(299) end - it "retrieves a stripe plan" do - original = stripe_helper.create_plan(amount: 1331) + original = stripe_helper.create_plan(product: product_id, amount: 1331, id: 'plan_943843') plan = Stripe::Plan.retrieve(original.id) expect(plan.id).to eq(original.id) expect(plan.amount).to eq(original.amount) end - it "updates a stripe plan" do - stripe_helper.create_plan(id: 'super_member', amount: 111) + stripe_helper.create_plan(id: 'super_member', product: product_id, amount: 111) plan = Stripe::Plan.retrieve('super_member') expect(plan.amount).to eq(111) @@ -94,7 +78,6 @@ expect(plan.amount).to eq(789) end - it "cannot retrieve a stripe plan that doesn't exist" do expect { Stripe::Plan.retrieve('nope') }.to raise_error {|e| expect(e).to be_a Stripe::InvalidRequestError @@ -104,7 +87,7 @@ end it "deletes a stripe plan" do - stripe_helper.create_plan(id: 'super_member', amount: 111) + stripe_helper.create_plan(id: 'super_member', product: product_id, amount: 111) plan = Stripe::Plan.retrieve('super_member') expect(plan).to_not be_nil @@ -119,8 +102,8 @@ end it "retrieves all plans" do - stripe_helper.create_plan(id: 'Plan One', amount: 54321) - stripe_helper.create_plan(id: 'Plan Two', amount: 98765) + stripe_helper.create_plan(id: 'Plan One', product: product_id, amount: 54321) + stripe_helper.create_plan(id: 'Plan Two', product: product_id, amount: 98765) all = Stripe::Plan.all expect(all.count).to eq(2) @@ -130,32 +113,31 @@ it 'retrieves plans with limit' do 101.times do | i| - stripe_helper.create_plan(id: "Plan #{i}", amount: 11) + stripe_helper.create_plan(id: "Plan #{i}", product: product_id, amount: 11) end all = Stripe::Plan.all(limit: 100) expect(all.count).to eq(100) end - it 'validates the amount' do - expect { - Stripe::Plan.create( - :id => 'pid_1', - :amount => 99.99, - :currency => 'USD', - :interval => 'month', - :product => { - :name => 'A product' - } - ) - }.to raise_error(Stripe::InvalidRequestError, "Invalid integer: 99.99") - end - - describe "Validation", :live => true do - let(:params) { stripe_helper.create_plan_params } + describe "Validations", :live => true do + include_context "stripe validator" + let(:params) { stripe_helper.create_plan_params(product: product_id) } let(:subject) { Stripe::Plan.create(params) } - describe "Required Parameters" do + describe "Associations" do + let(:not_found_product_id){ "prod_NONEXIST" } + let(:not_found_message) { stripe_validator.not_found_message(Stripe::Product, not_found_product_id) } + let(:params) { stripe_helper.create_plan_params(product: not_found_product_id) } + let(:products) { stripe_helper.list_products(100).data } + + it "validates associated product" do + expect(products.map(&:id)).to_not include(not_found_product_id) + expect { subject }.to raise_error(Stripe::InvalidRequestError, not_found_message) + end + end + + describe "Presence" do after do params.delete(@name) message = @@ -167,16 +149,49 @@ expect { subject }.to raise_error(Stripe::InvalidRequestError, message) end - it("requires a product name") { - @name = :name - params[:product].delete(@name) - } - it("requires an amount") { @name = :amount } - it("requires a currency") { @name = :currency } - it("requires an interval") { @name = :interval } + it("validates presence of interval") { @name = :interval } + it("validates presence of currency") { @name = :currency } + it("validates presence of product") { @name = :product } + it("validates presence of amount") { @name = :amount } + end + + describe "Inclusion" do + let(:invalid_interval) { "OOPS" } + let(:invalid_interval_message) { stripe_validator.invalid_plan_interval_message } + let(:invalid_interval_params) { params.merge({interval: invalid_interval}) } + let(:plan_with_invalid_interval) { Stripe::Plan.create(invalid_interval_params) } + + before(:each) do + product + end + + it "validates inclusion of interval" do + expect { plan_with_invalid_interval }.to raise_error(Stripe::InvalidRequestError, invalid_interval_message) + end + + let(:invalid_currency) { "OOPS" } + let(:invalid_currency_message) { stripe_validator.invalid_currency_message(invalid_currency) } + let(:invalid_currency_params) { params.merge({currency: invalid_currency}) } + let(:plan_with_invalid_currency) { Stripe::Plan.create(invalid_currency_params) } + + it "validates inclusion of currency" do + expect { plan_with_invalid_currency }.to raise_error(Stripe::InvalidRequestError, invalid_currency_message) + end + end + + describe "Numericality" do + let(:invalid_integer) { 99.99 } + let(:invalid_integer_message) { stripe_validator.invalid_integer_message(invalid_integer)} + + it 'validates amount is an integer' do + expect { + Stripe::Plan.create( plan_attributes.merge({amount: invalid_integer}) ) + }.to raise_error(Stripe::InvalidRequestError, invalid_integer_message) + end end describe "Uniqueness" do + let(:already_exists_message) { stripe_validator.already_exists_message(Stripe::Plan) } it "validates for uniqueness" do stripe_helper.delete_plan(params[:id]) @@ -184,9 +199,39 @@ Stripe::Plan.create(params) expect { Stripe::Plan.create(params) - }.to raise_error(Stripe::InvalidRequestError, "Plan already exists.") + }.to raise_error(Stripe::InvalidRequestError, already_exists_message) end end + + end + + describe "Mock Data" do + let(:mock_object) { StripeMock::Data.mock_plan } + let(:known_attributes) { [ + :id, + :object, + :active, + :aggregate_usage, + :amount, + :billing_scheme, + :created, + :currency, + :interval, + :interval_count, + :livemode, + :metadata, + :nickname, + :product, + :tiers, + :tiers_mode, + :transform_usage, + :trial_period_days, + :usage_type + ] } + + it "includes all retreived attributes" do + expect(mock_object.keys).to eql(known_attributes) + end end end diff --git a/spec/shared_stripe_examples/product_example.rb b/spec/shared_stripe_examples/product_example.rb deleted file mode 100644 index 0b0fbcb3e..000000000 --- a/spec/shared_stripe_examples/product_example.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'spec_helper' - -shared_examples 'Product API' do - it 'creates a product' do - product = Stripe::Product.create( - name: 'my awesome product', - type: 'service' - ) - - expect(product.name).to eq 'my awesome product' - expect(product.type).to eq 'service' - end - - it 'retrieves a product' do - Stripe::Product.create( - id: 'test_prod_1', - name: 'my awesome product', - type: 'service' - ) - - product = Stripe::Product.retrieve('test_prod_1') - - expect(product.name).to eq 'my awesome product' - expect(product.type).to eq 'service' - end - - it 'updates a product' do - Stripe::Product.create( - id: 'test_prod_1', - name: 'my awesome product', - type: 'service' - ) - - Stripe::Product.update('test_prod_1', name: 'my lame product') - - product = Stripe::Product.retrieve('test_prod_1') - - expect(product.name).to eq 'my lame product' - end - - it 'lists all products' do - 2.times do |n| - Stripe::Product.create( - name: "product #{n}", - type: 'service' - ) - end - - products = Stripe::Product.list - - expect(products.map(&:name)).to match_array ['product 0', 'product 1'] - end - - it 'destroys a product', live: true do - Stripe::Product.create( - id: 'test_prod_1', - name: 'my awesome product', - type: 'service' - ) - - Stripe::Product.delete('test_prod_1') - - expect { Stripe::Product.retrieve('test_prod_1') }. to raise_error(Stripe::InvalidRequestError) - end -end diff --git a/spec/shared_stripe_examples/product_examples.rb b/spec/shared_stripe_examples/product_examples.rb new file mode 100644 index 000000000..ef27e723b --- /dev/null +++ b/spec/shared_stripe_examples/product_examples.rb @@ -0,0 +1,156 @@ +require "spec_helper" + +shared_examples "Product API" do + let(:product_attributes) { {id: "prod_123", name: "My Mock Product", type: "service"} } + let(:product) { Stripe::Product.create(product_attributes) } + + it "creates a stripe product" do + expect(product.id).to eq("prod_123") + expect(product.name).to eq("My Mock Product") + expect(product.type).to eq("service") + end + + it "stores a created stripe product in memory" do + product = Stripe::Product.create(product_attributes) + product2 = Stripe::Product.create(product_attributes.merge({id: "prod_456", name: "My Other Product"})) + + data = test_data_source(:products) + expect(data[product.id]).to_not be_nil + expect(data[product.id][:id]).to eq("prod_123") + expect(data[product.id][:name]).to eq("My Mock Product") + expect(data[product2.id]).to_not be_nil + expect(data[product2.id][:id]).to eq("prod_456") + expect(data[product2.id][:name]).to eq("My Other Product") + end + + it "retrieves a stripe product" do + original = stripe_helper.create_product(product_attributes) + product = Stripe::Product.retrieve(original.id) + + expect(product.id).to eq(original.id) + expect(product.name).to eq(original.name) + end + + it "updates a stripe product" do + stripe_helper.create_product(id: "prod_XYZ", name: "Future Product") + + product = Stripe::Product.retrieve("prod_XYZ") + expect(product.name).to eq("Future Product") + + product.name = "Updated Product" + product.save + product = Stripe::Product.retrieve("prod_XYZ") + expect(product.name).to eq("Updated Product") + end + + it "cannot retrieve a stripe product that doesn't exist" do + expect { Stripe::Product.retrieve('nope') }.to raise_error {|e| + expect(e).to be_a Stripe::InvalidRequestError + expect(e.param).to eq("product") + expect(e.http_status).to eq(404) + } + end + + it "deletes a stripe product" do + stripe_helper.create_product(id: "prod_DEL", name: "Aging Product") + + product = Stripe::Product.retrieve("prod_DEL") + expect(product).to_not be_nil + + product.delete + + expect { Stripe::Product.retrieve("prod_DEL") }.to raise_error {|e| + expect(e).to be_a Stripe::InvalidRequestError + expect(e.param).to eq("product") + expect(e.http_status).to eq(404) + } + end + + it "retrieves all products" do + stripe_helper.create_product(id: "prod_123", name: "First Product") + stripe_helper.create_product(id: "prod_456", name: "Second Product") + + all = Stripe::Product.all + expect(all.count).to eq(2) + expect(all.map &:id).to include("prod_123", "prod_456") + expect(all.map &:name).to include("First Product", "Second Product") + end + + it 'retrieves products with limit' do + 101.times do |i| + stripe_helper.create_product(id: "Product #{i}", name: "My Product ##{i}") + end + all = Stripe::Product.all(limit: 100) + + expect(all.count).to eq(100) + end + + describe "Validation", :live => true do + include_context "stripe validator" + let(:params) { stripe_helper.create_product_params } + let(:subject) { Stripe::Product.create(params) } + before { stripe_helper.delete_product(params[:id]) } + + describe "Required Parameters" do + after do + params.delete(@attribute_name) + message = stripe_validator.missing_param_message(@attribute_name) + expect { subject }.to raise_error(Stripe::InvalidRequestError, message) + end + + it("requires a name") { @attribute_name = :name } + it("requires a type") { @attribute_name = :type } + end + + describe "Inclusion" do + it "validates inclusion of type in 'good' or 'service'" do + expect { + Stripe::Product.create(params.merge({type: "OOPS"})) + }.to raise_error(Stripe::InvalidRequestError, "Invalid type: must be one of good or service") + end + end + + describe "Uniqueness" do + let(:already_exists_message){ stripe_validator.already_exists_message(Stripe::Product) } + + it "validates uniqueness of identifier" do + stripe_helper.delete_product(params[:id]) + + Stripe::Product.create(params) + expect { + Stripe::Product.create(params) + }.to raise_error(Stripe::InvalidRequestError, already_exists_message) + end + end + end + + describe "Mock Data" do + let(:mock_object) { StripeMock::Data.mock_product } + let(:known_attributes) { [ + :id, + :object, + :active, + :attributes, + :caption, + :created, + :deactivate_on, + :description, + :images, + :livemode, + :metadata, + :name, + :package_dimensions, + :shippable, + :statement_descriptor, + :type, + :unit_label, + :updated, + :url + ] } + + it "includes all retreived attributes" do + expect(mock_object.keys).to eql(known_attributes) + end + end + +end diff --git a/spec/shared_stripe_examples/subscription_examples.rb b/spec/shared_stripe_examples/subscription_examples.rb index bfd2c8296..9d3da3d88 100644 --- a/spec/shared_stripe_examples/subscription_examples.rb +++ b/spec/shared_stripe_examples/subscription_examples.rb @@ -1,36 +1,45 @@ require 'spec_helper' +require 'securerandom' shared_examples 'Customer Subscriptions' do + let(:gen_card_tk) { stripe_helper.generate_card_token } - def gen_card_tk - stripe_helper.generate_card_token - end + let(:product) { stripe_helper.create_product } + let(:plan_attrs) { {id: 'silver', product: product.id, amount: 4999, currency: 'usd'} } + let(:plan) { stripe_helper.create_plan(plan_attrs) } + + let(:plan_with_trial_attrs) { {id: 'trial', product: product.id, amount: 999, trial_period_days: 14 } } + let(:plan_with_trial) { stripe_helper.create_plan(plan_with_trial_attrs) } + + let(:free_plan) { stripe_helper.create_plan(id: 'free', product: product.id, amount: 0) } context "creating a new subscription" do it "adds a new subscription to customer with none using items", :live => true do - plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' }, - amount: 4999, currency: 'usd') + plan customer = Stripe::Customer.create(source: gen_card_tk) expect(customer.subscriptions.data).to be_empty expect(customer.subscriptions.count).to eq(0) - sub = Stripe::Subscription.create({ items: [{ plan: 'silver' }], - customer: customer.id, metadata: { foo: "bar", example: "yes" } }) + subscription = Stripe::Subscription.create({ + customer: customer.id, + items: [{ plan: 'silver' }], + metadata: { foo: "bar", example: "yes" } + }) - expect(sub.object).to eq('subscription') - expect(sub.plan.to_hash).to eq(plan.to_hash) - expect(sub.metadata.foo).to eq( "bar" ) - expect(sub.metadata.example).to eq( "yes" ) + expect(subscription.object).to eq('subscription') + expect(subscription.plan.to_hash).to eq(plan.to_hash) + expect(subscription.metadata.foo).to eq("bar") + expect(subscription.metadata.example).to eq("yes") customer = Stripe::Customer.retrieve(customer.id) expect(customer.subscriptions.data).to_not be_empty expect(customer.subscriptions.count).to eq(1) expect(customer.subscriptions.data.length).to eq(1) expect(customer.charges.data.length).to eq(1) - expect(customer.currency).to eq( "usd" ) + expect(customer.currency).to eq("usd") - expect(customer.subscriptions.data.first.id).to eq(sub.id) + expect(customer.subscriptions.data.first.id).to eq(subscription.id) expect(customer.subscriptions.data.first.plan.to_hash).to eq(plan.to_hash) expect(customer.subscriptions.data.first.customer).to eq(customer.id) expect(customer.subscriptions.data.first.metadata.foo).to eq( "bar" ) @@ -38,8 +47,7 @@ def gen_card_tk end it "adds a new subscription to customer with none", :live => true do - plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' }, - amount: 4999, currency: 'usd') + plan customer = Stripe::Customer.create(source: gen_card_tk) expect(customer.subscriptions.data).to be_empty @@ -68,7 +76,7 @@ def gen_card_tk end it 'when customer object provided' do - plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' }, amount: 4999, currency: 'usd') + plan customer = Stripe::Customer.create(source: gen_card_tk) expect(customer.subscriptions.data).to be_empty @@ -102,27 +110,16 @@ def gen_card_tk customer = Stripe::Customer.create(source: gen_card_tk) expect(customer.subscriptions.count).to eq(0) - plan = stripe_helper.create_plan(id: :silver, product: { name: 'Silver Plan' }, - amount: 4999, currency: 'usd') - sub = Stripe::Subscription.create({ plan: 'silver', customer: customer.id }) + plan + sub = Stripe::Subscription.create({plan: plan.id, customer: customer.id }) customer = Stripe::Customer.retrieve(customer.id) expect(sub.plan.to_hash).to eq(plan.to_hash) expect(customer.subscriptions.count).to eq(1) - - plan = stripe_helper.create_plan(id: 'gold', product: { name: 'Gold Plan' }, - amount: 14999, currency: 'usd') - sub = Stripe::Subscription.create({ plan: 'gold', customer: customer.id }) - customer = Stripe::Customer.retrieve(customer.id) - expect(sub.plan.to_hash).to eq(plan.to_hash) - expect(customer.subscriptions.count).to eq(2) end it 'creates a charge for the customer', live: true do - stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' }, - amount: 4999) - customer = Stripe::Customer.create(source: gen_card_tk) - Stripe::Subscription.create({ plan: 'silver', customer: customer.id, metadata: { foo: "bar", example: "yes" } }) + Stripe::Subscription.create({ plan: plan.id, customer: customer.id, metadata: { foo: "bar", example: "yes" } }) customer = Stripe::Customer.retrieve(customer.id) expect(customer.charges.data.length).to eq(1) @@ -130,8 +127,6 @@ def gen_card_tk end it 'contains coupon object', live: true do - plan = stripe_helper.create_plan(id: 'plan_with_coupon', product: { name: 'One More Test Plan' }, - amount: 777) coupon = stripe_helper.create_coupon(id: 'free_coupon', duration: 'repeating', duration_in_months: 3) customer = Stripe::Customer.create(source: gen_card_tk) Stripe::Subscription.create(plan: plan.id, customer: customer.id, coupon: coupon.id) @@ -145,32 +140,27 @@ def gen_card_tk end it 'when coupon is not exist', live: true do - plan = stripe_helper.create_plan(id: 'plan_with_coupon', product: { name: 'One More Test Plan' }, - amount: 777) customer = Stripe::Customer.create(source: gen_card_tk) - expect { Stripe::Subscription.create(plan: plan.id, customer: customer.id, coupon: 'none') }.to raise_error {|e| - expect(e).to be_a Stripe::InvalidRequestError - expect(e.http_status).to eq(400) - expect(e.message).to eq('No such coupon: none') - } + expect { + Stripe::Subscription.create(plan: plan.id, customer: customer.id, coupon: 'none') + }.to raise_error {|e| + expect(e).to be_a Stripe::InvalidRequestError + expect(e.http_status).to eq(400) + expect(e.message).to eq('No such coupon: none') + } end it "correctly sets quantity, application_fee_percent and tax_percent" do - Stripe::Plan.create( - :amount => 2500, - :interval => 'month', - :product => { - :name => 'Test plan' - }, - :currency => 'usd', - :id => 'silver', - :statement_description => "testPlan" - ) customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk) subscription = Stripe::Subscription.create({ - plan: "silver", customer: customer.id, quantity: 2, application_fee_percent: 10, tax_percent: 20}) + plan: plan.id, + customer: customer.id, + quantity: 2, + application_fee_percent: 10, + tax_percent: 20 + }) expect(subscription.quantity).to eq(2) expect(subscription.application_fee_percent).to eq(10) expect(subscription.tax_percent).to eq(20) @@ -178,26 +168,22 @@ def gen_card_tk it "correctly sets created when it's not provided as a parameter", live: true do customer = Stripe::Customer.create(source: gen_card_tk) - plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' }, - amount: 4999, currency: 'usd') - subscription = Stripe::Subscription.create({ plan: 'silver', customer: customer.id }) + subscription = Stripe::Subscription.create({ plan: plan.id, customer: customer.id }) expect(subscription.created).to eq(subscription.current_period_start) end it "correctly sets created when it's provided as a parameter" do customer = Stripe::Customer.create(source: gen_card_tk) - plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' }, - amount: 4999, currency: 'usd') - subscription = Stripe::Subscription.create({ plan: 'silver', customer: customer.id, created: 1473576318 }) + subscription = Stripe::Subscription.create({ plan: plan.id, customer: customer.id, created: 1473576318 }) expect(subscription.created).to eq(1473576318) end it "adds additional subscription to customer with existing subscription" do - silver = stripe_helper.create_plan(id: 'silver') - gold = stripe_helper.create_plan(id: 'gold') - customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: 'gold') + silver = stripe_helper.create_plan(id: 'silver', product: product.id) + gold = stripe_helper.create_plan(id: 'gold', product: product.id) + customer = Stripe::Customer.create(id: 'test_customer_sub', product: product.id, source: gen_card_tk, plan: 'gold') sub = Stripe::Subscription.create({ plan: 'silver', customer: customer.id }) @@ -218,7 +204,7 @@ def gen_card_tk end it "subscribes a cardless customer when specifing a card token" do - plan = stripe_helper.create_plan(id: 'enterprise', amount: 499) + plan = stripe_helper.create_plan(id: 'enterprise', product: product.id, amount: 499) customer = Stripe::Customer.create(id: 'cardless') sub = Stripe::Subscription.create(plan: 'enterprise', customer: customer.id, source: gen_card_tk) @@ -247,10 +233,10 @@ def gen_card_tk end it "throws an error when subscribing a customer with no card" do - plan = stripe_helper.create_plan(id: 'enterprise', amount: 499) + plan = stripe_helper.create_plan(id: 'enterprise', product: product.id, amount: 499) customer = Stripe::Customer.create(id: 'cardless') - expect { Stripe::Subscription.create({ plan: 'enterprise', customer: customer.id }) }.to raise_error {|e| + expect { Stripe::Subscription.create({ plan: plan.id, customer: customer.id }) }.to raise_error {|e| expect(e).to be_a Stripe::InvalidRequestError expect(e.http_status).to eq(400) expect(e.message).to_not be_nil @@ -261,12 +247,14 @@ def gen_card_tk end it "throws an error when subscribing the customer to a second plan in a different currency" do - usd_plan = stripe_helper.create_plan(id: 'enterprise_usd', amount: 499, currency: 'usd') customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk) - usd_subscription = Stripe::Subscription.create({ plan: 'enterprise_usd', customer: customer.id }) - eur_plan = stripe_helper.create_plan(id: 'enterprise_eur', amount: 499, currency: 'eur') - expect { Stripe::Subscription.create({ plan: 'enterprise_eur', customer: customer.id }) }.to raise_error {|e| + expect(plan.currency).to eql("usd") + usd_subscription = Stripe::Subscription.create({ plan: plan.id, customer: customer.id }) + + eur_plan = stripe_helper.create_plan(plan_attrs.merge(id: "plan_EURO", currency: 'eur')) + expect(eur_plan.currency).to eql("eur") + expect { Stripe::Subscription.create({ plan: eur_plan.id, customer: customer.id }) }.to raise_error {|e| expect(e).to be_a Stripe::InvalidRequestError expect(e.http_status).to eq(400) expect(e.message).to_not be_nil @@ -274,7 +262,7 @@ def gen_card_tk end it 'when attempting to create a new subscription with the params trial', live: true do - plan = stripe_helper.create_plan(id: 'trial', amount: 999) + plan = stripe_helper.create_plan(id: 'trial', product: product.id, amount: 999) customer = Stripe::Customer.create(source: gen_card_tk) expect{ Stripe::Subscription.create(plan: plan.id, customer: customer.id, trial: 10) }.to raise_error {|e| @@ -286,13 +274,11 @@ def gen_card_tk end it "subscribes a customer with no card to a plan with a free trial" do - plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) customer = Stripe::Customer.create(id: 'cardless') - - sub = Stripe::Subscription.create({ plan: 'trial', customer: customer.id }) + sub = Stripe::Subscription.create({ plan: plan_with_trial.id, customer: customer.id }) expect(sub.object).to eq('subscription') - expect(sub.plan.to_hash).to eq(plan.to_hash) + expect(sub.plan.to_hash).to eq(plan_with_trial.to_hash) expect(sub.trial_end - sub.trial_start).to eq(14 * 86400) expect(sub.billing_cycle_anchor).to be_nil @@ -302,19 +288,17 @@ def gen_card_tk expect(customer.subscriptions.data.length).to eq(1) expect(customer.subscriptions.data.first.id).to eq(sub.id) - expect(customer.subscriptions.data.first.plan.to_hash).to eq(plan.to_hash) + expect(customer.subscriptions.data.first.plan.to_hash).to eq(plan_with_trial.to_hash) expect(customer.subscriptions.data.first.customer).to eq(customer.id) expect(customer.charges.count).to eq(0) end it "subscribes a customer with no card to a plan with a free trial with plan as item" do - plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) customer = Stripe::Customer.create(id: 'cardless') - - sub = Stripe::Subscription.create({ items: [ { plan: 'trial' } ], customer: customer.id }) + sub = Stripe::Subscription.create({ items: [ { plan: plan_with_trial.id } ], customer: customer.id }) expect(sub.object).to eq('subscription') - expect(sub.items.data[0].plan.to_hash).to eq(plan.to_hash) + expect(sub.items.data[0].plan.to_hash).to eq(plan_with_trial.to_hash) # no idea how to fix this one # expect(sub.trial_end - sub.trial_start).to eq(14 * 86400) @@ -324,17 +308,17 @@ def gen_card_tk expect(customer.subscriptions.data.length).to eq(1) expect(customer.subscriptions.data.first.id).to eq(sub.id) - expect(customer.subscriptions.data.first.items.data.first.plan.to_hash).to eq(plan.to_hash) + expect(customer.subscriptions.data.first.items.data.first.plan.to_hash).to eq(plan_with_trial.to_hash) expect(customer.subscriptions.data.first.customer).to eq(customer.id) # No idea on this one # expect(customer.charges.count).to eq(0) end it "subscribes a customer with no card to a free plan" do - plan = stripe_helper.create_plan(id: 'free_tier', amount: 0) + plan = stripe_helper.create_plan(id: 'free_tier', product: product.id, amount: 0) customer = Stripe::Customer.create(id: 'cardless') - sub = Stripe::Subscription.create({ plan: 'free_tier', customer: customer.id }) + sub = Stripe::Subscription.create({ plan: plan.id, customer: customer.id }) expect(sub.object).to eq('subscription') expect(sub.plan.to_hash).to eq(plan.to_hash) @@ -350,20 +334,21 @@ def gen_card_tk end it "overrides trial length when trial end is set" do - plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) customer = Stripe::Customer.create(id: 'short_trial') trial_end = Time.now.utc.to_i + 3600 - sub = Stripe::Subscription.create({ plan: 'trial', customer: customer.id, trial_end: trial_end }) + sub = Stripe::Subscription.create({ plan: plan_with_trial.id, customer: customer.id, trial_end: trial_end }) expect(sub.object).to eq('subscription') - expect(sub.plan.to_hash).to eq(plan.to_hash) + expect(sub.plan.to_hash).to eq(plan_with_trial.to_hash) expect(sub.current_period_end).to eq(trial_end) expect(sub.trial_end).to eq(trial_end) end it "does not override trial end when trial end is not set" do - plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) + product = stripe_helper.create_product(name: 'Trial') + plan = stripe_helper.create_plan(id: 'trial', amount: 999, + trial_period_days: 14, product: product.id) customer = Stripe::Customer.create(id: 'short_trial') trial_end = Time.now.utc.to_i + 3600 metadata = {description: 'original description'} @@ -387,23 +372,21 @@ def gen_card_tk end it "returns without a trial when trial_end is set to 'now'" do - plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) customer = Stripe::Customer.create(id: 'no_trial', source: gen_card_tk) - sub = Stripe::Subscription.create({ plan: 'trial', customer: customer.id, trial_end: "now" }) + sub = Stripe::Subscription.create({ plan: plan_with_trial.id, customer: customer.id, trial_end: "now" }) expect(sub.object).to eq('subscription') - expect(sub.plan.to_hash).to eq(plan.to_hash) + expect(sub.plan.to_hash).to eq(plan_with_trial.to_hash) expect(sub.status).to eq('active') expect(sub.trial_start).to be_nil expect(sub.trial_end).to be_nil end it "raises error when trial_end is not an integer or 'now'" do - plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) customer = Stripe::Customer.create(id: 'cus_trial') - expect { Stripe::Subscription.create({ plan: 'trial', customer: customer.id, trial_end: "gazebo" }) }.to raise_error {|e| + expect { Stripe::Subscription.create({ plan: plan_with_trial.id, customer: customer.id, trial_end: "gazebo" }) }.to raise_error {|e| expect(e).to be_a Stripe::InvalidRequestError expect(e.http_status).to eq(400) expect(e.message).to eq("Invalid timestamp: must be an integer") @@ -411,11 +394,10 @@ def gen_card_tk end it "raises error when trial_end is set to a time in the past" do - plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) customer = Stripe::Customer.create(id: 'past_trial') trial_end = Time.now.utc.to_i - 3600 - expect { Stripe::Subscription.create({ plan: 'trial', customer: customer.id, trial_end: trial_end }) }.to raise_error {|e| + expect { Stripe::Subscription.create({ plan: plan_with_trial.id, customer: customer.id, trial_end: trial_end }) }.to raise_error {|e| expect(e).to be_a Stripe::InvalidRequestError expect(e.http_status).to eq(400) expect(e.message).to eq("Invalid timestamp: must be an integer Unix timestamp in the future") @@ -423,11 +405,10 @@ def gen_card_tk end it "raises error when trial_end is set to a time more than five years in the future" do - plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) customer = Stripe::Customer.create(id: 'long_trial') trial_end = Time.now.utc.to_i + 31557600*5 + 3600 # 5 years + 1 hour - expect { Stripe::Subscription.create({ plan: 'trial', customer: customer.id, trial_end: trial_end }) }.to raise_error {|e| + expect { Stripe::Subscription.create({ plan: plan_with_trial.id, customer: customer.id, trial_end: trial_end }) }.to raise_error {|e| expect(e).to be_a Stripe::InvalidRequestError expect(e.http_status).to eq(400) expect(e.message).to eq("Invalid timestamp: can be no more than five years in the future") @@ -435,11 +416,10 @@ def gen_card_tk end it 'overrides current period end when billing cycle anchor is set' do - plan = stripe_helper.create_plan(id: 'plan', amount: 999) customer = Stripe::Customer.create(source: gen_card_tk) billing_cycle_anchor = Time.now.utc.to_i + 3600 - sub = Stripe::Subscription.create({ plan: 'plan', customer: customer.id, billing_cycle_anchor: billing_cycle_anchor }) + sub = Stripe::Subscription.create({ plan: plan.id, customer: customer.id, billing_cycle_anchor: billing_cycle_anchor }) expect(sub.status).to eq('active') expect(sub.current_period_end).to eq(billing_cycle_anchor) @@ -447,9 +427,9 @@ def gen_card_tk end it 'when plan defined inside items', live: true do - plan = stripe_helper.create_plan(id: 'BASE_PRICE_PLAN1') + plan = stripe_helper.create_plan(id: 'BASE_PRICE_PLAN1', product: product.id) - plan2 = stripe_helper.create_plan(id: 'PER_USER_PLAN1') + plan2 = stripe_helper.create_plan(id: 'PER_USER_PLAN1', product: product.id) customer = Stripe::Customer.create( source: { object: 'card', @@ -476,9 +456,9 @@ def gen_card_tk end it 'when plan defined inside items for trials with no card', live: true do - plan = stripe_helper.create_plan(id: 'BASE_PRICE_PLAN1') + plan = stripe_helper.create_plan(id: 'BASE_PRICE_PLAN1', product: product.id) - plan2 = stripe_helper.create_plan(id: 'PER_USER_PLAN1') + plan2 = stripe_helper.create_plan(id: 'PER_USER_PLAN1', product: product.id) customer = Stripe::Customer.create trial_end = Time.now.utc.to_i + 3600 @@ -498,7 +478,8 @@ def gen_card_tk end it 'add a new subscription to bill via an invoice' do - plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' }, + product = stripe_helper.create_product(id: 'invoice_billing') + plan = stripe_helper.create_plan(id: 'silver', product: product.id, amount: 4999, currency: 'usd') customer = Stripe::Customer.create(id: 'cardless') @@ -519,8 +500,13 @@ def gen_card_tk expect(sub.days_until_due).to eq 30 end + let(:subscription_header) {{ + :idempotency_key => SecureRandom.hex + }} + it "adds a new subscription to customer with identical idempotency key" do - plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' }, + product = stripe_helper.create_product(name: 'Silver Product') + plan = stripe_helper.create_plan(id: 'silver', product: product.id, amount: 4999, currency: 'usd') customer = Stripe::Customer.create(source: gen_card_tk) @@ -537,28 +523,29 @@ def gen_card_tk end it "adds a new subscription to customer with different idempotency key", :live => true do - plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' }, + product = stripe_helper.create_product(name: 'Silver Product') + plan = stripe_helper.create_plan(id: 'silver', product: product.id, amount: 4999, currency: 'usd') customer = Stripe::Customer.create(source: gen_card_tk) expect(customer.subscriptions.data).to be_empty expect(customer.subscriptions.count).to eq(0) - subscription_header = { - :idempotency_key => "uniq_idempotency_key_#{customer.id}" + sub_header_1 = { + :idempotency_key => SecureRandom.hex } - - another_subscription_header = { - :idempotency_key => "another_uniq_idempotency_key_#{customer.id}" + sub_header_2 = { + :idempotency_key => SecureRandom.hex } - sub1 = Stripe::Subscription.create({ items: [{ plan: 'silver' }], customer: customer.id }, subscription_header) - sub2 = Stripe::Subscription.create({ items: [{ plan: 'silver' }], customer: customer.id }, another_subscription_header) + sub1 = Stripe::Subscription.create({ items: [{ plan: 'silver' }], customer: customer.id }, sub_header_1) + sub2 = Stripe::Subscription.create({ items: [{ plan: 'silver' }], customer: customer.id }, sub_header_2) expect(sub1).not_to eq(sub2) end it "accepts a hash of items" do - silver = stripe_helper.create_plan(id: 'silver') + product = stripe_helper.create_product(name: 'Silver Product') + silver = stripe_helper.create_plan(id: 'silver', product: product.id) customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk) sub = Stripe::Subscription.create({ items: { '0' => { plan: 'silver' } }, customer: customer.id }) @@ -566,15 +553,14 @@ def gen_card_tk expect(sub.cancel_at_period_end).to be_truthy expect(sub.save).to be_truthy - expect(sub.cancel_at_period_end).to be_falsey + expect(sub.cancel_at_period_end).to be_truthy end end context "updating a subscription" do it 'raises invalid request exception when subscription is cancelled' do - stripe_helper.create_plan(id: 'the truth') - customer = Stripe::Customer.create(source: gen_card_tk, plan: 'the truth') + customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id) subscription = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) subscription.delete @@ -587,24 +573,22 @@ def gen_card_tk end it "updates a stripe customer's existing subscription with one plan inside items" do - silver = stripe_helper.create_plan(id: 'silver') customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk) - sub = Stripe::Subscription.create({ items: [ { plan: 'silver' } ], customer: customer.id }) + sub = Stripe::Subscription.create({ items: [ { plan: plan.id } ], customer: customer.id }) sub.delete(at_period_end: true) expect(sub.cancel_at_period_end).to be_truthy expect(sub.save).to be_truthy - expect(sub.cancel_at_period_end).to be_falsey + expect(sub.cancel_at_period_end).to be_truthy end it "updates a stripe customer's existing subscription when plan inside of items" do - silver = stripe_helper.create_plan(id: 'silver') - gold = stripe_helper.create_plan(id: 'gold') - customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: 'silver') + customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: plan.id) + gold_plan = stripe_helper.create_plan(id: 'gold', product: product.id) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) - sub.plan = 'gold' + sub.plan = gold_plan.id sub.quantity = 5 sub.metadata.foo = "bar" sub.metadata.example = "yes" @@ -612,7 +596,7 @@ def gen_card_tk expect(sub.save).to be_truthy expect(sub.object).to eq('subscription') - expect(sub.plan.to_hash).to eq(gold.to_hash) + expect(sub.plan.to_hash).to eq(gold_plan.to_hash) expect(sub.quantity).to eq(5) expect(sub.metadata.foo).to eq( "bar" ) expect(sub.metadata.example).to eq( "yes" ) @@ -623,16 +607,15 @@ def gen_card_tk expect(customer.subscriptions.data.length).to eq(1) expect(customer.subscriptions.data.first.id).to eq(sub.id) - expect(customer.subscriptions.data.first.plan.to_hash).to eq(gold.to_hash) + expect(customer.subscriptions.data.first.plan.to_hash).to eq(gold_plan.to_hash) expect(customer.subscriptions.data.first.customer).to eq(customer.id) end it "updates a stripe customer's existing subscription with single plan when multiple plans inside of items" do - silver_plan = stripe_helper.create_plan(id: 'silver') - gold_plan = stripe_helper.create_plan(id: 'gold') - addon_plan = stripe_helper.create_plan(id: 'addon_plan') - customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: silver_plan.id) + customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: plan.id) + gold_plan = stripe_helper.create_plan(id: 'gold', product: product.id) + addon_plan = stripe_helper.create_plan(id: 'addon_plan', product: product.id) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) sub.items = [{ plan: gold_plan.id, quantity: 2 }, { plan: addon_plan.id, quantity: 2 }] expect(sub.save).to be_truthy @@ -653,12 +636,12 @@ def gen_card_tk end it "updates a stripe customer's existing subscription with multple plans when multiple plans inside of items" do - silver_plan = stripe_helper.create_plan(id: 'silver') - gold_plan = stripe_helper.create_plan(id: 'gold') - addon1_plan = stripe_helper.create_plan(id: 'addon1') - addon2_plan = stripe_helper.create_plan(id: 'addon2') customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk) - sub = Stripe::Subscription.create(customer: customer.id, items: [{ plan: silver_plan.id }, { plan: addon1_plan.id }]) + addon1_plan = stripe_helper.create_plan(id: 'addon1', product: product.id) + sub = Stripe::Subscription.create(customer: customer.id, items: [{ plan: plan.id }, { plan: addon1_plan.id }]) + + gold_plan = stripe_helper.create_plan(id: 'gold', product: product.id) + addon2_plan = stripe_helper.create_plan(id: 'addon2', product: product.id) sub.items = [{ plan: gold_plan.id, quantity: 2 }, { plan: addon2_plan.id, quantity: 2 }] expect(sub.save).to be_truthy @@ -678,9 +661,30 @@ def gen_card_tk expect(customer.subscriptions.data.first.items.data[1].plan.to_hash).to eq(addon2_plan.to_hash) end + it "updates a subscription's cancel_at_period_end" do + silver = stripe_helper.create_plan(id: 'silver', product: product.id) + customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk) + + sub = Stripe::Subscription.create({ items: [ { plan: 'silver' } ], customer: customer.id }) + + expect(sub.cancel_at_period_end).to be_falsey + + sub.cancel_at_period_end = true + sub.save + + expect(sub.save).to be_truthy + expect(sub.cancel_at_period_end).to be_truthy + expect(sub.canceled_at).to be_truthy + + sub.cancel_at_period_end = false + sub.save + + expect(sub.save).to be_truthy + expect(sub.cancel_at_period_end).to be_falsey + expect(sub.canceled_at).to be_falsey + end + it 'when adds coupon', live: true do - plan = stripe_helper.create_plan(id: 'plan_with_coupon2', product: { name: 'One More Test Plan' }, - amount: 777) coupon = stripe_helper.create_coupon customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id) subscription = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) @@ -694,8 +698,6 @@ def gen_card_tk end it 'when add not exist coupon' do - plan = stripe_helper.create_plan(id: 'plan_with_coupon3', product: { name: 'One More Test Plan' }, - amount: 777) customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id) subscription = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) @@ -710,8 +712,6 @@ def gen_card_tk end it 'when coupon is removed' do - plan = stripe_helper.create_plan(id: 'plan_with_coupon3', product: { name: 'One More Test Plan' }, - amount: 777) customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id) coupon = stripe_helper.create_coupon subscription = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) @@ -725,8 +725,7 @@ def gen_card_tk end it "throws an error when plan does not exist" do - free = stripe_helper.create_plan(id: 'free', amount: 0) - customer = Stripe::Customer.create(id: 'cardless', plan: 'free') + customer = Stripe::Customer.create(id: 'cardless', plan: free_plan.id) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) sub.plan = 'gazebo' @@ -740,75 +739,59 @@ def gen_card_tk customer = Stripe::Customer.retrieve('cardless') expect(customer.subscriptions.count).to eq(1) expect(customer.subscriptions.data.length).to eq(1) - expect(customer.subscriptions.data.first.plan.to_hash).to eq(free.to_hash) + expect(customer.subscriptions.data.first.plan.to_hash).to eq(free_plan.to_hash) end it "throws an error when subscription does not exist" do - free = stripe_helper.create_plan(id: 'free', amount: 0) - customer = Stripe::Customer.create(id: 'cardless', plan: 'free') - - expect { Stripe::Subscription.retrieve("gazebo") }.to raise_error {|e| + expect(stripe_helper.list_subscriptions(50).keys).to_not include("sub_NONEXIST") + expect { Stripe::Subscription.retrieve("sub_NONEXIST") }.to raise_error {|e| expect(e).to be_a Stripe::InvalidRequestError expect(e.http_status).to eq(404) expect(e.message).to_not be_nil } - - customer = Stripe::Customer.retrieve('cardless') - expect(customer.subscriptions.count).to eq(1) - expect(customer.subscriptions.data.length).to eq(1) - expect(customer.subscriptions.data.first.plan.to_hash).to eq(free.to_hash) end [nil, 0].each do |trial_period_days| - it "throws an error when updating a customer with no card, and plan trail_period_days = #{trial_period_days}", live: true do + it "raises an error when updating a customer with no card, and plan trial_period_days = #{trial_period_days}", live: true do begin - free = stripe_helper.create_plan(id: 'free', amount: 0) - paid = stripe_helper.create_plan(id: 'enterprise', amount: 499, trial_period_days: trial_period_days) - customer = Stripe::Customer.create(description: 'cardless', plan: 'free') + free_plan + paid_plan = stripe_helper.create_plan(id: 'enterprise', product: product.id, amount: 499, trial_period_days: trial_period_days) + customer = Stripe::Customer.create(description: 'cardless', plan: free_plan.id) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) - sub.plan = 'enterprise' - - expect { sub.save }.to raise_error {|e| - expect(e).to be_a Stripe::InvalidRequestError - expect(e.http_status).to eq(400) - expect(e.message).to_not be_nil - } - - customer = Stripe::Customer.retrieve(customer.id) - expect(customer.subscriptions.count).to eq(1) - expect(customer.subscriptions.data.length).to eq(1) - expect(customer.subscriptions.data.first.plan.to_hash).to eq(free.to_hash) + sub.plan = paid_plan.id + + expect { + sub.save + }.to raise_error(Stripe::InvalidRequestError, "This customer has no attached payment source") ensure customer.delete if customer - paid.delete if paid - free.delete if free + paid_plan.delete if paid_plan + free_plan.delete if free_plan end end end it 'updates a subscription if the customer has a free trial', live: true do - stripe_helper.create_plan(id: 'enterprise', amount: 499) trial_end = Time.now.utc.to_i + 3600 - customer = Stripe::Customer.create(plan: 'enterprise', - trial_end: trial_end) - subscription = customer.subscriptions.first + customer = Stripe::Customer.create(plan: plan.id, trial_end: trial_end) + subscription = customer.subscriptions.first subscription.quantity = 2 subscription.save expect(subscription.quantity).to eq(2) end it "updates a customer with no card to a plan with a free trial" do - free = stripe_helper.create_plan(id: 'free', amount: 0) - trial = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) - customer = Stripe::Customer.create(id: 'cardless', plan: 'free') + free_plan + trial_plan = stripe_helper.create_plan(id: 'trial', product: product.id, amount: 999, trial_period_days: 14) + customer = Stripe::Customer.create(id: 'cardless', plan: free_plan.id) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) - sub.plan = 'trial' + sub.plan = trial_plan.id sub.save expect(sub.object).to eq('subscription') - expect(sub.plan.to_hash).to eq(trial.to_hash) + expect(sub.plan.to_hash).to eq(trial_plan.to_hash) customer = Stripe::Customer.retrieve('cardless') expect(customer.subscriptions.data).to_not be_empty @@ -816,21 +799,21 @@ def gen_card_tk expect(customer.subscriptions.data.length).to eq(1) expect(customer.subscriptions.data.first.id).to eq(sub.id) - expect(customer.subscriptions.data.first.plan.to_hash).to eq(trial.to_hash) + expect(customer.subscriptions.data.first.plan.to_hash).to eq(trial_plan.to_hash) expect(customer.subscriptions.data.first.customer).to eq(customer.id) end it "updates a customer with no card to a free plan" do - free = stripe_helper.create_plan(id: 'free', amount: 0) - gratis = stripe_helper.create_plan(id: 'gratis', amount: 0) - customer = Stripe::Customer.create(id: 'cardless', plan: 'free') + free_plan + customer = Stripe::Customer.create(id: 'cardless', product: product.id, plan: free_plan.id) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) - sub.plan = 'gratis' + gratis_plan = stripe_helper.create_plan(id: 'gratis', product: product.id, amount: 0) + sub.plan = gratis_plan.id sub.save expect(sub.object).to eq('subscription') - expect(sub.plan.to_hash).to eq(gratis.to_hash) + expect(sub.plan.to_hash).to eq(gratis_plan.to_hash) customer = Stripe::Customer.retrieve('cardless') expect(customer.subscriptions.data).to_not be_empty @@ -838,17 +821,15 @@ def gen_card_tk expect(customer.subscriptions.data.length).to eq(1) expect(customer.subscriptions.data.first.id).to eq(sub.id) - expect(customer.subscriptions.data.first.plan.to_hash).to eq(gratis.to_hash) + expect(customer.subscriptions.data.first.plan.to_hash).to eq(gratis_plan.to_hash) expect(customer.subscriptions.data.first.customer).to eq(customer.id) end it "sets a card when updating a customer's subscription" do - free = stripe_helper.create_plan(id: 'free', amount: 0) - paid = stripe_helper.create_plan(id: 'paid', amount: 499) - customer = Stripe::Customer.create(id: 'test_customer_sub', plan: 'free') + customer = Stripe::Customer.create(id: 'test_customer_sub', plan: free_plan.id) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) - sub.plan = 'paid' + sub.plan = plan.id sub.source = gen_card_tk sub.save @@ -861,11 +842,8 @@ def gen_card_tk end it "overrides trial length when trial end is set" do - plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) - customer = Stripe::Customer.create(id: 'test_trial_end', plan: 'trial') - + customer = Stripe::Customer.create(id: 'test_trial_end', plan: plan_with_trial.id) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) - trial_end = Time.now.utc.to_i + 3600 sub.trial_end = trial_end sub.save @@ -876,8 +854,7 @@ def gen_card_tk end it "returns without a trial when trial_end is set to 'now'" do - plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14) - customer = Stripe::Customer.create(id: 'test_trial_end', plan: 'trial') + customer = Stripe::Customer.create(id: 'test_trial_end', plan: plan_with_trial.id, default_source: 'tok_visa') sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) @@ -885,18 +862,15 @@ def gen_card_tk sub.save expect(sub.object).to eq('subscription') - expect(sub.plan.to_hash).to eq(plan.to_hash) + expect(sub.plan.to_hash).to eq(plan_with_trial.to_hash) expect(sub.status).to eq('active') expect(sub.trial_start).to be_nil expect(sub.trial_end).to be_nil end it "changes an active subscription to a trial when trial_end is set" do - plan = stripe_helper.create_plan(id: 'no_trial', amount: 999) - customer = Stripe::Customer.create(id: 'test_trial_end', plan: 'no_trial', source: gen_card_tk) - + customer = Stripe::Customer.create(id: 'test_trial_end', plan: plan.id, source: gen_card_tk) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) - trial_end = Time.now.utc.to_i + 3600 sub.trial_end = trial_end sub.save @@ -910,8 +884,8 @@ def gen_card_tk it "raises error when trial_end is not an integer or 'now'" do - plan = stripe_helper.create_plan(id: 'no_trial', amount: 999) - customer = Stripe::Customer.create(id: 'test_trial_end', plan: 'no_trial', source: gen_card_tk) + expect(plan.trial_period_days).to be_nil + customer = Stripe::Customer.create(id: 'test_trial_end', plan: plan.id, source: gen_card_tk) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) sub.trial_end = "gazebo" @@ -925,10 +899,10 @@ def gen_card_tk end context "cancelling a subscription" do + let(:customer) { Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: plan.id) } it "cancels a stripe customer's subscription", :live => true do - truth = stripe_helper.create_plan(id: 'the truth') - customer = Stripe::Customer.create(source: gen_card_tk, plan: "the truth") + customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id) sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) result = sub.delete @@ -943,53 +917,11 @@ def gen_card_tk expect(customer.subscriptions.count).to eq(0) expect(customer.subscriptions.data.length).to eq(0) end - - it "cancels a stripe customer's subscription at period end" do - truth = stripe_helper.create_plan(id: 'the_truth') - customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: "the_truth") - - sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) - result = sub.delete(at_period_end: true) - - expect(result.status).to eq('active') - expect(result.cancel_at_period_end).to eq(true) - expect(result.id).to eq(sub.id) - - customer = Stripe::Customer.retrieve('test_customer_sub') - expect(customer.subscriptions.data).to_not be_empty - expect(customer.subscriptions.count).to eq(1) - expect(customer.subscriptions.data.length).to eq(1) - - expect(customer.subscriptions.data.first.status).to eq('active') - expect(customer.subscriptions.data.first.cancel_at_period_end).to eq(true) - expect(customer.subscriptions.data.first.ended_at).to be_nil - expect(customer.subscriptions.data.first.canceled_at).to_not be_nil - end - - it "resumes an at period end cancelled subscription" do - truth = stripe_helper.create_plan(id: 'the_truth') - customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: "the_truth") - - sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) - result = sub.delete(at_period_end: true) - - sub.plan = 'the_truth' - sub.save - - customer = Stripe::Customer.retrieve('test_customer_sub') - expect(customer.subscriptions.data).to_not be_empty - expect(customer.subscriptions.count).to eq(1) - expect(customer.subscriptions.data.length).to eq(1) - - expect(customer.subscriptions.data.first.status).to eq('active') - expect(customer.subscriptions.data.first.cancel_at_period_end).to eq(false) - expect(customer.subscriptions.data.first.ended_at).to be_nil - expect(customer.subscriptions.data.first.canceled_at).to be_nil - end end it "supports 'cancelling' by updating cancel_at_period_end" do - truth = stripe_helper.create_plan(id: 'the_truth') + product = stripe_helper.create_product(name: 'Truth Product') + truth = stripe_helper.create_plan(id: 'the_truth', product: product.id) customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: "the_truth") sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) @@ -1011,7 +943,8 @@ def gen_card_tk end it "resumes a subscription cancelled by updating cancel_at_period_end" do - truth = stripe_helper.create_plan(id: 'the_truth') + product = stripe_helper.create_product(name: 'Truth Product') + truth = stripe_helper.create_plan(id: 'the_truth', product: product.id) customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: "the_truth") sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) @@ -1035,7 +968,7 @@ def gen_card_tk end it "doesn't change status of subscription when cancelling at period end" do - trial = stripe_helper.create_plan(id: 'trial', trial_period_days: 14) + trial = stripe_helper.create_plan(id: 'trial', product: product.id, trial_period_days: 14) customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: "trial") sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) @@ -1050,13 +983,11 @@ def gen_card_tk it "doesn't require a card when trial_end is present", :live => true do plan = stripe_helper.create_plan( - amount: 2000, - interval: 'month', - product: { - name: 'Amazing Gold Plan' - }, - currency: 'usd', - id: 'gold' + :amount => 2000, + :product => product.id, + :interval => 'month', + :currency => 'usd', + :id => 'gold' ) stripe_customer = Stripe::Customer.create @@ -1069,7 +1000,7 @@ def gen_card_tk let(:subscription) { Stripe::Subscription.retrieve(customer.subscriptions.data.first.id) } before do - stripe_helper.create_plan(id: 'free', amount: 0) + free_plan Stripe::Subscription.create({ plan: 'free', customer: customer.id }) end @@ -1095,9 +1026,9 @@ def gen_card_tk context "retrieve multiple subscriptions" do it "retrieves a list of multiple subscriptions" do - free = stripe_helper.create_plan(id: 'free', amount: 0) - paid = stripe_helper.create_plan(id: 'paid', amount: 499) - customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: "free") + free_plan + paid = stripe_helper.create_plan(id: 'paid', product: product.id, amount: 499) + customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: free_plan.id) Stripe::Subscription.create({ plan: 'paid', customer: customer.id }) subs = Stripe::Subscription.all({ customer: customer.id }) @@ -1127,9 +1058,7 @@ def gen_card_tk create_plan( :amount => 500, :interval => 'month', - :product => { - :name => 'Sample Plan' - }, + :product => product.id, :currency => 'usd', :id => 'Sample5' ) diff --git a/spec/shared_stripe_examples/subscription_items_examples.rb b/spec/shared_stripe_examples/subscription_items_examples.rb index 76aa3efbe..524577fec 100644 --- a/spec/shared_stripe_examples/subscription_items_examples.rb +++ b/spec/shared_stripe_examples/subscription_items_examples.rb @@ -2,8 +2,9 @@ shared_examples 'Subscription Items API' do let(:stripe_helper) { StripeMock.create_test_helper } - let(:plan) { stripe_helper.create_plan } - let(:plan2) { stripe_helper.create_plan(amount: 100, id: 'one_more_1_plan') } + let(:product) { stripe_helper.create_product(name: 'Silver Product') } + let(:plan) { stripe_helper.create_plan(product: product.id, id: 'silver_plan') } + let(:plan2) { stripe_helper.create_plan(amount: 100, id: 'one_more_1_plan', product: product.id) } let(:customer) { Stripe::Customer.create(source: stripe_helper.generate_card_token) } let(:subscription) { Stripe::Subscription.create(customer: customer.id, items: [{ plan: plan.id }]) } diff --git a/spec/shared_stripe_examples/transfer_examples.rb b/spec/shared_stripe_examples/transfer_examples.rb index fb7686220..857e48aaf 100644 --- a/spec/shared_stripe_examples/transfer_examples.rb +++ b/spec/shared_stripe_examples/transfer_examples.rb @@ -104,7 +104,7 @@ end it "when amount is not integer", live: true do - dest = Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", business_name: "Alex Smith") + dest = Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", requested_capabilities: ['card_payments', 'platform_payments']) expect { Stripe::Transfer.create(amount: '400.2', currency: 'usd', destination: dest.id, @@ -116,7 +116,7 @@ end it "when amount is negative", live: true do - dest = Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", business_name: "Alex Smith") + dest = Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", requested_capabilities: ['card_payments', 'platform_payments']) expect { Stripe::Transfer.create(amount: '-400', currency: 'usd', destination: dest.id, diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index afe19a588..8cbed5bb8 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -30,10 +30,9 @@ if ENV['IS_TRAVIS'] puts "Travis ruby version: #{RUBY_VERSION}" api_key = case RUBY_VERSION - when '2.0.0' then ENV['STRIPE_TEST_SECRET_KEY_A'] - when '2.1.10' then ENV['STRIPE_TEST_SECRET_KEY_B'] - when '2.2.7' then ENV['STRIPE_TEST_SECRET_KEY_C'] - when '2.3.4' then ENV['STRIPE_TEST_SECRET_KEY_D'] + when '2.4.6' then ENV['STRIPE_TEST_SECRET_KEY_A'] + when '2.5.5' then ENV['STRIPE_TEST_SECRET_KEY_B'] + when '2.6.3' then ENV['STRIPE_TEST_SECRET_KEY_C'] end else api_key = ENV['STRIPE_TEST_SECRET_KEY'] diff --git a/spec/support/shared_contexts/stripe_validator_spec.rb b/spec/support/shared_contexts/stripe_validator_spec.rb new file mode 100644 index 000000000..0c7badda6 --- /dev/null +++ b/spec/support/shared_contexts/stripe_validator_spec.rb @@ -0,0 +1,8 @@ + +class StripeValidator + include StripeMock::RequestHandlers::ParamValidators +end + +RSpec.shared_context "stripe validator", shared_context: :metadata do + let(:stripe_validator) { StripeValidator.new } +end \ No newline at end of file