Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Stripe Checkout.js Feature Spec with Puffing Billy #101

Open
wants to merge 39 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1d13483
Move puffing billy cache to http_cache/frontend
eliotsykes Dec 6, 2015
8f08bba
Introduce role column on User
eliotsykes Dec 6, 2015
bbcf8d0
Move login method to LoginHelper
eliotsykes Dec 6, 2015
d2d5c10
Notes on Stripe testing
eliotsykes Dec 6, 2015
e3311e3
Tidied vcr config
eliotsykes Dec 6, 2015
b0d360b
Put test standard user in seeds
eliotsykes Dec 6, 2015
d1c9f4e
StripeHelper
eliotsykes Dec 6, 2015
ea133f7
Correct puffing billy committed config
eliotsykes Dec 6, 2015
7789139
[WIP] User Upgrades Feature Spec
eliotsykes Dec 6, 2015
75cc8ed
[WIP] Stripe Checkout.js form
eliotsykes Dec 6, 2015
d011d51
Puffing Billy+VCR user-agent ignore host logic and BILLY_RECORDING en…
eliotsykes Dec 11, 2015
08d1258
Use create_with and find_or_create_by! to seed User in dev
eliotsykes Dec 12, 2015
43db5a4
Capybara.using_wait_time whilst recording Stripe interactions
eliotsykes Dec 12, 2015
11e4975
Ignore params for some Stripe URLs
eliotsykes Dec 12, 2015
b135f20
Use form_tag to get CSRF hidden field automatically
eliotsykes Dec 12, 2015
5481b90
Introduce BillyCache.use_billy_cache for puffing billy
eliotsykes Dec 12, 2015
7f54802
Use a Puffing Billy cache scope
eliotsykes Dec 12, 2015
a4b9aab
Introduce merge_cached_responses_whitelist
eliotsykes Dec 12, 2015
aa4824d
Add user_upgrades_spec.rb feature spec to README
eliotsykes Dec 12, 2015
920df7a
Use puffing_billy_driver_active? method
eliotsykes Dec 12, 2015
f7c6331
Upgrade selenium-webdriver to work with latest Firefox
eliotsykes Jan 25, 2016
7b11ec8
Tweak puffing-billy config to work with Stripe checkout.js
eliotsykes Jan 25, 2016
46ae121
Rename use_billy_cache to intention-revealing with_browser_responses
eliotsykes Jan 25, 2016
04f461c
Rename http_cache/frontend to http_cache/browser
eliotsykes Jan 26, 2016
1218eaa
Monkey Patch Billy::Config.after_cache_handles_request to handle CORS…
eliotsykes Jan 26, 2016
21dc3fc
frontend dir renamed to browser
eliotsykes Jan 26, 2016
4bc64c5
Readability tweaks for feature spec
eliotsykes Jan 26, 2016
408aaa3
http_cache/frontend -> http_cache/browser
eliotsykes Jan 26, 2016
739d214
Move Puffing Billy extensions to dedicated file
eliotsykes Jan 28, 2016
8fb7b4b
Upgrade puffing-billy to 0.6.2 from 0.5.1
eliotsykes Jan 28, 2016
2a79877
Add User#upgradeable? and User#standard? methods
eliotsykes Jan 28, 2016
7495570
Introduce User#upgrade method
eliotsykes Jan 28, 2016
095c81d
Configure Stripe API key
eliotsykes Jan 29, 2016
8801910
Install Stripe gem
eliotsykes Jan 29, 2016
32376f0
Move vcr cache dir to http_cache/server
eliotsykes Jan 29, 2016
c4acc0f
Strict VCR config
eliotsykes Jan 29, 2016
1d9a57f
Improve check for detecting when VCR should ignore request
eliotsykes Jan 29, 2016
99c79d9
Disable all HTTP with Webmock unless ENV['RECORD']
eliotsykes Jan 29, 2016
3e424b5
Introduce HttpRecord.off?/on? toggle with ENV['RECORD']
eliotsykes Jan 30, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ gem 'sqlite3'
gem 'turbolinks'
gem 'uglifier', '>= 1.3.0'
gem 'symmetric-encryption', '~> 3.8.1'
gem 'stripe'

gem 'quiet_assets', group: :development

Expand Down
36 changes: 26 additions & 10 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ GEM
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.3.8)
addressable (2.4.0)
arel (6.0.2)
bcrypt (3.1.10)
binding_of_caller (0.7.2)
Expand All @@ -50,7 +50,7 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
childprocess (0.5.6)
childprocess (0.5.9)
ffi (~> 1.0, >= 1.0.11)
cliver (0.3.2)
coderay (1.1.0)
Expand All @@ -64,7 +64,7 @@ GEM
execjs
coffee-script-source (1.9.1.1)
columnize (0.9.0)
cookiejar (0.3.2)
cookiejar (0.3.0)
crack (0.4.2)
safe_yaml (~> 1.0.0)
database_cleaner (1.4.1)
Expand All @@ -79,21 +79,23 @@ GEM
thread_safe (~> 0.1)
warden (~> 1.2.3)
diff-lcs (1.2.5)
em-http-request (1.1.2)
domain_name (0.5.25)
unf (>= 0.0.5, < 1.0.0)
em-http-request (1.1.3)
addressable (>= 2.3.4)
cookiejar
cookiejar (<= 0.3.0)
em-socksify (>= 0.3)
eventmachine (>= 1.0.3)
http_parser.rb (>= 0.6.0)
em-socksify (0.3.0)
em-socksify (0.3.1)
eventmachine (>= 1.0.0.beta.4)
em-synchrony (1.0.4)
eventmachine (>= 1.0.0.beta.1)
email_spec (1.6.0)
launchy (~> 2.1)
mail (~> 2.2)
erubis (2.7.0)
eventmachine (1.0.7)
eventmachine (1.0.9.1)
eventmachine_httpserver (0.2.1)
execjs (2.5.2)
factory_girl (4.5.0)
Expand All @@ -105,6 +107,8 @@ GEM
globalid (0.3.5)
activesupport (>= 4.1.0)
hike (1.2.3)
http-cookie (1.0.2)
domain_name (~> 0.5)
http_parser.rb (0.6.0)
i18n (0.7.0)
interception (0.5)
Expand All @@ -124,6 +128,7 @@ GEM
mini_portile (0.6.2)
minitest (5.7.0)
multi_json (1.11.2)
netrc (0.11.0)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
orm_adapter (0.5.0)
Expand All @@ -144,11 +149,11 @@ GEM
pry-stack_explorer (0.4.9.2)
binding_of_caller (>= 0.7)
pry (>= 0.9.11)
puffing-billy (0.5.1)
puffing-billy (0.6.2)
addressable
em-http-request (~> 1.1.0)
em-synchrony
eventmachine
eventmachine (~> 1.0.4)
eventmachine_httpserver
http_parser.rb (~> 0.6.0)
multi_json
Expand Down Expand Up @@ -184,6 +189,10 @@ GEM
rake (10.4.2)
responders (2.1.0)
railties (>= 4.2.0, < 5)
rest-client (1.8.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rspec-core (3.3.2)
rspec-support (~> 3.3.0)
rspec-expectations (3.3.1)
Expand All @@ -209,7 +218,7 @@ GEM
sass (~> 3.2.2)
sprockets (~> 2.8, < 3.0)
sprockets-rails (~> 2.0)
selenium-webdriver (2.46.2)
selenium-webdriver (2.49.0)
childprocess (~> 0.5)
multi_json (~> 1.0)
rubyzip (~> 1.0)
Expand All @@ -230,6 +239,9 @@ GEM
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
sqlite3 (1.3.10)
stripe (1.34.0)
json (~> 1.8.1)
rest-client (~> 1.4)
symmetric-encryption (3.8.1)
coercible (~> 1.0)
thor (0.19.1)
Expand All @@ -242,6 +254,9 @@ GEM
uglifier (2.7.1)
execjs (>= 0.3.0)
json (>= 1.8.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.1)
vcr (2.9.3)
warden (1.2.3)
rack (>= 1.0)
Expand Down Expand Up @@ -288,6 +303,7 @@ DEPENDENCIES
spring
spring-commands-rspec
sqlite3
stripe
symmetric-encryption (~> 3.8.1)
turbolinks
uglifier (>= 1.3.0)
Expand Down
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Hopefully this will be of help to those of you learning RSpec and Rails. If ther
- [Routing Specs & Docs](#routing-specs--docs)
- [Enable Spring for RSpec](#enable-spring-for-rspec)
- [Automated Continuous Integration with Travis CI](#automated-continuous-integration-with-travis-ci)
- [Stripe](#stripe)
- [Contributors](#contributors)

<!-- /MarkdownTOC -->
Expand Down Expand Up @@ -168,10 +169,11 @@ Capybara configuration how-to and examples:
If you need to debug Puffing Billy, refer to its output in `log/test.log`.

Puffing Billy configuration how-to and examples:
- [spec/support/puffing_billy.rb](spec/support/puffing_billy.rb)
- [spec/support/puffing_billy.rb](spec/support/puffing_billy.rb) - see comments on recording responses with `RECORD` environment variable
- [spec/features/user_upgrades_spec.rb](spec/features/user_upgrades_spec.rb)
- [spec/features/share_page_spec.rb](spec/features/share_page_spec.rb)
- [Cache options](https://github.com/oesmith/puffing-billy#caching)
- [Cached responses in spec/support/http_cache/billy](spec/support/http_cache/billy)
- [Cached responses in spec/support/http_cache/browser](spec/support/http_cache/browser)


# Shoulda-Matchers Examples
Expand Down Expand Up @@ -311,6 +313,19 @@ Travis CI configuration how-to and example:
- [Our Travis CI build!](https://travis-ci.org/eliotsykes/rspec-rails-examples)
- Our Travis CI badge (hopefully its green): [![Build Status](https://travis-ci.org/eliotsykes/rspec-rails-examples.svg?branch=master)](https://travis-ci.org/eliotsykes/rspec-rails-examples)


# Stripe

The app uses Stripe to handle payments for users wishing to upgrade their membership from standard to premium.

You can test Stripe's JavaScript integration without being dependent on Stripe's test environment network availability. For reliable, faster tests, its usually a good idea to make your tests work independently of any 3rd party environments.

To remove the dependency on Stripe's environment, the test suite relies on Puffing Billy mocking the Stripe HTTP responses in the browser.

- [spec/features/user_upgrades_spec.rb](spec/features/user_upgrades_spec.rb)
- [spec/support/http_cache/frontend/](spec/support/http_cache/frontend/) stores Stripe cached HTTP responses for Puffing Billy
- [Stripe testing guide](https://stripe.com/docs/testing) with card numbers for testing different error states

---

# Contributors
Expand Down
18 changes: 18 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,27 @@ class User < ActiveRecord::Base
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable

STANDARD = 'standard'
PREMIUM = 'premium'
ROLES = [STANDARD, PREMIUM].freeze

validates_inclusion_of :role, in: ROLES

has_many :access_tokens, dependent: :destroy

def issue_access_token
access_tokens.create!
end

def upgradeable?
standard?
end

def standard?
STANDARD == role
end

def upgrade
update!(role: PREMIUM)
end
end
13 changes: 13 additions & 0 deletions app/views/pages/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
<% if user_signed_in? %>
<p>Hello, <%= current_user.email %></p>
<nav><%= button_to "Log out", destroy_user_session_path, method: :delete %></nav>

<%= form_tag "/charge" do %>
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.application.secrets.stripe_publishable_key %>"
data-label="Upgrade Membership"
data-name="RSpec Rails Examples"
data-description="Member Upgrade"
data-currency="usd"
data-amount="999">
</script>
<% end %>

<% else %>
<p>Not registered? <%= link_to "Sign up", new_user_registration_path %></p>
<nav>
Expand Down
1 change: 1 addition & 0 deletions config/initializers/stripe.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Stripe.api_key = Rails.application.secrets.stripe_secret_key
5 changes: 5 additions & 0 deletions db/migrate/20151206175412_add_role_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddRoleToUsers < ActiveRecord::Migration
def change
add_column :users, :role, :string, default: "standard", null: false
end
end
11 changes: 6 additions & 5 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20151024100339) do
ActiveRecord::Schema.define(version: 20151206175412) do

create_table "access_tokens", force: :cascade do |t|
t.string "locator", null: false
Expand Down Expand Up @@ -47,12 +47,12 @@
add_index "subscriptions", ["email"], name: "index_subscriptions_on_email", unique: true

create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
Expand All @@ -61,11 +61,12 @@
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "failed_attempts", default: 0, null: false
t.integer "failed_attempts", default: 0, null: false
t.string "unlock_token"
t.datetime "locked_at"
t.datetime "created_at"
t.datetime "updated_at"
t.string "role", default: "standard", null: false
end

add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
Expand Down
10 changes: 3 additions & 7 deletions db/seeds.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
# Mayor.create(name: 'Emanuel', city: cities.first)
if Rails.env.development?
User.create_with(password: 'password', confirmed_at: Time.zone.now).find_or_create_by!(email: '[email protected]')
end
8 changes: 0 additions & 8 deletions spec/features/user_login_and_logout_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,4 @@

end

private

def login(email, password)
fill_in "Email", with: email
fill_in "Password", with: password
click_button "Log in"
end

end
32 changes: 32 additions & 0 deletions spec/features/user_upgrades_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require "rails_helper"

feature "User upgrades", js: true do

scenario "successfully" do
with_browser_responses('stripe checkout') do
user = create(:user, role: "standard")

visit new_user_session_path
login user
click_button "Upgrade Membership"

Capybara.using_wait_time 5.seconds do
within_frame 'stripe_checkout_app' do
fill_in "Email", with: user.email
fill_in_stripe_field "#card_number", with: "4242 4242 4242 4242"
fill_in_stripe_field "#cc-exp", with: "12/22"
fill_in "CVC", with: '123'
click_button "Pay $9.99"
end
expect(page).to have_no_button "Upgrade Membership"
end

expect(page).to have_content "Charged!"
expect(page).to have_content "Thank you for upgrading your membership!"
expect(user.reload.premium?).to eq true
end
end

xscenario "unsuccessfully"

end
Loading