Skip to content

Instantly share code, notes, and snippets.

@nruth
Last active March 7, 2023 00:21
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nruth/b2500074749e9f56e0b7 to your computer and use it in GitHub Desktop.
Save nruth/b2500074749e9f56e0b7 to your computer and use it in GitHub Desktop.
capybara selenium webdriver stripe.js checkout test helper
# -*- encoding : utf-8 -*-
module PayStripeHelpers
# must be used with driver: :selenium (or :sauce?)
def pay_stripe
sleep(0.7) # wait for the js to create the popup in response to pressing the button
within_frame 'stripe_checkout_app' do # must be selenium
# fill_in 'card_number', with: '4242424242424242' no longer works
4.times {page.driver.browser.find_element(:id, 'card_number').send_keys('4242')}
# fill_in 'cc-exp', with: '5/2018' no longer works
page.driver.browser.find_element(:id, 'cc-exp').send_keys '5'
page.driver.browser.find_element(:id, 'cc-exp').send_keys '18'
page.driver.browser.find_element(:id, 'cc-csc').send_keys '123'
find('button[type="submit"]').click
end
# wait for stripe to finish and change the page; default is 2 seconds
find("body[data-tests-page='member/dashboard']", wait: 30)
end
end
if respond_to?(:World) #cucumber
World(PayStripeHelpers)
else
RSpec.configure do |config|
config.include PayStripeHelpers, :type => :feature
end
end
@hoanghuynh
Copy link

Thank you, this is lovely!

@stephenson
Copy link

Thanks! :wait: did the job!

@nruth
Copy link
Author

nruth commented Jul 24, 2015

We added address collection and made a few tweaks:

find('#submitButton', text: 'Payment Info').click
then leave the frame and call
within_frame 'stripe_checkout_app' do
again before filling in the card details

unfortunately this is all really really brittle, and in the end I've just kept one test that hits their javascript, and replaced the rest with this:

      expect(page).to have_css('iframe[name="stripe_checkout_app"]')
      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();")

which assumes checkout works correctly, and just tests your server's API calls when it's given a valid stripe token.

The js injected into the browser is almost the same as the code in our checkout.js form handler.

@Confusion
Copy link

The various page.driver. .... can be simplified to e.g.

4.times {find('#card_number').send_keys('4242')}

@iloveitaly
Copy link

Here's an updated version of this snippet that worked for me:

    stripe_card_number = '4242424242424242'

    within_frame 'stripe_checkout_app' do
      # must use `find_field` since the credit card field does not have a static ID
      find_field('Card number').send_keys(stripe_card_number)
      find_field('MM / YY').send_keys "01#{DateTime.now.year + 1}"
      find_field('CVC').send_keys '123'

      find('button[type="submit"]').click
    end

@bparanj
Copy link

bparanj commented Jan 21, 2017

You are my hero!

@brntsllvn
Copy link

Adding address stuff to @iloveitaly 's answer. This stuff still works as of late(ish) 2017.

    within_frame 'stripe_checkout_app' do
      find_field('Name').send_keys 'Some Person'
      find_field('Street').send_keys '123 Sunshine Pl.'
      find_field('City').send_keys 'Seattle'
      find_field('ZIP Code').send_keys '98112'
      find('button[type="submit"]').click

      find_field('Card number').send_keys '4242424242424242'
      find_field('MM / YY').send_keys "01#{DateTime.now.year + 1}"
      find_field('CVC').send_keys '123'
      find('button[type="submit"]').click
    end

@srghma
Copy link

srghma commented Dec 28, 2017

for v3 (was able to find iframe only by position)

def fill_stripe(card, cvc, exp)
  iframes = all('iframe')
  card_iframe = iframes[0]
  cvc_iframe = iframes[1]
  exp_iframe = iframes[2]

  within_frame card_iframe do
    card.chars.each do |piece|
      find_field('cardnumber').send_keys(piece)
    end
  end

  within_frame cvc_iframe do
    cvc.chars.each do |piece|
      find_field('cvc').send_keys(piece)
    end
  end

  within_frame exp_iframe do
    exp.chars.each do |piece|
      find_field('exp-date').send_keys(piece)
    end
  end
end

@bhbryant
Copy link

bhbryant commented Feb 25, 2018

Modified to work with Stripe Card Element:

  def fill_stripe_element(card,exp, cvc, postal='')
    card_iframe = all('iframe')[0]

    within_frame card_iframe do
      card.chars.each do |piece|
        find_field('cardnumber').send_keys(piece)
      end

      exp.chars.each do |piece|
        find_field('exp-date').send_keys(piece)
      end

      cvc.chars.each do |piece|
        find_field('cvc').send_keys(piece)
      end

     
      postal.chars.each do |piece|
        find_field('postal').send_keys(piece)
      end
    end
  end

@hayesr
Copy link

hayesr commented Sep 17, 2018

Thanks @bhbryant!

@jmzbond
Copy link

jmzbond commented Dec 8, 2018

Is this still working for you ? It's not working for me anymore... This is what I'm seeing

  • Stripe DOES in fact initialize an iframe; without Stripe on the page, no iframe is found
  • However, with Stripe and within that iframe, if I search for a generic input element, it defaults to an input I had put on the page

It's as if Stripe's iframe is "deflecting" to my regular view...

@excid3
Copy link

excid3 commented Oct 24, 2019

I added some helpers for Stripe SCA in case anyone needs that: https://gorails.com/blog/fill-in-stripe-elements-js-for-sca-3d-secure-2-and-capybara

@jclusso
Copy link

jclusso commented Mar 7, 2023

Was wondering if there was any update to this for Stripe's Payment Element? Have been struggling to get this to work with the new way. Oddly, I can get it to work within a pry, but not when it runs by itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment