Coder Social home page Coder Social logo

fake_stripe's Introduction

fake_stripe, a Stripe fake

This library is a way to test Stripe code without hitting Stripe's servers. It uses Capybara::Server and Webmock to intercept all of the calls from Stripe's Ruby library and returns JSON that the Stripe library can parse.

Installation

Gemfile

Add the fake_stripe Gem to the :test group in your Gemfile:

# Gemfile
group :test do
  gem 'fake_stripe'
end

Remember to run bundle install.

Stripe settings

Set the STRIPE_JS_HOST constant in an initializer:

# config/initializers/stripe.rb
Stripe.api_key = ENV['STRIPE_API_KEY']

unless defined? STRIPE_JS_HOST
  STRIPE_JS_HOST = 'https://js.stripe.com'
end

Include the Stripe JavaScript in your application template.

For Stripe.js v1:

# app/views/layouts/application.html.erb
<%= javascript_include_tag "#{STRIPE_JS_HOST}/v1/" %>

For Stripe.js v2:

# app/views/layouts/application.html.erb
<%= javascript_include_tag "#{STRIPE_JS_HOST}/v2/" %>

For Stripe.js v3:

# app/views/layouts/application.html.erb
<%= javascript_include_tag "#{STRIPE_JS_HOST}/v3/" %>

When the test suite runs fake_stripe will override the address for STRIPE_JS_HOST and serve up a local version of Stripe.js.

In Tests

Require the library in your spec support:

# spec/support/fake_stripe.rb
require 'fake_stripe'

RSpec.configure do |config|
  config.before(:each) do
    FakeStripe.stub_stripe
  end
end

Contributing

Please see CONTRIBUTING.md for more details.

fake_stripe's People

Contributors

alookatommorow avatar andrey-demidenko avatar calebhearth avatar cllns avatar composerinteralia avatar cpytel avatar danbee avatar dependabot[bot] avatar derekprior avatar gabebw avatar halogenandtoast avatar harlow avatar jayroh avatar jsteiner avatar mjankowski avatar nhippenmeyer avatar nickrivadeneira avatar paulthegeek avatar qrush avatar r00k avatar seanpdoyle avatar sgrif avatar tylerrockwell avatar waruboy 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

fake_stripe's Issues

Leverage the Stripe Gems test data

Looks like a lot of the responses are already stubbed out in the official Stripe Gem. See if we can leverage those. It would probably help avoid API drift as the Stripe Gem would also need to update if the Stripe API ever changes.

live copy of stripe.js is loaded instead of local version of stripe.js

Contrary to the README, fake_stripe is not intercepting requests to js.stripe.com when stripe.js is loaded in script tag on a page.

The former approach of specifying STRIPE_JS_HOST in javascript_include_tag works correctly, but the new approach of referencing the real stripe URL in javascript_include_tag does not work, since it is relying on WebMock to stub calls to js.stripe.com. This changed in the recently merged PR #29

WebMock cannot intercept http requests generated by a browser in a separate process (i.e. specs using capybara-webkit, poltergeist, selenium, etc.). This is why things like puffing-billy exist.

In theory, WebMock might work when using rack-test, but of course we're not using rack-test in tests that involve loading stripe.js

Here is a minimal rails app that illustrates the issue: https://github.com/naw/fake_stripe_example

The real copy of stripe.js (not the local one) is loaded. Therefore, the spec will pass if you are connected to the internet, but fail when you are disconnected. If fake_stripe were actually intercepting the request with WebMock, then the local version would be loaded even when you are disconnected from the internet, and the spec should pass (it doesn't).

I recommend reverting #29

@seanpdoyle

Stripe Customer retrieve stub and expand default_source option

The customer retrieve stub currently doesn't support Stripe's expand: ['default_source'] option:

customer = Stripe::Customer.retrieve(id: 'customer-id-here', expand: ['default_source'])

With fake_stripe and Stripe customer = Stripe::Customer.retrieve(id: 'customer-id-here') (no expand option) the customer.default_source returns a String (the id of the default payment source).

However with Stripe, but not fake_stripe customer = Stripe::Customer.retrieve(id: 'customer-id-here', expand: ['default_source]) (note the expand option) the customer.default_source returns the populated payment source object (not just the string id of the payment source). fake_stripe only returns the String id of the payment source.

(stripe-ruby-mock has a similar issue that may be useful stripe-ruby-mock/stripe-ruby-mock#109 )

Fixtures out of date

It looks like the list_customers fixture being used as the response to create customer calls is out of date. We had to override with a copy of the JSON from the API reference.

react-stripe-js is unable to create individual elements

So we're using the react-stripe-js to render Stripe elements on the page. When we render the Stripe elements using the JavaScript returned by the STRIPE_JS_HOST/v3/, it renders every component each time we call create. Please check out the example below.

Here is a code example.

    this.stripe = Stripe(stripeApiKey);
    const elements = this.stripe.elements();

    this.cardNumber = elements.create('cardNumber', {
      placeholder: this.cardTarget.dataset.placeholder,
      style: this.style,
    });
    this.cardExpiry = elements.create('cardExpiry', {
      placeholder: this.dateTarget.dataset.placeholder,
      style: this.style,
    });
    this.cardCvc = elements.create('cardCvc', {
      placeholder: this.cvcTarget.dataset.placeholder,
      style: this.style,
    });
    this.postalCode = elements.create('postalCode', {
      placeholder: this.postalCodeTarget.dataset.placeholder,
      style: this.style,
    });

Expected Result

Screen Shot 2020-04-14 at 4 58 57 PM

Actual Result

Screen Shot 2020-04-14 at 4 58 46 PM

It looks like we have the parameters, we just need to dynamically render the correct fields:
https://github.com/thoughtbot/fake_stripe/blob/master/lib/fake_stripe/assets/v3.js#L24

Happy to submit a PR if other people are seeing this issue as well.

Sinatra endpoints always return the same UUIDs

Hi, I ran into this problem while writing a system test for a feature that issues multiple Stripe transactions. Post submission, we save the returned transaction_ids to a column with a unique index. Since the create_transaction fixture returned by stub_app always returns the same UUID, this throws an error on the second transaction submission.

Would it be problematic to return a random UUID instead?

Customer data in fixture files

Lauren Lusher from Stripe reached out to me via email asking to remove personal email address from the example payloads. It looks like some customer data leaked into the codebase with this commit:

f2ae538

We should cut a new version of this gem with all test data sanitized and yank the pervious versions from Ruby Gems. I'm wondering if its also worth squashing those commits out of git history?

cc @jferris @adarsh @cpytel

Original email from Lauren (I'm not sure how it got on Omniref... do they just scrape Rubygems?)

Hi Harlow,

I work with Stripe and I'm reaching out about the fake_stripe gem you created on Omniref. Sorry to reach out to you out of the blue like this. One of our users got in touch with us recently, as he found that his personal email address was being used in some of your example documentation, pulled from Stripe's API docs:

<REDACTED>

It's become evident that the user didn't realize he was using Stripe's public test API keys to create test charges, and that the information would be publicly available later on. We use test data from the account associated with our test API key to populate Stripe's documentation. The data displayed is chosen at random, and unfortunately the test charges and customer objects he created were displayed when you copied our documentation. 

I'm wondering if it would be possible for you to use different examples on Omniref. We are working on improving this flow and have removed all instances of the email address from the account, and I believe it would put the developer's mind at ease to see his personal email address removed from Omniref. 

Look forward to hearing from you.

Best,
Lauren

AuthenticationError

I'm not sure what I'm doing wrong... Do you have any ideas/suggestions based on my experiences, below?

I've got an API-only Rails app that is integrated with Stripe. My spec has this line in it:

stripe_customer = Stripe::Customer.create

which causes this error:

1) Subscription is created in Stripe
   Failure/Error: stripe_customer = Stripe::Customer.create

   Stripe::AuthenticationError:
     Invalid API Key provided: ****_******_***_KEY
   # /Users/me/.rvm/gems/ruby-2.3.0@project/gems/stripe-1.43.1/lib/stripe.rb:333:in `handle_api_error'
   # /Users/me/.rvm/gems/ruby-2.3.0@project/gems/stripe-1.43.1/lib/stripe.rb:209:in `rescue in execute_request_with_rescues'
   # /Users/me/.rvm/gems/ruby-2.3.0@project/gems/stripe-1.43.1/lib/stripe.rb:195:in `execute_request_with_rescues'
   # /Users/me/.rvm/gems/ruby-2.3.0@project/gems/stripe-1.43.1/lib/stripe.rb:148:in `request'
   # /Users/me/.rvm/gems/ruby-2.3.0@project/gems/stripe-1.43.1/lib/stripe/api_operations/request.rb:15:in `request'
   # /Users/me/.rvm/gems/ruby-2.3.0@project/gems/stripe-1.43.1/lib/stripe/api_operations/create.rb:5:in `create'
   # ./spec/models/subscription_spec.rb:69:in `block (3 levels) in <top (required)>'
   # ------------------
   # --- Caused by: ---
   # RestClient::Unauthorized:
   #   401 Unauthorized
   #   /Users/me/.rvm/gems/ruby-2.3.0@project/gems/rest-client-1.8.0/lib/restclient/abstract_response.rb:74:in `return!'

I did some searching around GitHub to see how others are using FakeStripe, and I came across this method which suggests to me that I still need to write all my own allow calls. I'm not sure if that's correct, though.

v0.2.0 only supports Capybara v3

We had Capybara v2 installed and running FakeStripe.stub_stripe caused a Capybara error about getaddrinfo.

I'm guessing this was due to #88. I think there should be a version restriction on Capybara to be v3+ in this gemspec.

I'd open that PR but I don't have the time right now to make sure that's exactly the problem (and the right fix).

No support for Js v3

This gem is great, thanks for contributing. Currently Stripe offers v3 API and would be nice to have it here too

Stripe.card.validateExpiry out of sync with original Stripe JS

Stripe's original Stripe.card.validateExpiry method allows various signatures that don't seem to be supported in this fake:

Stripe.card.validateExpiry(12, 17) // stripe.js supports 2 digit years
Stripe.card.validateExpiry('12/17') // stripe.js supports passing the expiration date as a single string
Stripe.card.validateExpiry('12/2017') // same

On the other hand, it seems to allow something that's not allowed by Stripe:

Stripe.card.validateExpiry(-1, 2018) // this fake functionally turns this into 12/2017 but stripe.js doesn't support months < 1

I think the only issue here is that the JavaScript needs to be updated based on Stripe's original JS (https://js.stripe.com/v2/stripe-debug.js).

Implement `Stripe.card.createToken` in the fake JS

Stripe documentation says to use Stripe.card.createToken but this won't work with FakeStripe. We have to use Stripe.createToken, which does work for both the fake and real implementations. We should aim to be consistent with the docs, though.

Update fixtures to enable use of sources instead of cards

According to the Stripe API docs, cards can be created in the following manner:

customer = Stripe::Customer.retrieve("cus_8r5Y28tCBr2Gxd")
customer.sources.create(:source => "tok_18YMiEI24udUzZHL2PJkS73T")

In my controller I have the following code:

stripe_customer = Stripe::Customer.create(email: params[:email])
stripe_customer.sources.create(source: params[:stripe_token])

which raises the following error in my spec:

Stripe::APIError:
       Invalid response object from API: "<!DOCTYPE html>\n<html>\n<head>\n  <style type=\"text/css\">\n  body { text-align:center;font-family:helvetica,arial;font-size:22px;\n    color:#888;margin:20px}\n  #c {margin:0 auto;width:500px;text-align:left}\n  </style>\n</head>\n<body>\n  <h2>Sinatra doesn&rsquo;t know this ditty.</h2>\n  <img src='https://api.stripe.com/__sinatra__/404.png'>\n  <div id=\"c\">\n    Try this:\n    <pre># in stub_app.rb\nclass FakeStripe::StubApp\n  post &#x27;&#x2F;v1&#x2F;customers&#x2F;abcdefghijklmnop&#x2F;sources&#x27; do\n    &quot;Hello World&quot;\n  end\nend\n</pre>\n  </div>\n</body>\n</html>\n" (HTTP response code was 404)

However, if I change the syntax (replacing sources with cards) as follows:

stripe_customer = Stripe::Customer.create(email: params[:email])
stripe_customer.cards.create(source: params[:stripe_token])

I do not get the error. The customer fixtures should be updated to mirror what is actually being returned from the Stripe API:

{
  "id": "cus_8rU9hek1yGXX91",
  "object": "customer",
  "account_balance": 0,
  "created": 1469122908,
  "currency": "usd",
  "default_source": "card_18ZlBAI24udUzZHLiISVRkqR",
  "delinquent": false,
  "description": null,
  "discount": null,
  "email": "[email protected]",
  "livemode": false,
  "metadata": {
  },
  "shipping": null,
  "sources": {
    "object": "list",
    "data": [
      {
        "id": "card_18ZlBAI24udUzZHLiISVRkqR",
        "object": "card",
        "address_city": "",
        "address_country": null,
        "address_line1": "",
        "address_line1_check": null,
        "address_line2": "",
        "address_state": "",
        "address_zip": "",
        "address_zip_check": null,
        "brand": "Visa",
        "country": "US",
        "customer": "cus_8rU9hek1yGXX91",
        "cvc_check": "pass",
        "dynamic_last4": null,
        "exp_month": 12,
        "exp_year": 2019,
        "funding": "credit",
        "last4": "4242",
        "metadata": {
        },
        "name": null,
        "tokenization_method": null
      }
    ],
    "has_more": false,
    "total_count": 1,
    "url": "/v1/customers/cus_8rU9hek1yGXX91/sources"
  },
  "subscriptions": {
    "object": "list",
    "data": [

    ],
    "has_more": false,
    "total_count": 0,
    "url": "/v1/customers/cus_8rU9hek1yGXX91/subscriptions"
  }
}

TRAVIS issue only

I have below error on my travis server. It's fine on my local.
NoMethodError: undefined method `closed?' for nil:NilClass

the code that reports is something like this.

FakeStripe.stub_stripe
Stripe::Token.create(last4: "9191", exp_year: 1984).id

Rails 5 compatibility

I tried to set up fake_stripe in a fresh Rails 5 app, but ran into some dependency problems with Sinatra and Rack. Rails 5 requires Rack 2.0 or higher, and the most recent version of Sinatra requires Rack ~> 1.5. Bundler resolves the Sinatra version to 1.0 because it has a more optimistic requirement for Rack (>= 1.0). This older version of Sinatra does not work because of this error.

In short, I don't think we can make fake_stripe compatible with Rails 5 until Sinatra is compatible with Rack 2.0+.

Prepare next patch release

An application I'm working on needs the following commit:

e4f98ad

I now tie its Gemfile to the master branch for now, but I plan to release v0.0.11 from latest master.

I announce this here in case you have any feedback before I do so. Thank you!

cc @gylaz: can you please add me as an owner in rubygems? You could also release it yourself if you prefer. Thank you!

Supporting `paymentRequest` and `createPaymentMethod`

Hey there! Thanks for making this wonderful gem.

I've already started working on a fork which would support the paymentRequest and createPaymentMethod functions on the stripe object, but I thought I should just check before I get too deep to see if this is something someone has already done or maybe has started on their own fork. And also gather some interest in case, if I do finish, I know whether to make a PR or not.

Thanks!

Using gem blocks all external HTTP requests

Added FakeStripe to a test suite not currently using WebMock and it blocked a number of calls to third-party services. Whilst I eventually want to mock all those calls, I didn't expect this gem to block anything beyond Stripe. Looks like the problem line is this in the WebMock initialiser.

WebMock.disable_net_connect!(allow_localhost: true)

I can put in a PR to remove that line but wanted to check if there was a reason it was in there? My assumption is that so the gem would catch any requests to Stripe that didn't match the two stubbed requests:

# fake_stripe/fake_stripe.rb:35
    stub_request(:any, /api.stripe.com/).to_rack(FakeStripe::StubApp)
    stub_request(:any, /js.stripe.com/).to_rack(FakeStripe::StubApp)

Store reference to last transaction

Noticed that some of the other Stripe implementations are storing the "last charge/customer/etc" for reference later. Figure out whats needed in this use-case and replicate.

Validate inputs to charge

Fake stripe should validate the inputs to charge similarly to Stripe and should raise the same errors if appropriate.

For instance, raise if there is no token. Raise if amount is not a positive integer. Raise if there's no currency, etc.

Improve reliability of FakeStripe::Utils.find_available_port

Consider updating FakeStripe::Utils.find_available_port to reduce the likelihood of Errno::EADDRINUSE errors when the port was not released in time by the server used to find it.

def self.find_available_port
server = TCPServer.new(FIND_AVAILABLE_PORT)
server.addr[1]
ensure
server.close if server
end

Consider borrowing from Capybara's recently tweaked port finding code to check the server was closed:

https://github.com/teamcapybara/capybara/blob/6b2d6a1012138bf1230c0832dc17e36ea52a053a/lib/capybara/server.rb#L107-L122

Related discussion: teamcapybara/capybara#2244

Testing Incorrect Coupon Codes

How would I tests incorrect coupon codes in the controller? When I use, "Stripe::Coupon.retrieve("dajkfjkadfjkadfakdfkjadjkfjkadf")", it goes back as a valid coupon with the id of "25OFF"?

context "with invalid coupon" do
  it "should not set a coupon in session" do
    get :show, id: "1OFF"

    expect(session[:coupon]).to be_nil
    expect(flash[:error]).to eq I18n.t("coupons.flashes.invalid")
    expect(response).to redirect_to(root_path)
  end
end

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.