diff --git a/.document b/.document deleted file mode 100644 index c91e2150a..000000000 --- a/.document +++ /dev/null @@ -1,4 +0,0 @@ -lib/**/*.rb -README.rdoc -ChangeLog.rdoc -LICENSE.txt diff --git a/.gitignore b/.gitignore index 9689e9eea..fd2209439 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ html/ pkg/ +.DS_Store diff --git a/LICENSE.txt b/LICENSE.txt index c775c9dbe..1d131067f 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,3 +1,5 @@ +(The MIT License) + Copyright (c) 2013 Gilbert Permission is hereby granted, free of charge, to any person obtaining diff --git a/README.md b/README.md new file mode 100644 index 000000000..9f15dc2c0 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# stripe-ruby-mock + +* Homepage: https://github.com/mindeavor/stripe-ruby-mock#readme +* Issues: https://github.com/mindeavor/stripe-ruby-mock/issues + +## Install + + $ gem install stripe-ruby-mock + +## Features + +* Easily test against stripe errors +* No stripe server access required + +## Description + +** *WARNING: THIS LIBRARY IS INCOMPLETE* ** + +At its core, this library overrides [stripe-ruby's](https://github.com/stripe/stripe-ruby) +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' + require 'stripe_mock' + + describe MyApp do + before { StripeMock.start } + after { StripeMock.stop } + + it "should create a stripe customer" do + + # This doesn't touch stripe's servers nor the internet! + customer = Stripe::Customer.create({ + email: 'johnny@appleseed.com', + card: 'void_card_token' + }) + expect(customer.email).to eq('johnny@appleseed.com') + end + end + +## TODO + +* Cover all stripe urls/methods +* Mock stripe error responses +* Create hash for storing/retrieving stripe objects in-memory + +## Copyright + +Copyright (c) 2013 Gilbert + +See LICENSE.txt for details. diff --git a/README.rdoc b/README.rdoc deleted file mode 100644 index 7be3d5da7..000000000 --- a/README.rdoc +++ /dev/null @@ -1,28 +0,0 @@ -= stripe-ruby-mock - -* {Homepage}[https://github.com/mindeavor/stripe-ruby-mock#readme] -* {Issues}[https://github.com/mindeavor/stripe-ruby-mock/issues] -* {Documentation}[http://rubydoc.info/gems/stripe-ruby-mock/frames] -* {Email}[mailto:gilbertbgarza at gmail.com] - -== Description - -TODO: Description - -== Features - -== Examples - - require 'stripe/mock' - -== Requirements - -== Install - - $ gem install stripe-ruby-mock - -== Copyright - -Copyright (c) 2013 Gilbert - -See LICENSE.txt for details. diff --git a/Rakefile b/Rakefile index df6d715c4..f1687e275 100644 --- a/Rakefile +++ b/Rakefile @@ -13,19 +13,6 @@ rescue LoadError => e warn "Run `gem install rubygems-tasks` to install Gem::Tasks." end -begin - gem 'rdoc', '~> 3.0' - require 'rdoc/task' - - RDoc::Task.new do |rdoc| - rdoc.title = "stripe-ruby-mock" - end -rescue LoadError => e - warn e.message - warn "Run `gem install rdoc` to install 'rdoc/task'." -end -task :doc => :rdoc - begin gem 'rspec', '~> 2.4' require 'rspec/core/rake_task' diff --git a/lib/stripe/mock.rb b/lib/stripe/mock.rb deleted file mode 100644 index 20a9346e6..000000000 --- a/lib/stripe/mock.rb +++ /dev/null @@ -1 +0,0 @@ -require 'stripe/mock/version' diff --git a/lib/stripe/mock/version.rb b/lib/stripe/mock/version.rb deleted file mode 100644 index 54ed2d700..000000000 --- a/lib/stripe/mock/version.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Stripe - module Mock - # stripe-ruby-mock version - VERSION = "0.1.0" - end -end diff --git a/lib/stripe_mock.rb b/lib/stripe_mock.rb new file mode 100644 index 000000000..c2b49768c --- /dev/null +++ b/lib/stripe_mock.rb @@ -0,0 +1,29 @@ +require 'stripe_mock/version' +require 'stripe_mock/data' +require 'stripe_mock/methods' + +module StripeMock + + @@init = false + @@enabled = false + + def self.start + if @@init == false + @@request_method = Stripe.method(:request) + @@init = true + end + alias_stripe_method :request, Methods.method(:mock_request) + @@enabled = true + end + + def self.stop + return unless @@enabled == true + alias_stripe_method :request, @@request_method + @@enabled = false + end + + def self.alias_stripe_method(new_name, method_object) + Stripe.define_singleton_method(new_name) {|*args| method_object.call(*args) } + end + +end diff --git a/lib/stripe_mock/data.rb b/lib/stripe_mock/data.rb new file mode 100644 index 000000000..e87137d74 --- /dev/null +++ b/lib/stripe_mock/data.rb @@ -0,0 +1,268 @@ +module StripeMock + module Data + + def self.test_customer(params) + { + :subscription_history => [], + :bills => [], + :charges => [], + :livemode => false, + :object => "customer", + :id => "c_test_customer", + :active_card => { + :type => "Visa", + :last4 => "4242", + :exp_month => 11, + :country => "US", + :exp_year => 2012, + :id => "cc_test_card", + :object => "card" + }, + :created => 1304114758 + }.merge(params) + end + + def self.test_customer_array + { + :data => [test_customer, test_customer, test_customer], + :object => 'list', + :url => '/v1/customers' + } + end + + def self.test_charge(params={}) + { + :refunded => false, + :paid => true, + :amount => 100, + :card => { + :type => "Visa", + :last4 => "4242", + :exp_month => 11, + :country => "US", + :exp_year => 2012, + :id => "cc_test_card", + :object => "card" + }, + :id => "ch_test_charge", + :reason => "execute_charge", + :livemode => false, + :currency => "usd", + :object => "charge", + :created => 1304114826 + }.merge(params) + end + + def self.test_charge_array + { + :data => [test_charge, test_charge, test_charge], + :object => 'list', + :url => '/v1/charges' + } + end + + def self.test_card(params={}) + { + :type => "Visa", + :last4 => "4242", + :exp_month => 11, + :country => "US", + :exp_year => 2012, + :id => "cc_test_card", + :object => "card" + }.merge(params) + end + + def self.test_coupon(params={}) + { + :duration => 'repeating', + :duration_in_months => 3, + :percent_off => 25, + :id => "co_test_coupon", + :object => "coupon" + }.merge(params) + end + + #FIXME nested overrides would be better than hardcoding plan_id + def self.test_subscription(plan_id="gold") + { + :current_period_end => 1308681468, + :status => "trialing", + :plan => { + :interval => "month", + :amount => 7500, + :trial_period_days => 30, + :object => "plan", + :identifier => plan_id + }, + :current_period_start => 1308595038, + :start => 1308595038, + :object => "subscription", + :trial_start => 1308595038, + :trial_end => 1308681468, + :customer => "c_test_customer" + } + end + + def self.test_invoice(params={}) + { + :id => 'in_test_invoice', + :object => 'invoice', + :livemode => false, + :amount_due => 1000, + :attempt_count => 0, + :attempted => false, + :closed => false, + :currency => 'usd', + :customer => 'c_test_customer', + :date => 1349738950, + :lines => { + "invoiceitems" => [ + { + :id => 'ii_test_invoice_item', + :object => '', + :livemode => false, + :amount => 1000, + :currency => 'usd', + :customer => 'c_test_customer', + :date => 1349738950, + :description => "A Test Invoice Item", + :invoice => 'in_test_invoice' + }, + ], + }, + :paid => false, + :period_end => 1349738950, + :period_start => 1349738950, + :starting_balance => 0, + :subtotal => 1000, + :total => 1000, + :charge => nil, + :discount => nil, + :ending_balance => nil, + :next_payemnt_attempt => 1349825350, + }.merge(params) + end + + def self.test_paid_invoice + test_invoice.merge({ + :attempt_count => 1, + :attempted => true, + :closed => true, + :paid => true, + :charge => 'ch_test_charge', + :ending_balance => 0, + :next_payment_attempt => nil, + }) + end + + def self.test_invoice_customer_array + { + :data => [test_invoice], + :object => 'list', + :url => '/v1/invoices?customer=test_customer' + } + end + + def self.test_recipient(params={}) + { + :name => "Stripe User", + :type => "individual", + :livemode => false, + :object => "recipient", + :id => "rp_test_recipient", + :active_account => { + :last4 => "6789", + :bank_name => "STRIPE TEST BANK", + :country => "US", + :object => "bank_account" + }, + :created => 1304114758, + :verified => true + }.merge(params) + end + + def self.test_recipient_array + { + :data => [test_recipient, test_recipient, test_recipient], + :object => 'list', + :url => '/v1/recipients' + } + end + + def self.test_transfer(params={}) + { + :status => 'pending', + :amount => 100, + :account => { + :object => 'bank_account', + :country => 'US', + :bank_name => 'STRIPE TEST BANK', + :last4 => '6789' + }, + :recipient => 'test_recipient', + :fee => 0, + :fee_details => [], + :id => "tr_test_transfer", + :livemode => false, + :currency => "usd", + :object => "transfer", + :date => 1304114826 + }.merge(params) + end + + def self.test_transfer_array + { + :data => [test_transfer, test_transfer, test_transfer], + :object => 'list', + :url => '/v1/transfers' + } + end + + def self.test_invalid_api_key_error + { + "error" => { + "type" => "invalid_request_error", + "message" => "Invalid API Key provided: invalid" + } + } + end + + def self.test_invalid_exp_year_error + { + "error" => { + "code" => "invalid_expiry_year", + "param" => "exp_year", + "type" => "card_error", + "message" => "Your card's expiration year is invalid" + } + } + end + + def self.test_missing_id_error + { + :error => { + :param => "id", + :type => "invalid_request_error", + :message => "Missing id" + } + } + end + + def self.test_api_error + { + :error => { + :type => "api_error" + } + } + end + + def self.test_delete_discount_response + { + :deleted => true, + :id => "di_test_coupon" + } + end + + end +end diff --git a/lib/stripe_mock/methods.rb b/lib/stripe_mock/methods.rb new file mode 100644 index 000000000..6d42573e2 --- /dev/null +++ b/lib/stripe_mock/methods.rb @@ -0,0 +1,25 @@ +module StripeMock + module Methods + + def self.mock_request(method, url, api_key, params={}, headers={}) + return {} if method == :xtest + + # Ordered from most specific to least specific + case "#{method} #{url}" + when 'post /v1/customers' + Data.test_customer(params) + when 'post /v1/invoiceitems' + Data.test_invoice(params) + when %r{post /v1/customers/(.*)/subscription} + Data.test_subscription(params[:plan]) + when %r{get /v1/customers/(.*)} + Data.test_customer :id => $1 + else + puts "WARNING: Unrecognized method + url: [#{method} #{url}]" + puts " params: #{params}" + {} + end + end + + end +end diff --git a/lib/stripe_mock/version.rb b/lib/stripe_mock/version.rb new file mode 100644 index 000000000..9991f3172 --- /dev/null +++ b/lib/stripe_mock/version.rb @@ -0,0 +1,4 @@ +module StripeMock + # stripe-ruby-mock version + VERSION = "1.8.1" +end diff --git a/spec/mock_spec.rb b/spec/mock_spec.rb index 1f0dcd82a..7c8b13716 100644 --- a/spec/mock_spec.rb +++ b/spec/mock_spec.rb @@ -1,8 +1,54 @@ require 'spec_helper' -require 'stripe/mock' +require 'stripe_mock' -describe Stripe::Mock do - it "should have a VERSION constant" do - subject.const_get('VERSION').should_not be_empty +describe StripeMock do + + before { StripeMock.start } + after { StripeMock.stop } + + it "should override stripe's request method" do + Stripe.request(:xtest, '/', 'abcde') # no error + end + + it "should revert overriding stripe's request method" do + Stripe.request(:xtest, '/', 'abcde') # no error + StripeMock.stop + expect { Stripe.request(:x, '/', 'abcde') }.to raise_error + end + + it "should create a stripe customer" do + customer = Stripe::Customer.create({ + email: 'johnny@appleseed.com', + card: 'some_card_token', + description: "a description" + }) + expect(customer.email).to eq('johnny@appleseed.com') + expect(customer.description).to eq('a description') + end + + it "should retrieve a stripe customer" do + customer = Stripe::Customer.retrieve("test_customer") + expect(customer.id).to eq('test_customer') end + + it "should update a stripe customer's subscription" do + customer = Stripe::Customer.retrieve("test_customer") + sub = customer.update_subscription({ :plan => 'silver' }) + + expect(sub.object).to eq('subscription') + expect(sub.plan.identifier).to eq('silver') + end + + it "should create a stripe invoice item" do + invoice = Stripe::InvoiceItem.create({ + amount: 1099, + customer: 1234, + currency: 'USD', + description: "invoice desc" + }, 'abcde') + + expect(invoice.amount).to eq(1099) + expect(invoice.description).to eq('invoice desc') + end + end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9ce124acf..438fd8522 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,4 @@ gem 'rspec', '~> 2.4' require 'rspec' -require 'stripe/mock/version' - -include Stripe::Mock +require 'stripe' +require 'stripe_mock/version' diff --git a/stripe-ruby-mock.gemspec b/stripe-ruby-mock.gemspec index ab2a8da94..3df531ecc 100644 --- a/stripe-ruby-mock.gemspec +++ b/stripe-ruby-mock.gemspec @@ -1,12 +1,12 @@ # -*- encoding: utf-8 -*- -require File.expand_path('../lib/stripe/mock/version', __FILE__) +require File.expand_path('../lib/stripe_mock/version', __FILE__) Gem::Specification.new do |gem| gem.name = "stripe-ruby-mock" - gem.version = Stripe::Mock::VERSION - gem.summary = %q{TODO: Summary} - gem.description = %q{TODO: Description} + gem.version = StripeMock::VERSION + gem.summary = %q{TDD with stripe} + gem.description = %q{A drop-in library to test stripe without hitting their servers} gem.license = "MIT" gem.authors = ["Gilbert"] gem.email = "gilbertbgarza@gmail.com" @@ -17,7 +17,8 @@ Gem::Specification.new do |gem| gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.require_paths = ['lib'] - gem.add_development_dependency 'rdoc', '~> 3.0' + gem.add_dependency 'stripe', '~> 1.8.1' + gem.add_development_dependency 'rspec', '~> 2.4' gem.add_development_dependency 'rubygems-tasks', '~> 0.2' end