From 1d13483834e9de3bd1232fdb5d685f796230c3ca Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Sun, 6 Dec 2015 18:10:14 +0000 Subject: [PATCH 01/39] Move puffing billy cache to http_cache/frontend --- README.md | 2 +- ...ithub.io_14d848c4b4914df4e7ab6e2e3e4e4ec3ad51c16b.yml | 0 spec/support/puffing_billy.rb | 9 ++++----- 3 files changed, 5 insertions(+), 6 deletions(-) rename spec/support/http_cache/{billy => frontend}/get_eliotsykes.github.io_14d848c4b4914df4e7ab6e2e3e4e4ec3ad51c16b.yml (100%) diff --git a/README.md b/README.md index daef333..01bf06b 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ Puffing Billy configuration how-to and examples: - [spec/support/puffing_billy.rb](spec/support/puffing_billy.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/frontend](spec/support/http_cache/frontend) # Shoulda-Matchers Examples diff --git a/spec/support/http_cache/billy/get_eliotsykes.github.io_14d848c4b4914df4e7ab6e2e3e4e4ec3ad51c16b.yml b/spec/support/http_cache/frontend/get_eliotsykes.github.io_14d848c4b4914df4e7ab6e2e3e4e4ec3ad51c16b.yml similarity index 100% rename from spec/support/http_cache/billy/get_eliotsykes.github.io_14d848c4b4914df4e7ab6e2e3e4e4ec3ad51c16b.yml rename to spec/support/http_cache/frontend/get_eliotsykes.github.io_14d848c4b4914df4e7ab6e2e3e4e4ec3ad51c16b.yml diff --git a/spec/support/puffing_billy.rb b/spec/support/puffing_billy.rb index ea81ace..f1c2fd6 100644 --- a/spec/support/puffing_billy.rb +++ b/spec/support/puffing_billy.rb @@ -4,13 +4,13 @@ # # 1. Puffing Billy depends on Capybara. Install Capybara as explained # in spec/support/capybara.rb -# +# # 2. Add puffing-billy to Gemfile: # # group :development, :test do # gem 'puffing-billy' # end -# +# # 3. Create a file like this one you're reading in spec/support/puffing_billy.rb: require 'billy/rspec' @@ -24,7 +24,7 @@ c.non_successful_error_level = :warn # cache_path is where responses from external URLs will be saved as YAML. - c.cache_path = "spec/support/http_cache/billy/" + c.cache_path = "spec/support/http_cache/frontend/" # Avoid having tests dependent on external URLs. # @@ -42,11 +42,10 @@ # Capybara.javascript_driver = :poltergeist_billy # 6. Start using Puffing Billy. See spec/features/share_page_spec.rb for an example, -# and find your cached responses in spec/support/http_cache/billy +# and find your cached responses in spec/support/http_cache/frontend # Suggested docs # -------------- # https://github.com/oesmith/puffing-billy # https://github.com/oesmith/puffing-billy#rspec-usage # https://github.com/oesmith/puffing-billy#caching - From 8f08bbab8da51487f5d1d9f6373807896aa97a81 Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Sun, 6 Dec 2015 18:10:58 +0000 Subject: [PATCH 02/39] Introduce role column on User --- app/models/user.rb | 4 ++++ db/migrate/20151206175412_add_role_to_users.rb | 5 +++++ db/schema.rb | 11 ++++++----- spec/models/user_spec.rb | 12 +++++++++--- 4 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20151206175412_add_role_to_users.rb diff --git a/app/models/user.rb b/app/models/user.rb index f010337..7136e5a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,6 +5,10 @@ class User < ActiveRecord::Base :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable + ROLES = ["standard", "premium"].freeze + + validates_inclusion_of :role, in: ROLES + has_many :access_tokens, dependent: :destroy def issue_access_token diff --git a/db/migrate/20151206175412_add_role_to_users.rb b/db/migrate/20151206175412_add_role_to_users.rb new file mode 100644 index 0000000..5ab6afe --- /dev/null +++ b/db/migrate/20151206175412_add_role_to_users.rb @@ -0,0 +1,5 @@ +class AddRoleToUsers < ActiveRecord::Migration + def change + add_column :users, :role, :string, default: "standard", null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index a6cc0ce..d7c1032 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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 @@ -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" @@ -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 diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index edcad0a..f0ce3bc 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -2,18 +2,19 @@ describe User do - context 'validations' do + describe 'validations' do it { should validate_presence_of :email } it { should validate_presence_of :password } it { should validate_confirmation_of :password } it { should validate_uniqueness_of(:email).case_insensitive } + it { should validate_inclusion_of(:role).in_array(["standard", "premium"]) } end - context 'associations' do + describe 'associations' do it { should have_many(:access_tokens).dependent(:destroy) } end - context '#issue_access_token' do + describe '#issue_access_token' do it 'creates access token belonging to user' do user = create(:user) @@ -26,4 +27,9 @@ end end + describe '#role' do + it 'defaults to standard' do + expect(User.new.role).to eq "standard" + end + end end From bbcf8d01c6c8887fdde013afdbdca78e35dd193b Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Sun, 6 Dec 2015 18:11:20 +0000 Subject: [PATCH 03/39] Move login method to LoginHelper --- spec/features/user_login_and_logout_spec.rb | 8 ------- spec/support/login_helper.rb | 23 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 spec/support/login_helper.rb diff --git a/spec/features/user_login_and_logout_spec.rb b/spec/features/user_login_and_logout_spec.rb index ea5aede..a3870ab 100644 --- a/spec/features/user_login_and_logout_spec.rb +++ b/spec/features/user_login_and_logout_spec.rb @@ -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 diff --git a/spec/support/login_helper.rb b/spec/support/login_helper.rb new file mode 100644 index 0000000..1b74cc6 --- /dev/null +++ b/spec/support/login_helper.rb @@ -0,0 +1,23 @@ +module LoginHelper + + def login(*args) + if args.size == 1 && args[0].is_a?(User) + user = args[0] + email = user.email + password = user.password + elsif args.size == 2 + email, password = args + else + raise "Unable to handle args #{args.inspect}" + end + + fill_in "Email", with: email + fill_in "Password", with: password + click_button "Log in" + end + +end + +RSpec.configure do |config| + config.include LoginHelper, type: :feature +end From d2d5c1035d9e56c6a72000f385a02bf8292505bc Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Sun, 6 Dec 2015 18:22:13 +0000 Subject: [PATCH 04/39] Notes on Stripe testing --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 01bf06b..9ced4ec 100644 --- a/README.md +++ b/README.md @@ -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) @@ -311,6 +312,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 From e3311e382c8b41766128af795b233a89eab90cb0 Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Sun, 6 Dec 2015 20:20:33 +0000 Subject: [PATCH 05/39] Tidied vcr config --- spec/support/vcr.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/support/vcr.rb b/spec/support/vcr.rb index 78522b6..09e56ff 100644 --- a/spec/support/vcr.rb +++ b/spec/support/vcr.rb @@ -24,4 +24,4 @@ # Suggested docs # -------------- # https://relishapp.com/vcr/vcr/docs -# http://www.rubydoc.info/gems/vcr/frames \ No newline at end of file +# http://www.rubydoc.info/gems/vcr/frames From b0d360bf73569414491278048acb4f6ea3c3ef0b Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Sun, 6 Dec 2015 20:52:26 +0000 Subject: [PATCH 06/39] Put test standard user in seeds --- db/seeds.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/db/seeds.rb b/db/seeds.rb index 4edb1e8..0058699 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -5,3 +5,10 @@ # # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) # Mayor.create(name: 'Emanuel', city: cities.first) + +if Rails.env.development? + user = User.find_or_initialize_by(email: "a@a.a") + user.password = "password" + user.skip_confirmation! + user.save! +end From d1c9f4e288fde7c19e1c855e8993ee5934132e6e Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Sun, 6 Dec 2015 20:52:47 +0000 Subject: [PATCH 07/39] StripeHelper --- spec/support/capybara.rb | 2 +- spec/support/puffing_billy.rb | 34 ++++++++++++++++++++++++++++++++-- spec/support/stripe_helper.rb | 13 +++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 spec/support/stripe_helper.rb diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index ff4d247..3cb25cb 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -28,4 +28,4 @@ # -------------- # http://www.rubydoc.info/github/jnicklas/capybara/master # Cheatsheet: https://gist.github.com/zhengjia/428105 -# Capybara matchers: http://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Matchers \ No newline at end of file +# Capybara matchers: http://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Matchers diff --git a/spec/support/puffing_billy.rb b/spec/support/puffing_billy.rb index f1c2fd6..449c544 100644 --- a/spec/support/puffing_billy.rb +++ b/spec/support/puffing_billy.rb @@ -24,7 +24,7 @@ c.non_successful_error_level = :warn # cache_path is where responses from external URLs will be saved as YAML. - c.cache_path = "spec/support/http_cache/frontend/" + c.cache_path = "spec/support/http_cache/frontend/" # Avoid having tests dependent on external URLs. # @@ -32,7 +32,37 @@ # to false when first recording a 3rd party interaction. After # the recording has been stored to cache_path, then set # non_whitelisted_requests_disabled back to true. - c.non_whitelisted_requests_disabled = true + c.non_whitelisted_requests_disabled = false +end + +# https://github.com/oesmith/puffing-billy#working-with-vcr-and-webmock +if defined?(VCR) + VCR.configure do |config| + config.ignore_request { |request| handled_by_billy?(request) } + end + + def handled_by_billy?(request) + # browser_referer?(request) + browser_user_agent?(request) + end + + def browser_user_agent?(request) + user_agent = !request.headers["User-Agent"].blank? && request.headers["User-Agent"].first + is_real_browser_user_agent = user_agent != "Ruby" + end + + # def allowed_referers + # [ + # %r{\Ahttp://#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}/}, + # %r{\Ahttps://checkout\.stripe\.com}, + # %r{\Ahttps://b\.stripecdn\.com} + # ] + # end + + # def browser_referer?(request) + # referer = !request.headers["Referer"].blank? && request.headers["Referer"].first + # handled = referer && allowed_referers.any? { |pattern| pattern =~ referer } + # end end # 5. Uncomment the *_billy driver for your desired browser: diff --git a/spec/support/stripe_helper.rb b/spec/support/stripe_helper.rb new file mode 100644 index 0000000..e524ebd --- /dev/null +++ b/spec/support/stripe_helper.rb @@ -0,0 +1,13 @@ +module StripeHelper + + def fill_in_with_force(locator, options) + page.execute_script "$('#{locator}').val('#{options[:with]}');" + end + + alias_method :fill_in_stripe_field, :fill_in_with_force + +end + +RSpec.configure do |config| + config.include StripeHelper, type: :feature +end From ea133f73434614114ae9c8bef9b2eec6446ddcf3 Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Sun, 6 Dec 2015 20:53:30 +0000 Subject: [PATCH 08/39] Correct puffing billy committed config --- spec/support/puffing_billy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/support/puffing_billy.rb b/spec/support/puffing_billy.rb index 449c544..38ab0f8 100644 --- a/spec/support/puffing_billy.rb +++ b/spec/support/puffing_billy.rb @@ -32,7 +32,7 @@ # to false when first recording a 3rd party interaction. After # the recording has been stored to cache_path, then set # non_whitelisted_requests_disabled back to true. - c.non_whitelisted_requests_disabled = false + c.non_whitelisted_requests_disabled = true end # https://github.com/oesmith/puffing-billy#working-with-vcr-and-webmock From 7789139645e2a27405c4ac62d3bf444b3370f8f0 Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Sun, 6 Dec 2015 20:53:58 +0000 Subject: [PATCH 09/39] [WIP] User Upgrades Feature Spec --- spec/features/user_upgrades_spec.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 spec/features/user_upgrades_spec.rb diff --git a/spec/features/user_upgrades_spec.rb b/spec/features/user_upgrades_spec.rb new file mode 100644 index 0000000..7105c79 --- /dev/null +++ b/spec/features/user_upgrades_spec.rb @@ -0,0 +1,27 @@ +require "rails_helper" + +feature "User upgrades", js: true do + + scenario "successfully" do + user = create(:user, role: "standard") + + visit new_user_session_path + login user + click_button "Upgrade Membership" + + within_frame "stripe_checkout_app" do + fill_in "Email", with: user.email + fill_in_stripe_field "#card_number", with: "4242424242424242" + fill_in_stripe_field "#cc-exp", with: "12/22" + fill_in "CVC", with: '123' + click_button "Pay $9.99" + end + + expect(page).to have_content "Thank you for upgrading your membership!" + expect(page).not_to have_css "button", text: "Upgrade Membership" + expect(user.reload.premium?).to eq true + end + + xscenario "unsuccessfully" + +end From 75cc8edab563eee6c414a37ae2bc7fab4d8fd980 Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Sun, 6 Dec 2015 20:54:29 +0000 Subject: [PATCH 10/39] [WIP] Stripe Checkout.js form --- app/views/pages/index.html.erb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/views/pages/index.html.erb b/app/views/pages/index.html.erb index a76228c..64ef65f 100644 --- a/app/views/pages/index.html.erb +++ b/app/views/pages/index.html.erb @@ -3,6 +3,19 @@ <% if user_signed_in? %>

Hello, <%= current_user.email %>

+ +
+ +
+ <% else %>

Not registered? <%= link_to "Sign up", new_user_registration_path %>