I\'ve hit the wall trying to write an integration test for Stripe\'s checkout.js [ https://checkout.stripe.com/checkout.js ] for my Rails 3.2 app.
Stripe checkout wo
Problem solved!
With some help from parov via his similar question & answer [ Poltergeist Stripe checkout.js ] I tracked the problem down to using an old version of Capybara '~>1.1.2' and the subsequent dependency-effect this had on the various javascript testing gems (ie. selenium, capybara-webkit, poltergeist...).
Doing a bundle update
of Capybara to 2.3.0, and so bringing poltergeist to 1.5.1, with selenium-webdriver at 2.42.0 and capybara-webkit at 1.1.0, gets (almost) everything working.
For selenium, this method via Capybara trouble filling in JS modal does work:
stripe_iframe = all('iframe[name=stripe_checkout_app]').last
Capybara.within_frame stripe_iframe do
fill_in "email", with: "test-user@example.com"
...
end
However, that does not work in poltergeist or capybara-webkit.
For poltergeist, parov's suggestion works:
stripe = page.driver.window_handles.last
page.within_window stripe do
fill_in "email", with: "test-user@example.com"
...
end
For capybara-webkit I wasn't able to get anything working, though given I had something working with poltergeist I didn't put too much time into finding a capybara-webkit solution.
Comments?
I tried James's answer and modified for my current environment. Here is my code (system spec with Chrome headless):
require 'rails_helper'
describe 'Orders', type: :system do
before do
# Temporarily change default_max_wait_time to wait for Stripe response
@old_wait_time = Capybara.default_max_wait_time
Capybara.default_max_wait_time = 10
end
after do
Capybara.default_max_wait_time = @old_wait_time
end
scenario 'Payment via Stripe', js: true do
visit payment_path
click_button 'Pay with Card'
# Use VCR to avoid actual data creation
VCR.use_cassette 'orders/payment_via_stripe' do
expect(page).to have_css('iframe[name="stripe_checkout_app"]')
stripe_iframe = all('iframe[name=stripe_checkout_app]').last
Capybara.within_frame stripe_iframe do
# Set values by placeholders
fill_in 'Card number', with: '4242424242424242'
fill_in 'MM / YY', with: '08/44'
fill_in 'CVC', with: '999'
# You might need to fill more fields...
click_button 'Pay $9.99'
end
# Confirm payment completed
expect(page).to have_content 'Payment completed.'
end
end
end
I am using:
My app is built according to https://stripe.com/docs/checkout/rails .
I've been fighting with this for some time (as the gist james mentions shows) and in the end found it's too brittle and too slow to test the checkout js.
Instead you can use the following (ruby, capybara, selenium) to stub checkout.js and post your form with a stripe token:
# optionally ensure the iframe was opened
expect(page).to have_css('iframe[name="stripe_checkout_app"]')
# post the form
token = Stripe::Token.create(
:card => {
:number => "4242424242424242",
:exp_month => 7,
:exp_year => 2019,
:cvc => "314",
address_line1: Faker::Address.street_address,
address_city: Faker::Address.city,
address_zip: Faker::Address.postcode,
address_country: 'United Kingdom'
},
)
page.execute_script("$('#payment_token').val('#{token.id}');")
page.execute_script("$('#our-stripe-payment-form').submit();")
n.b. this assumes you already have the stripe api gem loaded in your test environment (by your rails app) and have a registered API key etc, otherwise see the docs.
For capybara-webkit, I was able to get this to work:
stripe_iframe = page.driver.window_handles.last
page.within_window stripe_iframe do
fill_in "email", with: "test-user@example.com"
...
end
I could not get any of the solutions here so far to work for me, and then reading this post: https://gist.github.com/nruth/b2500074749e9f56e0b7 I realized that the key was to add a delay to the test to give the Stripe enough time to 1) load the checkout window and 2) process the token.
For that reason the only code that I could get to work was this (feel free to play with timing) :
SELENIUM
describe "test stripe" do, js: true, driver: :selenium do
before do
... # fill in order form or whatever
click_button "checkout_with_stripe"
sleep(2) # allows stripe_checkout_app frame to load
stripe_iframe = all('iframe[name=stripe_checkout_app]').last
Capybara.within_frame stripe_iframe do
page.execute_script(%Q{ $('input#email').val('jamesdd9302@yahoo.com'); })
page.execute_script(%Q{ $('input#card_number').val('4242424242424242'); })
page.execute_script(%Q{ $('input#cc-exp').val('08/44'); })
page.execute_script(%Q{ $('input#cc-csc').val('999'); })
page.execute_script(%Q{ $('#submitButton').click(); })
sleep(3) # allows stripe_checkout_app to submit
end
end
it "should successfully process the request" do
... # test should pass
end
end
For Capybara-webkit, the sleep
trick didn't work nor sadly did @Ryan's solution, and I got too tired of trying to figure this out so I just stopped, but hopefully someone else will get it because I'd rather use webkit for speed reasons! (I was using capybara-webkit 1.3.0
)
In case it helps, here are my relevant versions:
selenium-webdriver 2.35.1
rspec-rails 2.14.2
capybara 2.1.0
stripe 1.16.0 da216fd
rails 4.1.1
ruby 2.1.2