Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write integration tests for Stripe checkout on Rails?

Tags:

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 => "[email protected]"
      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: '[email protected]'
    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: '[email protected]'
 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!

like image 714
djoll Avatar asked Jun 06 '14 11:06

djoll


People also ask

What are integration tests rails?

While unit tests make sure that individual parts of your application work, integration tests are used to test that different parts of your application work together.

How do you test a Stripe product?

To test it, create a subscription in test mode. Then, log in to the portal as the test user and update the subscription. Check the Dashboard or API to see whether the subscription reflects the customer's change. Read the integration guide to learn how to set up the customer portal.

Can I use Stripe for testing?

Testing paymentsYou can issue cards and simulate purchases using your own Stripe integration in test mode. This allows you to test your integration before you go live without having to make real purchases. You can only use these cards for testing within your Stripe account and not for external purchases.

How do I integrate stripe checkout into my Rails application?

You can use Stripe's standard test credit card number (4242 4242 4242 4242), CVV (123), and any future date to check if your application gets back the token from Stripe. Once you’ve completed all the steps described above, you’ve successfully integrated Stripe Checkout into your Rails application.

What are integration tests in rails?

Integration tests are used to test how various parts of our application interact. They are generally used to test important workflows within our application. For creating Rails integration tests, we use the test/integration directory for our application. Rails provides a generator to create an integration test skeleton for us.

What is the new stripe Checkout service?

Since April 2019, Stripe provides a new Checkout service. Let's see how to integrate it step by step. I'll show you how to integrate the new Stripe Checkout service into your Rails application. This service allows us to seamlessly integrate a Stripe Checkout form, conform to the new Strong Customer Authentication EU regulation.

How to implement a stripe checkout using JavaScript?

we can define this Javascript to implement a checkout: once clicked, the button starts a request to the server to generate a session for the selected plan. The session id is then returned to the browser that redirects to the checkout window offered by Stripe. We cannot just rely on a call to the success_url we defined above.


1 Answers

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('[email protected]'); })
        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
like image 165
james Avatar answered Oct 23 '22 12:10

james