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 works correctly for me when manually tested (using Stripe's testing keys), but I cannot get Capybara to detect and fill_in
the email field in the Stripe checkout iframe modal.
I am using poltergeist for headless javascript, though have also tested this with capybara-webkit and even selenium with the same problem.
What I am trying to test is the complete subscription sign-up flow, to show that a new user can create a subscriber account after entering their payment details in Stripe - but I cannot get past the Stripe checkout pop-up.
Here is my before .. do
:
describe "show Stripe checkout", :js => true do
before do
visit pricing_path
click_button 'plan-illuminated'
stripe_iframe = all('iframe[name=stripe_checkout_app]').last
Capybara.within_frame stripe_iframe do
fill_in "email", :with => "test-user@example.com"
fill_in "billing-name", :with => "Mr Name"
fill_in "billing-street", :with => "test Street"
fill_in "billing-zip", :with => 10000
fill_in "billing-city", :with => "Berlin"
click_button "Payment Info"
end
end
it { should have_selector('button', text: "Subscribe") }
end
Which errors with:
Failure/Error: Capybara.within_frame stripe_iframe do
Capybara::Poltergeist::TimeoutError:
Timed out waiting for response to {"name":"push_frame","args":[null]}
If I swap out the attempt to choose the correct iframe (suggested here: Capybara trouble filling in JS modal ) like so:
# stripe_iframe = all('iframe[name=stripe_checkout_app]').last
# Capybara.within_frame stripe_iframe do
Capybara.within_frame 'stripe_checkout_app' do
I still get the similar:
Capybara::Poltergeist::TimeoutError:
Timed out waiting for response to {"name":"push_frame","args":["stripe_checkout_app"]}
It appears that whichever javascript testing gem I use, rspec/capybara cannot find the Stripe checkout iframe. When I check with Selenium I see the Choose this Plan
button pressed and the Checkout pop-up, but the spec times out looking for the email field to fill in.
Any ideas?
I've already tried:
- Various ways of choosing or finding the email field.
- Updating all my gems.
- Using StripeMock before this (not that it should be involved, right?).
- Running the same tests against Stripe's own site, which give the same errors:
Testing with:
visit "https://stripe.com/docs/checkout"
click_button 'Pay with Card'
stripe_iframe = all('iframe[name=stripe_checkout_app]').last
Capybara.within_frame stripe_iframe do
fill_in 'Email', with: 'test@example.com'
sleep 3
end
Depending which method I use to select the iframe I receive the same errors. Using just Capybara.within_frame 'stripe_checkout_app' do
:
Failure/Error: Capybara.within_frame stripe_iframe do
Capybara::Poltergeist::TimeoutError:
Timed out waiting for response to {"name":"push_frame","args":[null]}
or using Selenium with stripe_iframe = all('iframe[name=stripe_checkout_app]').last
:
Failure/Error: Unable to find matching line from backtrace
SystemStackError:
stack level too deep
or even just:
Failure/Error: fill_in 'Email', with: 'test@example.com'
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'Email' found
...depending on which testing javascript gem I am using.
Any help or wisdom is greatly appreciated!
For capybara-webkit, I was able to get this to work:
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:
However, that does not work in poltergeist or capybara-webkit.
For poltergeist, parov's suggestion works:
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'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:
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.
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
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 usingcapybara-webkit 1.3.0
)In case it helps, here are my relevant versions:
I tried James's answer and modified for my current environment. Here is my code (system spec with Chrome headless):
I am using:
My app is built according to https://stripe.com/docs/checkout/rails .