Git Product home page Git Product logo

stripe-ruby-mock's Introduction

stripe-ruby-mock Tests

REQUEST: Looking for More Core Contributors

This gem has unexpectedly grown in popularity and I've gotten pretty busy, so I'm currently looking for more core contributors to help me out. If you're interested, there is only one requirement: submit a significant enough pull request and have it merged into master (many of you have already done this). Afterwards, ping @gilbert in chat and I will add you as a collaborator.

Install

In your gemfile:

gem 'stripe-ruby-mock', '~> 3.1.0', :require => 'stripe_mock'

!!! Important

We have changelog. It's first attempt. Feel free to update it and suggest to a new format of it.

version 3.0.0 has breaking changes - we support stripe > 5 and < 6 for now and try to follow the newest API version. But if you still use older versions please read.

Features

  • No stripe server access required
  • Easily test against stripe errors
  • Mock and customize stripe webhooks
  • Flip a switch to run your tests against Stripe's live test servers

Requirements

  • ruby >= 2.6.0
  • stripe >= 5.0.0

Specifications

STRIPE API TARGET VERSION: 2019-08-20 (master) - we try, but some features are not implemented yet.

Older API version branches:

Versioning System

Since StripeMock tries to keep up with Stripe's API version, its version system is a little different:

  • The major number (1.x.x) is for breaking changes involving how you use StripeMock itself
  • The minor number (x.1.x) is for breaking changes involving Stripe's API
  • The patch number (x.x.0) is for non-breaking changes/fixes involving Stripe's API, or for non-breaking changes/fixes/features for StripeMock itself.

Description

** WARNING: This library does not cover all Stripe API endpoints. If you need one that's missing, please create an issue for it, or see this wiki page if you're interested in contributing **

At its core, this library overrides stripe-ruby's request method to skip all http calls and instead directly return test data. This allows you to write and run tests without the need to actually hit stripe's servers.

You can use stripe-ruby-mock with any ruby testing library. Here's a quick dummy example with RSpec:

require 'stripe_mock'

describe MyApp do
  let(:stripe_helper) { StripeMock.create_test_helper }
  before { StripeMock.start }
  after { StripeMock.stop }

  it "creates a stripe customer" do

    # This doesn't touch stripe's servers nor the internet!
    # Specify :source in place of :card (with same value) to return customer with source data
    customer = Stripe::Customer.create({
      email: '[email protected]',
      source: stripe_helper.generate_card_token
    })
    expect(customer.email).to eq('[email protected]')
  end
end

Test Helpers

Some Stripe API calls require several parameters. StripeMock helps you keep your test brief with some helpers:

describe MyApp do
  let(:stripe_helper) { StripeMock.create_test_helper }

  it "creates a stripe plan" do
    plan = stripe_helper.create_plan(:id => 'my_plan', :amount => 1500)

    # The above line replaces the following:
    # plan = Stripe::Plan.create(
    #   :id => 'my_plan',
    #   :name => 'StripeMock Default Plan ID',
    #   :amount => 1500,
    #   :currency => 'usd',
    #   :interval => 'month'
    # )
    expect(plan.id).to eq('my_plan')
    expect(plan.amount).to eq(1500)
  end
end

The available helpers are:

stripe_helper.create_plan(my_plan_params)
stripe_helper.delete_plan(my_plan_params)
stripe_helper.generate_card_token(my_card_params)

For everything else, use Stripe as you normally would (i.e. use Stripe as if you were not using StripeMock).

Live Testing

Every once in a while you want to make sure your tests are actually valid. StripeMock has a switch that allows you to run your test suite (or a subset thereof) against Stripe's live test servers.

Here is an example of setting up your RSpec (2.x) test suite to run live with a command line switch:

# RSpec 2.x
RSpec.configure do |c|
  if c.filter_manager.inclusions.keys.include?(:live)
    StripeMock.toggle_live(true)
    puts "Running **live** tests against Stripe..."
  end
end

With this you can run live tests by running rspec -t live

Here is an example of setting up your RSpec (3.x) test suite to run live with the same command line switch:

# RSpec 3.x
RSpec.configure do |c|
  if c.filter_manager.inclusions.rules.include?(:live)
    StripeMock.toggle_live(true)
    puts "Running **live** tests against Stripe..."
  end
end

Mocking Card Errors

** Ensure you start StripeMock in a before filter StripeMock.start Tired of manually inputting fake credit card numbers to test against errors? Tire no more!

it "mocks a declined card error" do
  # Prepares an error for the next create charge request
  StripeMock.prepare_card_error(:card_declined)

  expect { Stripe::Charge.create(amount: 1, currency: 'usd') }.to raise_error {|e|
    expect(e).to be_a Stripe::CardError
    expect(e.http_status).to eq(402)
    expect(e.code).to eq('card_declined')
  }
end

Built-In Card Errors

StripeMock.prepare_card_error(:incorrect_number)
StripeMock.prepare_card_error(:invalid_number)
StripeMock.prepare_card_error(:invalid_expiry_month)
StripeMock.prepare_card_error(:invalid_expiry_year)
StripeMock.prepare_card_error(:invalid_cvc)
StripeMock.prepare_card_error(:expired_card)
StripeMock.prepare_card_error(:incorrect_cvc)
StripeMock.prepare_card_error(:card_declined)
StripeMock.prepare_card_error(:missing)
StripeMock.prepare_card_error(:processing_error)
StripeMock.prepare_card_error(:incorrect_zip)

You can see the details of each error in lib/stripe_mock/api/errors.rb

Specifying Card Errors

** Ensure you start StripeMock in a before filter StripeMock.start By default, prepare_card_error only triggers for :new_charge, the event that happens when you run Charge.create. More explicitly, this is what happens by default:

StripeMock.prepare_card_error(:card_declined, :new_charge)

If you want the error to trigger on a different event, you need to replace :new_charge with a different event. For example:

StripeMock.prepare_card_error(:card_declined, :create_card)
customer = Stripe::Customer.create
# This line throws the card error
customer.cards.create

:new_charge and :create_card are names of methods in the StripeMock request handlers. You can also set StripeMock.toggle_debug(true) to see the event name for each Stripe request made in your tests.

Custom Errors

** Ensure you start StripeMock in a before filter StripeMock.start To raise an error on a specific type of request, take a look at the request handlers folder and pass a method name to StripeMock.prepare_error.

If you wanted to raise an error for creating a new customer, for instance, you would do the following:

it "raises a custom error for specific actions" do
  custom_error = StandardError.new("Please knock first.")

  StripeMock.prepare_error(custom_error, :new_customer)

  expect { Stripe::Charge.create(amount: 1, currency: 'usd') }.to_not raise_error
  expect { Stripe::Customer.create }.to raise_error {|e|
    expect(e).to be_a StandardError
    expect(e.message).to eq("Please knock first.")
  }
end

In the above example, :new_customer is the name of a method from customers.rb.

Running the Mock Server

Sometimes you want your test stripe data to persist for a bit, such as during integration tests running on different processes. In such cases you'll want to start the stripe mock server:

# spec_helper.rb
#
# The mock server will automatically be killed when your tests are done running.
#
require 'thin'
StripeMock.spawn_server

Then, instead of StripeMock.start, you'll want to use StripeMock.start_client:

describe MyApp do
  before do
    @client = StripeMock.start_client
  end

  after do
    StripeMock.stop_client
    # Alternatively:
    #   @client.close!
    # -- Or --
    #   StripeMock.stop_client(:clear_server_data => true)
  end
end

This is all essentially the same as using StripeMock.start, except that the stripe test data is held in its own server process.

Here are some other neat things you can do with the client:

@client.state #=> 'ready'

@client.get_server_data(:customers) # Also works for :charges, :plans, etc.
@client.clear_server_data

@client.close!
@client.state #=> 'closed'

Mock Server Options

# NOTE: Shown below are the default options
StripeMock.default_server_pid_path = './stripe-mock-server.pid'

StripeMock.spawn_server(
  :pid_path => StripeMock.default_server_pid_path,
  :host => '0.0.0.0',
  :port => 4999,
  :server => :thin
)

StripeMock.kill_server(StripeMock.default_server_pid_path)

Mock Server Command

If you need the mock server to continue running even after your tests are done, you'll want to use the executable:

$ stripe-mock-server -p 4000
$ stripe-mock-server --help

Mocking Webhooks

If your application handles stripe webhooks, you are most likely retrieving the event from stripe and passing the result to a handler. StripeMock helps you by easily mocking that event:

it "mocks a stripe webhook" do
  event = StripeMock.mock_webhook_event('customer.created')

  customer_object = event.data.object
  expect(customer_object.id).to_not be_nil
  expect(customer_object.default_card).to_not be_nil
  # etc.
end

it "mocks stripe connect webhooks" do
  event = StripeMock.mock_webhook_event('customer.created', account: 'acc_123123')

  expect(event.account).to eq('acc_123123')
end

Customizing Webhooks

By default, StripeMock searches in your spec/fixtures/stripe_webhooks/ folder for your own, custom webhooks. If it finds nothing, it falls back to test events generated through stripe's webhooktester.

For example, you could create a file in spec/fixtures/stripe_webhooks/invoice.created.with-sub.json, copy/paste the default from the default invoice.created.json, and customize it to your needs.

Then you can use that webook directly in your specs:

it "can use a custom webhook fixture" do
  event = StripeMock.mock_webhook_event('invoice.created.with-sub')
  # etc.
end

You can alse override values on the fly:

it "can override webhook values" do
  # NOTE: given hash values get merged directly into event.data.object
  event = StripeMock.mock_webhook_event('customer.created', {
    :id => 'cus_my_custom_value',
    :email => '[email protected]'
  })
  # Alternatively:
  # event.data.object.id = 'cus_my_custom_value'
  # event.data.object.email = '[email protected]'
  expect(event.data.object.id).to eq('cus_my_custom_value')
  expect(event.data.object.email).to eq('[email protected]')
end

You can name events whatever you like in your spec/fixtures/stripe_webhooks/ folder. However, if you try to call a non-standard event that's doesn't exist in that folder, StripeMock will throw an error.

If you wish to use a different fixture path, you can set it yourself:

StripeMock.webhook_fixture_path = './spec/other/folder/'

Generating Card Tokens

Sometimes you need to check if your code reads a stripe card correctly. If so, you can specifically assign card data to a generated card token:

it "generates a stripe card token" do
  card_token = StripeMock.generate_card_token(last4: "9191", exp_year: 1984)

  cus = Stripe::Customer.create(source: card_token)
  card = cus.sources.data.first
  expect(card.last4).to eq("9191")
  expect(card.exp_year).to eq(1984)
end

Debugging

To enable debug messages:

StripeMock.toggle_debug(true)

This will only last for the session; Once you call StripeMock.stop or StripeMock.stop_client, debug will be toggled off.

If you always want debug to be on (it's quite verbose), you should put this in a before block.

Miscellaneous Features

You may have noticed that all generated Stripe ids start with test_. If you want to remove this:

# Turns off test_ prefix
StripeMock.global_id_prefix = false

# Or you can set your own
StripeMock.global_id_prefix = 'my_app_'

TODO

  • Cover all stripe urls/methods
  • Throw useful errors that emulate Stripe's requirements
    • For example: "You must supply either a card or a customer id" for Stripe::Charge
  • Fingerprinting for other resources besides Cards

Developing stripe-ruby-mock

Please see this wiki page

Patches are welcome and greatly appreciated! If you're contributing to fix a problem, be sure to write tests that illustrate the problem being fixed. This will help ensure that the problem remains fixed in future updates.

Note: You may need to ulimit -n 4048 before running the test suite to get all tests to pass.

Copyright

Copyright (c) 2013 Gilbert

See LICENSE.txt for details.

stripe-ruby-mock's People

Contributors

adbjesus avatar alexmamonchik avatar amrdruid avatar cgunther avatar csalvato avatar eddm avatar fabianoarruda avatar gilbert avatar gyardley avatar icreatejb avatar ioki-klaus avatar jamesprior avatar joshcass avatar ka8725 avatar louim avatar mnin avatar nhocki avatar nomanurrehman avatar pedantic-git avatar pwim avatar rdptz avatar sman591 avatar smtlaissezfaire avatar tastypi avatar theoretick avatar trevorhinesley avatar typeoneerror avatar vadzimpiatkevich avatar vkinelev avatar ynagorny avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stripe-ruby-mock's Issues

Failing specs in Master

Just clarifying that there are 4 failing specs in master?

  1) StripeMock Server behaves like Customer API creates a stripe customer with a default card
     Failure/Error: expect(customer.cards.count).to eq(1)
     NoMethodError:
       undefined method `cards' for #<Stripe::Customer:0x007ff21c23da78>
     Shared Example Group: "Customer API" called from ./spec/support/stripe_examples.rb:12
     # ./spec/shared_stripe_examples/customer_examples.rb:15:in `block (2 levels) in <top (required)>'

  2) StripeMock Server behaves like Customer API creates a stripe customer without a card
     Failure/Error: expect(customer.cards.count).to eq(0)
     NoMethodError:
       undefined method `cards' for #<Stripe::Customer:0x007ff21c2cc9a8>
     Shared Example Group: "Customer API" called from ./spec/support/stripe_examples.rb:12
     # ./spec/shared_stripe_examples/customer_examples.rb:32:in `block (2 levels) in <top (required)>'

  3) StripeMock Server behaves like Customer API retrieves a stripe customer
     Failure/Error: expect(customer.default_card).to eq(original.default_card)
     NoMethodError:
       undefined method `default_card' for #<Stripe::Customer:0x007ff21c59f310>
     Shared Example Group: "Customer API" called from ./spec/support/stripe_examples.rb:12
     # ./spec/shared_stripe_examples/customer_examples.rb:63:in `block (2 levels) in <top (required)>'

  4) StripeMock Server behaves like Customer API updates a stripe customer's card
     Failure/Error: card = original.cards.data.first
     NoMethodError:
       undefined method `cards' for #<Stripe::Customer:0x007ff21c792668>
     Shared Example Group: "Customer API" called from ./spec/support/stripe_examples.rb:12
     # ./spec/shared_stripe_examples/customer_examples.rb:101:in `block (2 levels) in <top (required)>'

I was trying to look into the "cards" deal. But then I got confused because it's saying #cards off of Stripe::Customer. Is Stripe::Customer from cards coming from the actual gem or are you monkey patching a response somehow? Wondering if it's stripe-ruby-mock's fault or the gem not having that actual method yet. I know cards was recently added to the Stripe api... so not sure.

starting server causing error in postgres

Ive narrowed this behaviour down to when the server is started. It does not happen otherwise. I dont really know what other information i can provide to help but ill happily provide nay other information that i can.

/Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/blankslate-3.1.2/lib/blankslate.rb:51: warning: undefining `object_id' may cause serious problems
You are using WebMock 1.14.0. VCR is known to work with WebMock >= 1.8.0, < 1.14. It may not work with this version.
/Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/activerecord-3.2.13/lib/active_record/connection_adapters/postgresql_adapter.rb:1147:in `translate_exception': undefined method `error_field' for nil:NilClass (NoMethodError)
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract_adapter.rb:284:in `rescue in log'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `log'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/activerecord-3.2.13/lib/active_record/connection_adapters/postgresql_adapter.rb:641:in `query'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/activerecord-3.2.13/lib/active_record/connection_adapters/postgresql_adapter.rb:777:in `tables'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/activerecord-3.2.13/lib/active_record/connection_adapters/postgresql_adapter.rb:526:in `ensure in disable_referential_integrity'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/activerecord-3.2.13/lib/active_record/connection_adapters/postgresql_adapter.rb:526:in `disable_referential_integrity'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/database_cleaner-1.1.1/lib/database_cleaner/active_record/deletion.rb:57:in `clean'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/database_cleaner-1.1.1/lib/database_cleaner/base.rb:40:in `clean_with'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/database_cleaner-1.1.1/lib/database_cleaner/configuration.rb:85:in `block in clean_with'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/database_cleaner-1.1.1/lib/database_cleaner/configuration.rb:85:in `each'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/database_cleaner-1.1.1/lib/database_cleaner/configuration.rb:85:in `clean_with'
    from /Users/luke/code/sqwiggle/sqwiggle-web/spec/spec_helper.rb:59:in `block (2 levels) in <top (required)>'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/hooks.rb:21:in `instance_eval'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/hooks.rb:21:in `run'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/hooks.rb:85:in `block in run'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/hooks.rb:85:in `each'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/hooks.rb:85:in `run'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/hooks.rb:446:in `run_hook'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/command_line.rb:27:in `block in run'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/reporter.rb:58:in `report'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/command_line.rb:25:in `run'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/runner.rb:80:in `run'
    from /Users/luke/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/rspec-core-2.14.5/lib/rspec/core/runner.rb:17:in `block in autorun'

Retrieve a Stripe Token

I have the following code included in my RSpec tests:

card_token = StripeMock.generate_card_token(last4: '4242')
Stripe::Token.retrieve(card_token)

When I run the specs I get the following:

WARNING: Unrecognized method + url: [get /v1/tokens/test_tok_1]
 params: {}

Am I using stripe mock incorrectly or has the method yet to be implemented? If its the latter, I'd be glad to add it.

Stripe-Ruby-Mock is not failing accounts with insufficient funds

Stripe-Ruby-Mock is generally working for me, but the following spec passes when I speak to the Stripe server directly, but fails when I use Stripe-Ruby-Mock.

    it "must have a valid credit card number" do
      login_as "customer"
      visit new_order_path(:product => "Retail Site Search")
      expect(find_field("order_product_id").value).to eq @product.id.to_s
      expect(page).to have_content User.last.email
      fill_in_order_fields
      click_on "submit_order"
      fill_in_standard_competitor_fields
      click_on "submit_order"
      click_on "submit_order"
      fill_in_credit_card_fields
      fill_in "order_number", :with => "4000000000000002"
      click_on "create_card"
      expect(page.current_path).to eq pay_order_path(Order.last)
      expect(ActionMailer::Base.deliveries.empty?).to be_truthy
      expect(page).to have_content "The credit card number you supplied was incorrect"
    end

It let's the number through as if the account has sufficient funds.

Stripe sets this aside as a number that should always generate an insufficient funds error code. See https://stripe.com/docs/testing

Update a Card doesn't work

Updating a card doesn't seem to work.

I can successfully retrieve the card

card = @customer.cards.retrieve(@payment_method.stripe_card_id)

Set a property

card.name = payment_method_params[:cardholder_name] if payment_method_params[:cardholder_name].present?

Now call

card.save

It errors and says

Stripe::InvalidRequestError Exception: No such customer: test_cus_1/cards/test_cc_3

Does anybody else have this same issue? Or am I forgetting something?

Cannot apply a coupon when creating a subscription

When doing the following:

plan_opts =  {:plan=>"Designer25", :coupon=>"WECORA5D"}
subscription = customer.subscriptions.create(plan_opts)

the return is:

#<Stripe::Subscription:0x3fd8c8007914 id=test_su_4> JSON: {
  "id": "test_su_4",
  "current_period_start": 1395759679,
  "current_period_end": 1398438079,
  "status": "active",
  "plan": "Designer25",
  "cancel_at_period_end": false,
  "canceled_at": null,
  "ended_at": null,
  "start": 1308595038,
  "object": "subscription",
  "trial_start": null,
  "trial_end": null,
  "customer": "test_cus_3",
  "quantity": 1
 }

when it should include a discount object representing the coupon. Without it we cannot test subscriptions that are charged with discount.

Here are the docs - https://stripe.com/docs/api#create_subscription

Thanks.

Weird server issues when specs run

Whenever specs run/fail I get this:


/Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/dante-0.1.5/lib/dante/runner.rb:159:in `parse_options': invalid option: -f (OptionParser::InvalidOption)
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/dante-0.1.5/lib/dante/runner.rb:50:in `execute'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/stripe-ruby-mock-1.8.4.4/lib/stripe_mock/api/server.rb:21:in `kill_server'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/stripe-ruby-mock-1.8.4.4/lib/stripe_mock/api/server.rb:16:in `block in spawn_server'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:103:in `fork'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:103:in `command'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:80:in `block (3 levels) in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:80:in `fork'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:80:in `block (2 levels) in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:73:in `each'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:73:in `block in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:62:in `loop'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:62:in `go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:78:in `block (3 levels) in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:78:in `fork'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:78:in `block (2 levels) in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:73:in `each'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:73:in `block in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:62:in `loop'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:62:in `go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:78:in `block (3 levels) in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:78:in `fork'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:78:in `block (2 levels) in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:73:in `each'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:73:in `block in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:62:in `loop'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:62:in `go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:78:in `block (3 levels) in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:78:in `fork'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:78:in `block (2 levels) in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:73:in `each'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:73:in `block in go'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:62:in `loop'
    from /Users/Bob/.rvm/gems/ruby-1.9.3-p448@someapp/gems/zeus-0.13.3/lib/zeus.rb:62:in `go'
    from -e:1:in `<main>'

The weird thing is if I don't run Zeus it doesn't even run at all. Very annoying.

Setup: guard-rspec/zeus

Web hook implementation issue for controller specs?

Hi folks. Have been using and loving Stripe Mock. But just came across a head scratcher.

My stripe web hooks controller looks like this:

  def create
    @event = Stripe::Event.retrieve(params[:id])
    method_name = @event.type.tr('.', '_')
    send(method_name) if respond_to?(method_name, true)
    head :ok
  end

  private

  def invoice_payment_succeeded
    ...
  end

I have various specs. Here's the simplest. They all return the same error:

let(:event) { StripeMock.mock_webhook_event('invoice.payment_succeeded') }

it "returns status 200" do
  post :create, id: event.id
  expect(response.status).to eq 200
end
WARNING: Unrecognized method + url: [get /v1/events/evt_00000000000000]
 params: {}
F

Failures:

  1) StripeEventsController POST #create when webhook event is implemented returns status 200
     Failure/Error: post :create, id: event.id
     NoMethodError:
       undefined method `type' for #<Stripe::Event:0x3ffd918f6f3c> JSON: {}
     # ./app/controllers/stripe_events_controller.rb:14:in `create'
     # ./spec/controllers/stripe_events_controller_spec.rb:32:in `block (4 levels) in <top (required)>'

I've previously used web hook mocks for my model specs and they were fine. What am I missing? Cheers.

Specs don't pass unless you run server

I was wrestling with why the specs wouldn't pass for a good while until I tried running ./bin/stripe-mock-server and then they finally passed.

Should this be required to run the test suite?

Support single subscription API?

Upon upgrading from 1.8.7.2 to latest, all of my Stripe specs failed. It looks like this lib isn't supporting legacy single subscription API for creating/updating subscription, even though the Stripe gem will indefinitely. Any chance of adding them back in?

customer.subscriptions.create({:plan => 'something'}) wrong response

According to stripe docs:
https://stripe.com/docs/api#create_subscription

When creating a new subscription, this is the expected response:

customer.subscriptions.create(plan: 'basic')
#<Stripe::StripeObject id=sub_3kdFpdlKthuL5B 0x00000a> JSON: {
  "id": "sub_3kdFpdlKthuL5B",
  "plan": "basic",
  "object": "subscription",
  "start": 1396043897,
  "status": "active",
  "customer": "cus_3kFavDGeHnFvFF",
  "cancel_at_period_end": false,
  "current_period_start": 1396043897,
  "current_period_end": 1398722297,
  "ended_at": null,
  "trial_start": null,
  "trial_end": null,
  "canceled_at": null,
  "quantity": 1,
  "application_fee_percent": null,
  "discount": null
}

however, I think the latest version of the 'stripe' gem has changed this behavior, this is the current response:

#<Stripe::Subscription:0x3be5854 id=sub_3kdVIgacdHlaUB> JSON: {
  "id": "sub_3kdVIgacdHlaUB",
  "plan": {"id":"free","interval":"month","name":"Free","created":121212,"amount":0,"currency":"usd","object":"plan","livemode":false,"interval_count":1,"trial_period_days":null,"metadata":{},"statement_description":null},
  "object": "subscription",
  "start": 1396044840,
  "status": "active",
  "customer": "cus_3kdVf7ZYCtdgVH",
  "cancel_at_period_end": false,
  "current_period_start": 1396044840,
  "current_period_end": 1398723240,
  "ended_at": null,
  "trial_start": null,
  "trial_end": null,
  "canceled_at": null,
  "quantity": 1,
  "application_fee_percent": null,
  "discount": null
}

As you can see, now "plan" returns the whole plan object instead of only the id string.

Can I use this?

Can I use this now for subscriptions in model specs and integration specs via Capybara?

Stripe::Invoice.all is unsupported

In my code, this line
invoice = Stripe::Invoice.all(customer: self.stripe_customer_token, count: 1).first
produces the following message when the specs are run

WARNING: Unrecognized method + url: [get /v1/invoices]
 params: {:customer=>"test_cus_1", :count=>100}

invoice is set to nil, even after doing things which normally cause Stripe to create an invoice.

customer.cards.create returns Stripe::InvalidRequestError

This code (from the 2013-08-13 api version).

customer = Stripe::Customer.retrieve("cus_2V4hw2Y2izDeZY")
customer.cards.create(:card => "tok_1Z2ZOUF2bL6CCB")

Returns a Stripe::InvalidRequestError with No such customer: cus_2V4hw2Y2izDeZY/cards even though the customer exists.

Awesome library btw :)

StripeMock.prepare_card_error doesn't seem to throw the error

I'm using StripeMock for integration tests, and I keep getting 200 responses when I've asked it to prepare errors. For example:

StripeMock.prepare_card_error(:incorrect_number)
submit_cc_form

<in the controller, when the form is submitted>
@customer = Stripe::Customer.create
@customer.cards.create

<StripeMock debugger output>
[StripeMock req]::new_customer post /v1/customers
                  {}
           [res]  {:email=>"[email protected]", :description=>"an auto-generated stripe customer data mock", :object=>"customer", :created=>1372126710, :id=>"test_cus_1", :livemode=>false, :delinquent=>false, :subscription=>nil, :discount=>nil, :account_balance=>0, :cards=>{:object=>"list", :count=>0, :url=>"/v1/customers/test_cus_1/cards", :data=>[]}, :default_card=>nil}
[StripeMock req]::create_card post /v1/customers/test_cus_1/cards
                  {:card=>"tok_103Utd2DItrN7h5Wj3SaAidq"}
           [res]  {:id=>"test_cc_2", :object=>"card", :last4=>"4242", :type=>"Visa", :exp_month=>4, :exp_year=>2016, :fingerprint=>"wXWJT135mEK107G8", :customer=>"test_cus_1", :country=>"US", :name=>"Johnny App", :address_line1=>nil, :address_line2=>nil, :address_city=>nil, :address_state=>nil, :address_zip=>nil, :address_country=>nil, :cvc_check=>nil, :address_line1_check=>nil, :address_zip_check=>nil}

I'm expecting it to throw the error on cards.create, but for some reason it's returning the regular card.

Thanks!

Access a customers charges.

With the following code:

card_token = StripeMock.generate_card_token(last4: '4242')
plan_id = Stripe::Plan.create(id: 'yearly_pro', amount: 2500, currency: 'usd', interval: 'year', name: 'Yearly Pro Plan').id
customer = Stripe::Customer.create(plan: plan_id, card: card_token)
puts customer.charges

I see the following:

WARNING: Unrecognized method + url: [get /v1/charges]
  params: { customer => 'test_cus_3' }
{}

I assume that method is not added yet. Just wondering.

Not parsing all JSON from fixtures.

Using:

  • stripe-ruby-mock (1.8.4.10)

When I run the following code:

event = StripeMock.mock_webhook_event('charge.succeeded')
event.id
# => 'evt_000000000'
event.data.object.customer
# => nil

However, when I look at the JSON fixture, the customer is set. I'm wondering if this is something I am doing wrong or an issue with how stripe-ruby-mock is parsing the fixtures?

Stripe::InvalidRequestError: You must supply a valid card

Using stripe (1.10.1)
Using stripe-ruby-mock (1.10.1.4)

I'm now creating the subscription from customer.subscriptions instead of using customer.create.
ex: customer.subscriptions.create(plan: plan.id, card: token)

I receive Stripe::InvalidRequestError: You must supply a valid card
Even though everything works manually.

Any idea? Need more info?

Canceling a subscription doesn't work?

[StripeMock req] post /v1/customers
                 {:description=>1, :email=>"[email protected]"}
[StripeMock res] {:email=>"[email protected]", :description=>1, :object=>"customer", :created=>1372126710, :id=>"test_cus_188", :livemode=>false, :delinquent=>false, :subscription=>nil, :discount=>nil, :account_balance=>0, :cards=>{:object=>"list", :count=>0, :url=>"/v1/customers/test_cus_188/cards", :data=>[]}, :default_card=>nil}
[StripeMock req] get /v1/customers/test_cus_188
                 {}
[StripeMock res] {:email=>"[email protected]", :description=>1, :object=>"customer", :created=>1372126710, :id=>"test_cus_188", :livemode=>false, :delinquent=>false, :subscription=>nil, :discount=>nil, :account_balance=>0, :cards=>{:object=>"list", :count=>0, :url=>"/v1/customers/test_cus_188/cards", :data=>[]}, :default_card=>nil}
[StripeMock req] post /v1/customers/test_cus_188
                 {:card=>"some-other-token"}
[StripeMock res] {:email=>"[email protected]", :description=>1, :object=>"customer", :created=>1372126710, :id=>"test_cus_188", :livemode=>false, :delinquent=>false, :subscription=>nil, :discount=>nil, :account_balance=>0, :cards=>{:object=>"list", :count=>1, :url=>"/v1/customers/test_cus_188/cards", :data=>[{:id=>"test_cc_189", :object=>"card", :last4=>"4242", :type=>"Visa", :exp_month=>4, :exp_year=>2016, :fingerprint=>"wXWJT135mEK107G8", :customer=>"test_cus_188", :country=>"US", :name=>"Johnny App", :address_line1=>nil, :address_line2=>nil, :address_city=>nil, :address_state=>nil, :address_zip=>nil, :address_country=>nil, :cvc_check=>nil, :address_line1_check=>nil, :address_zip_check=>nil}]}, :default_card=>"test_cc_189"}
[StripeMock req] get /v1/customers/test_cus_188
                 {}
[StripeMock res] {:email=>"[email protected]", :description=>1, :object=>"customer", :created=>1372126710, :id=>"test_cus_188", :livemode=>false, :delinquent=>false, :subscription=>nil, :discount=>nil, :account_balance=>0, :cards=>{:object=>"list", :count=>1, :url=>"/v1/customers/test_cus_188/cards", :data=>[{:id=>"test_cc_189", :object=>"card", :last4=>"4242", :type=>"Visa", :exp_month=>4, :exp_year=>2016, :fingerprint=>"wXWJT135mEK107G8", :customer=>"test_cus_188", :country=>"US", :name=>"Johnny App", :address_line1=>nil, :address_line2=>nil, :address_city=>nil, :address_state=>nil, :address_zip=>nil, :address_country=>nil, :cvc_check=>nil, :address_line1_check=>nil, :address_zip_check=>nil}]}, :default_card=>"test_cc_189"}
[StripeMock req] post /v1/customers/test_cus_188/subscription
                 {:plan=>"starter"}
[StripeMock res] {:current_period_end=>1308681468, :status=>"trialing", :plan=>{:interval=>"month", :amount=>2300, :trial_period_days=>nil, :object=>"plan", :id=>"starter", :name=>"The Basic Plan", :currency=>"usd", :livemode=>false, :interval_count=>1}, :current_period_start=>1308595038, :cancel_at_period_end=>false, :canceled_at=>nil, :start=>1308595038, :object=>"subscription", :trial_start=>1308595038, :trial_end=>1308681468, :customer=>"test_cus_188", :quantity=>1, :id=>"test_su_190"}
[StripeMock req] get /v1/customers/test_cus_188
                 {}
[StripeMock res] {:email=>"[email protected]", :description=>1, :object=>"customer", :created=>1372126710, :id=>"test_cus_188", :livemode=>false, :delinquent=>false, :subscription=>{:current_period_end=>1308681468, :status=>"trialing", :plan=>{:interval=>"month", :amount=>2300, :trial_period_days=>nil, :object=>"plan", :id=>"starter", :name=>"The Basic Plan", :currency=>"usd", :livemode=>false, :interval_count=>1}, :current_period_start=>1308595038, :cancel_at_period_end=>false, :canceled_at=>nil, :start=>1308595038, :object=>"subscription", :trial_start=>1308595038, :trial_end=>1308681468, :customer=>"test_cus_188", :quantity=>1, :id=>"test_su_190"}, :discount=>nil, :account_balance=>0, :cards=>{:object=>"list", :count=>1, :url=>"/v1/customers/test_cus_188/cards", :data=>[{:id=>"test_cc_189", :object=>"card", :last4=>"4242", :type=>"Visa", :exp_month=>4, :exp_year=>2016, :fingerprint=>"wXWJT135mEK107G8", :customer=>"test_cus_188", :country=>"US", :name=>"Johnny App", :address_line1=>nil, :address_line2=>nil, :address_city=>nil, :address_state=>nil, :address_zip=>nil, :address_country=>nil, :cvc_check=>nil, :address_line1_check=>nil, :address_zip_check=>nil}]}, :default_card=>"test_cc_189"}
[StripeMock req] delete /v1/customers/test_cus_188/subscription
                 {}
[StripeMock res] {:deleted=>true, :id=>"test_su_190"}
[StripeMock req] get /v1/customers/test_cus_188
                 {}
[StripeMock res] {:email=>"[email protected]", :description=>1, :object=>"customer", :created=>1372126710, :id=>"test_cus_188", :livemode=>false, :delinquent=>false, :subscription=>{:current_period_end=>1308681468, :status=>"trialing", :plan=>{:interval=>"month", :amount=>2300, :trial_period_days=>nil, :object=>"plan", :id=>"starter", :name=>"The Basic Plan", :currency=>"usd", :livemode=>false, :interval_count=>1}, :current_period_start=>1308595038, :cancel_at_period_end=>false, :canceled_at=>nil, :start=>1308595038, :object=>"subscription", :trial_start=>1308595038, :trial_end=>1308681468, :customer=>"test_cus_188", :quantity=>1, :id=>"test_su_190"}, :discount=>nil, :account_balance=>0, :cards=>{:object=>"list", :count=>1, :url=>"/v1/customers/test_cus_188/cards", :data=>[{:id=>"test_cc_189", :object=>"card", :last4=>"4242", :type=>"Visa", :exp_month=>4, :exp_year=>2016, :fingerprint=>"wXWJT135mEK107G8", :customer=>"test_cus_188", :country=>"US", :name=>"Johnny App", :address_line1=>nil, :address_line2=>nil, :address_city=>nil, :address_state=>nil, :address_zip=>nil, :address_country=>nil, :cvc_check=>nil, :address_line1_check=>nil, :address_zip_check=>nil}]}, :default_card=>"test_cc_189"}
  describe "#cancel_subscription" do
    before do
      StripeMock.toggle_debug(true)
    end
    it "cancels the subscription for model and stripe customer" do
      subscription = FactoryGirl.build :subscription, user: user
      subscription.create_stripe_customer
      subscription.save
      subscription.update_card "some-other-token"
      subscription.save
      subscription.change_plan_to(plan)
      subscription.cancel_subscription

      subscription.active.should eql(false)
      subscription.plan.should eql(nil)

      customer = Stripe::Customer.retrieve subscription.stripe_customer_token
      customer.subscription.should eql(nil)
    end
  end
  def cancel_subscription
    self.active = false
    self.plan = nil
    unless stripe_customer_token.nil?
      customer = Stripe::Customer::retrieve(stripe_customer_token)
      customer.cancel_subscription
    end
    save!
  rescue Stripe::StripeError => e
    logger.error "Stripe Error: " + e.message
    errors.add :base, "Unable to cancel your subscription. #{e.message}."
    false
  end

Requiring stripe_mock problem

Adding require 'stripe_mock' to one of my spec files produces this error:

10:30:41 - INFO - Running: spec/models/subscription_spec.rb
/Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/blankslate-3.1.2/lib/blankslate.rb:51: warning: undefining `object_id' may cause serious problems
/Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:251:in `require': cannot load such file -- thin (LoadError)
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:251:in `block in require'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/activesupport-        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/zeus-0.13.3/lib/zeus/load_tracking.rb:50:in `load'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/zeus-0.13.3/lib/zeus/load_tracking.rb:50:in `load'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/zeus-0.13.3/lib/zeus/load_tracking.rb:43:in `load'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:245:in `block in load'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:236:in `load_dependency'
        from /Users/landonschropp/
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:245:in `load'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/rspec-core-2.13.1/lib/rspec/core/configuration.rb:819:in `block in load_spec_files'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/rspec-core-2.13.1/lib/rspec/core/configuration.rb:819:in `each'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/rspec-core-2.13.1/lib/rspec/core/configuration.rb:819:in `load_spec_files'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/rspec-core-2.13.1/lib/rspec/core/command_line.rb:22:in
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/rspec-core-2.13.1/lib/rspec/core/runner.rb:80:in `run'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/zeus-0.13.3/lib/zeus/rails.rb:188:in `test'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/zeus-0.13.3/lib/zeus.rb:116:in `block in command'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/zeus-0.13.3/lib/zeus.rb:103:in `fork'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/zeus-0.13.3/lib/zeus.rb:103:in `command'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/zeus-0.13.3/lib/zeus.rb:80:in `block in go'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/zeus-0.13.3/lib/zeus.rb:62:in `loop'
        from /Users/landonschropp/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/zeus-0.13.3/lib/zeus.rb:62:in `go'
        from -e:1:in `<main>'

Is there some kind of conflict between stripe-ruby-mock and Zeus? The error doesn't occur when I run the specs without Zeus. I've updated my bundle and even added thin to it without any luck.

Accepting :card parameter when updating a subscription

Hi,

According to the docs, you can pass a :card parameter to the customer#update_subscription method and that will be used as the new default card for the customer.

https://stripe.com/docs/api/ruby#update_subscription

But this returns an error on the mock.

c = Stripe::Customer.create(email:'email')

c.update_subscription(card: 'test_tok_2', :plan => 'small', :prorate => true)
Stripe::InvalidRequestError: You must supply a valid card
.../gems/stripe-ruby-mock-1.8.4.10/lib/stripe_mock/request_handlers/customers.rb:36:in `update_subscription'

https://github.com/rebelidealist/stripe-ruby-mock/blob/master/lib/stripe_mock/request_handlers/customers.rb?source=cc#L35

Add support for metadata on subscriptions

Stripe ruby mock currently doesnt support metadata on subscriptions, which leads to failing tests for anyone using metadata in their code. Please add support for this.

Card creation doesn't update default card on a customer.

When I create a customer, attach a card, and then retrieve the customer, I see a list of cards but the default card is not set.

Output from @customer.inspect below:

<Stripe::Customer:0x3fec7604a694 id=test_cus_1> JSON: {
  "id": "test_cus_1",
  "email": "[email protected]",
  "description": "an auto-generated stripe customer data mock",
  "object": "customer",
  "created": 1372126710,
  "livemode": false,
  "delinquent": false,
  "discount": null,
  "account_balance": 0,
  "cards": {"object":"list","count":1,"url":"/v1/customers/test_cus_1/cards","data":[{"id":"test_cc_3","object":"card","last4":"9191","type":"Visa","exp_month":4,"exp_year":2015,"fingerprint":"wXWJT135mEK107G8","customer":"test_cus_1","country":"US","name":"Johnny App","address_line1":null,"address_line2":null,"address_city":null,"address_state":null,"address_zip":null,"address_country":null,"cvc_check":null,"address_line1_check":null,"address_zip_check":null}]},
  "subscriptions": {"object":"list","count":0,"url":"/v1/customers/test_cus_1/subscriptions","data":[]},
  "default_card": null
}

My interim solution has been to manually add the default card, but it would be nice to support this.

Support expanding objects (like customer.default_card)

First, thanks for the great work on this gem. It's made my life a lot easier.

Stripe allows child objects to be expanded when retrieving a parent. From https://stripe.com/docs/api/ruby#expand:

Many objects contain the id of another object in their response properties. Those objects can be expanded inline with the expand request parameter. Objects that can be expanded are noted in this documentation.

So if I know I want to use the default_card object, I pass :expand => ['default_card'] to Customer::Retrieve, like so:

irb(main):022:0> c = Stripe::Customer.retrieve({id: "cus_4PsDeNNph7uDl5", :expand => ['default_card']}, some_api_key)
=> #<Stripe::Customer:0x3fcb8198f3dc id=cus_4PsDeNNph7uDl5> JSON: {
  "id": "cus_4PsDeNNph7uDl5",
  "object": "customer",
  "created": 1405555764,
  "livemode": false,
  "description": null,
  "email": "test@example.com",
  "delinquent": false,
  "metadata": {},
  "subscriptions": {"object":"list","total_count":0,"has_more":false,"url":"/v1/customers/cus_4PsDeNNph7uDl5/subscriptions","data":[]},
  "discount": null,
  "account_balance": 0,
  "currency": null,
  "cards": {"object":"list","total_count":1,"has_more":false,"url":"/v1/customers/cus_4PsDeNNph7uDl5/cards","data":[{"id":"card_14H2V04DY8wO1agf2PweH4nx","object":"card","last4":"4242","brand":"Visa","funding":"credit","exp_month":5,"exp_year":2015,"fingerprint":"jXhLImsGljL25sAx","country":"US","name":null,"address_line1":null,"address_line2":null,"address_city":null,"address_state":null,"address_zip":null,"address_country":null,"cvc_check":null,"address_line1_check":null,"address_zip_check":null,"customer":"cus_4PsDeNNph7uDl5","type":"Visa"}]},
  "default_card": {"id":"card_14H2V04DY8wO1agf2PweH4nx","object":"card","last4":"4242","brand":"Visa","funding":"credit","exp_month":5,"exp_year":2015,"fingerprint":"jXhLImsGljL25sAx","country":"US","name":null,"address_line1":null,"address_line2":null,"address_city":null,"address_state":null,"address_zip":null,"address_country":null,"cvc_check":null,"address_line1_check":null,"address_zip_check":null,"customer":"cus_4PsDeNNph7uDl5","type":"Visa"}
}

If I didn't pass the :expand => ['default_card'] param, I'd just see a string containing a card_id in the returned customer:

irb(main):020:0> c = Stripe::Customer.retrieve({id: "cus_4PsDeNNph7uDl5"}, some_api_key)
=> #<Stripe::Customer:0x3fcb83778efc id=cus_4PsDeNNph7uDl5> JSON: {
  "id": "cus_4PsDeNNph7uDl5",
  "object": "customer",
  "created": 1405555764,
  "livemode": false,
  "description": null,
  "email": "test@example.com",
  "delinquent": false,
  "metadata": {},
  "subscriptions": {"object":"list","total_count":0,"has_more":false,"url":"/v1/customers/cus_4PsDeNNph7uDl5/subscriptions","data":[]},
  "discount": null,
  "account_balance": 0,
  "currency": null,
  "cards": {"object":"list","total_count":1,"has_more":false,"url":"/v1/customers/cus_4PsDeNNph7uDl5/cards","data":[{"id":"card_14H2V04DY8wO1agf2PweH4nx","object":"card","last4":"4242","brand":"Visa","funding":"credit","exp_month":5,"exp_year":2015,"fingerprint":"jXhLImsGljL25sAx","country":"US","name":null,"address_line1":null,"address_line2":null,"address_city":null,"address_state":null,"address_zip":null,"address_country":null,"cvc_check":null,"address_line1_check":null,"address_zip_check":null,"customer":"cus_4PsDeNNph7uDl5","type":"Visa"}]},
  "default_card": "card_14H2V04DY8wO1agf2PweH4nx"
}

In stripe-ruby-mock, I'd love to see the :expand parameter be supported so that it returns objects that are marked as "expandable" in the Stripe API:
google chromescreensnapz344

Thanks.

Can't create a customer with a string plan id

Is this a bug? I'd be happy to make a pull request if it's not me that's doing something wrong

[7] pry(#<RSpec::Core::ExampleGroup::Nested_1::Nested_2::Nested_1>)> Stripe::Customer.create(description: 'foo', card: 'token', plan: :pro)
=> #<Stripe::Customer:0x3fda7a82c640 id=test_cus_9> JSON: {
  "id": "test_cus_9",
  "email": "[email protected]",
  "description": "foo",
  "object": "customer",
  "created": 1372126710,
  "livemode": false,
  "delinquent": false,
  "discount": null,
  "account_balance": 0,
  "cards": {"object":"list","count":1,"url":"/v1/customers/test_cus_9/cards","data":[{"id":"test_cc_10","object":"card","last4":"4242","type":"Visa","exp_month":4,"exp_year":2016,"fingerprint":"wXWJT135mEK107G8","customer":"test_cus_9","country":"US","name":"Johnny App","address_line1":null,"address_line2":null,"address_city":null,"address_state":null,"address_zip":null,"address_country":null,"cvc_check":null,"address_line1_check":null,"address_zip_check":null}]},
  "subscriptions": {"object":"list","count":1,"url":"/v1/customers/test_cus_9/subscriptions","data":[{"id":"test_su_11","current_period_start":1397929699,"current_period_end":1400521699,"status":"trialing","plan":{"id":"pro","interval":"month","name":"Pro","amount":5000,"currency":"usd","object":"plan","livemode":false,"interval_count":1,"trial_period_days":30},"cancel_at_period_end":false,"canceled_at":null,"ended_at":null,"start":1308595038,"object":"subscription","trial_start":1397929699,"trial_end":1400521699,"customer":"test_cus_9","quantity":1}]},
  "default_card": "test_cc_10",
  "plan": "pro"
}
[8] pry(#<RSpec::Core::ExampleGroup::Nested_1::Nested_2::Nested_1>)> Stripe::Customer.create(description: 'foo', card: 'token', plan: 'pro')
Stripe::InvalidRequestError: No such plan: pro
from /Users/alex/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/stripe-ruby-mock-1.10.1.6/lib/stripe_mock/instance.rb:97:in `assert_existance'

Missing items for new Customer

I ended up with the following monkey patch today and thought that it might be useful.

Basically, for Stripe::Customer.create(), I've added active_card when a card parameter is supplied, and I set subscription with a plan inside when a plan is provided. Clearly, the latter is a less than ideal solution, but it was sufficient for my purposes.

I've not provided a PR as I'm sure there's a better, more general way to do this.

module StripeMock
  module RequestHandlers
    module Customers

      def new_customer(route, method_url, params, headers)
        params[:id] ||= new_id('cus')
        cards = []
        if params[:card]
          cards << get_card_by_token(params.delete(:card))
          params[:default_card] = cards.first[:id]
          params[:active_card] = cards.first
        end
        if params[:plan]
          params[:subscription] = {
            id: 'su_999',
            plan: Stripe::Plan.create(
              amount: 1500,
              interval: 'month',
              name: 'plan_name',
              currency: 'usd',
              id: params[:plan]
            ),
            current_period_start: 1381050497,
            current_period_end: 1383728897
          }
          params.delete(:plan)
        end
        customers[ params[:id] ] = Data.mock_customer(cards, params)
      end

    end
  end
end

Support for Invoice#pay

It would be great to have support for the Invoice#pay method, as documented here:

https://stripe.com/docs/api/ruby#pay_invoice

I believe the JSON returned would be mostly the same as the existing JSON for the Invoice object, but with attempted and paid set to true, and charge set to the id of a charge object.

Subscription quantity still not correctly set

Failing test case:

it "correctly sets the quantity" do
  Stripe::Plan.create(
    :amount => 2500,
    :interval => 'month',
    :name => 'Test plan',
    :currency => 'usd',
    :id => 'silver',
    :statement_description => "testPlan"
  )
  customer = Stripe::Customer.create(id: 'test_customer_sub', card: 'tk')

  subscription = customer.subscriptions.create({:plan => "silver", quantity: 2})
  expect(subscription.quantity).to eq(2)
end

and the result:

Failure/Error: expect(subscription.quantity).to eq(2)

   expected: 2
        got: 1

   (compared using ==)

invoice line items

According to stripe documentation, the syntax should be Stripe::Invoice.retrieve({INVOICE_ID}).lines.all(), but receiving an error,

Stripe::InvalidRequestError: No such invoice: test_in_1/lines from /Users/liouyang/.rvm/gems/ruby-1.9.3-p484/gems/stripe-ruby-mock-1.10.1.6/lib/stripe_mock/instance.rb:97:in `assert_existance'

Multiple Subscription changes broke Stripe::Customer#update_subscription support

Hello,

The following commit removed support for the '/v1/customers/{CUSTOMER_ID}/subscription' endpoint:

1fd4908#diff-fe9a4c81b76150e0bf2da5cb7d208802L8

However, this endpoint is still supported by the API:

https://stripe.com/docs/api#intro
https://github.com/stripe/stripe-ruby/blob/master/lib/stripe/customer.rb#L38

Also, I cannot see, with the current (multiple) Subscriptions support in v1.10.1.2, how I am supposed to mock update of a subscription. The Stripe api docs suggest using 'customer#subscriptions', but the current mocking of the subscriptions array in the customer response object is incomplete - it does not contain a list of subscription objects (or subscription IDs, which are necessary to update them).

So, in other words, the old approach was removed, and the new approach does not work as far as I can see. Do you have the v1.10.1.2 version working to mock any production code which retrieves or updates subscriptions? If so, what exact calls are you using to do it?

Thanks,
-- Chad

Stripe::Customer.create with a coupon does not return a discount

Currently when a Stripe::Customer is created with a coupon attribute, a discount is not created and returned with the customer response. Instead, a coupon property is returned, but this does not match Stripe's live response.

Example:

coupon = 'stripe_4_lyfe'

Stripe::Coupon.create(
  percent_off: 25,
  duration: 'repeating',
  duration_in_months: 3,
  id: coupon
)

customer_card = {
  number: 4242424242424242,
  exp_month: 2,
  exp_year: Time.now.year.next,
  cvc: "314"
}

Stripe::Customer.create(card: customer_card, coupon: coupon)

With the mock server running:

{
  "id": "test_cus_5",
  "email": "[email protected]",
  "description": "an auto-generated stripe customer data mock",
  "object": "customer",
  "created": 1372126710,
  "livemode": false,
  "delinquent": false,
  "discount": null,
  "account_balance": 0,
  "cards": {"object":"list","count":1,"url":"/v1/customers/test_cus_5/cards","data":[{"id":"test_cc_6","object":"card","last4":"4242","type":"Visa","exp_month":4,"exp_year":2016,"fingerprint":"wXWJT135mEK107G8","customer":"test_cus_5","country":"US","name":"Johnny App","address_line1":null,"address_line2":null,"address_city":null,"address_state":null,"address_zip":null,"address_country":null,"cvc_check":null,"address_line1_check":null,"address_zip_check":null}]},
  "default_card": "test_cc_6",
  "coupon": "stripe_4_lyfe",
  "subscriptions": {"data":[],"count":0,"object":"list","url":"/v1/customers/test_cus_5/subscriptions"}
}

Without the mock server running:

{
  "id": "cus_3d82VayotGv2d6",
  "object": "customer",
  "created": 1394313303,
  "livemode": false,
  "description": null,
  "email": null,
  "delinquent": false,
  "metadata": {},
  "subscriptions": {"object":"list","count":0,"url":"/v1/customers/cus_3d82VayotGv2d6/subscriptions","data":[]},
  "discount": {"coupon":{"id":"stripe_4_lyfe","created":1394313289,"percent_off":25,"amount_off":null,"currency":null,"object":"coupon","livemode":false,"duration":"repeating","redeem_by":null,"max_redemptions":null,"times_redeemed":1,"duration_in_months":3,"valid":true,"metadata":{}},"start":1394313303,"object":"discount","customer":"cus_3d82VayotGv2d6","subscription":null,"end":1402262103},
  "account_balance": 0,
  "currency": null,
  "cards": {"object":"list","count":1,"url":"/v1/customers/cus_3d82VayotGv2d6/cards","data":[{"id":"card_103d82237mKPGzkIw2wcCYex","object":"card","last4":"4242","type":"Visa","exp_month":2,"exp_year":2015,"fingerprint":"BvtkZuO7Uuz75a75","customer":"cus_3d82VayotGv2d6","country":"US","name":null,"address_line1":null,"address_line2":null,"address_city":null,"address_state":null,"address_zip":null,"address_country":null,"cvc_check":"pass","address_line1_check":null,"address_zip_check":null}]},
  "default_card": "card_103d82237mKPGzkIw2wcCYex"
}

This is useful to have when testing that a coupon properly converts into a discount for the stripe customer. In my case, it's an integration test that wants to assert the presence of the discount after a user submitted a form with a valid stripe token and coupon.

Accepting :plan parameter when creating a customer

Hi,

According to the docs, you can pass a :plan parameter to the customer#create method.

https://stripe.com/docs/api/ruby#create_customer

But this gets ignored in the mock. A subscription is not made.

a = Stripe::Customer.create(:plan => 'small', card: token, email: 'mail')
=> #<Stripe::Customer:0x3ff4b26dd60c> JSON: {"id":"test_cus_3","email":"[email protected]","description":"an auto-generated stripe customer data mock","object":"customer","created":1372126710,"livemode":false,"delinquent":false,"subscription":null,"discount":null,"account_balance":0,"cards":{"object":"list","count":1,"url":"/v1/customers/test_cus_3/cards","data":[{"id":"test_cc_2","object":"card","last4":"9191","type":"Visa","exp_month":4,"exp_year":2015,"fingerprint":"wXWJT135mEK107G8","customer":"test_cus_3","country":"US","name":"Johnny App","address_line1":null,"address_line2":null,"address_city":null,"address_state":null,"address_zip":null,"address_country":null,"cvc_check":null,"address_line1_check":null,"address_zip_check":null}]},"default_card":"test_cc_2","plan":"small"}

a.subscription
=> nil

https://github.com/rebelidealist/stripe-ruby-mock/blob/master/lib/stripe_mock/request_handlers/customers.rb#L15

Stripe-Ruby-Mock is not failing invalid credit card numbers

Stripe-Ruby-Mock is generally working for me, but the following spec passes when I speak to the Stripe server directly, but fails when I use Stripe-Ruby-Mock.

    it "must have a valid credit card number" do
      login_as "customer"
      visit new_order_path(:product => "Retail Site Search")
      expect(find_field("order_product_id").value).to eq @product.id.to_s
      expect(page).to have_content User.last.email
      fill_in_order_fields
      click_on "submit_order"
      fill_in_standard_competitor_fields
      click_on "submit_order"
      click_on "submit_order"
      fill_in_credit_card_fields
      fill_in "order_number", :with => "4242424242424241"
      click_on "create_card"
      expect(page.current_path).to eq pay_order_path(Order.last)
      expect(ActionMailer::Base.deliveries.empty?).to be_truthy
      expect(page).to have_content "The credit card number you supplied was incorrect"
    end

It let's the number through as if it was valid.

Stripe sets this aside as a number that should always generate an incorrect card number code. See https://stripe.com/docs/testing

Issue with Stripe::Token

Trying to create a stripe token like so:

Stripe::Token.create({
      card: {
        number: "4222222222222222",
        exp_month: '09',
        exp_year: 2.years.since.year.to_s, # e.g. '2017'
      }
    })

Should return a Stripe::Token object with an #id method, which is the token id. Instead it returns:

#<Stripe::StripeObject:0x3fc738d8db48> JSON: {}

Not sure if I'm using this incorrectly or if Stripe::Token hasn't been implemented yet.
Thanks,

  • Graham

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.