In test mode, Stripe Elements JS displays a modal iframe and then dynamically loads an inner iframe that displays the "Complete authentication" and "Fail authentication" buttons for testing.
Stripe Element's card element loads an iframe inside the div that it's mounted to. Similarly, Stripe handles SCA injecting an iframe on the body to create a modal. This iframe contains another iframe that holds the actual authentication buttons.
Here are 3 helper methods you can use with Capybara for interacting with Stripe's card element and SCA modal buttons.
require "test_helper" class ApplicationSystemTestCase < ActionDispatch::SystemTestCase driven_by :selenium, using: :chrome, screen_size: [1400, 1400] # Fills out the Stripe card element with the provided card details in Capybara # You can also provide a custom selector to find the correct iframe # By default, we use the ID of "#card-element" which Stripe uses in their documentation def fill_stripe_elements(card: , expiry: '1234', cvc: '123', postal: '12345', selector: '#card-element > div > iframe') find_frame(selector) do card.to_s.chars.each do |piece| find_field('cardnumber').send_keys(piece) end find_field('exp-date').send_keys expiry find_field('cvc').send_keys cvc find_field('postal').send_keys postal end end # Completes SCA authentication successfully def complete_stripe_sca find_frame('body > div > iframe') do # This helps find the inner iframe in the SCA modal's challenge frame which doesn't load immediately sleep 1 find_frame('#challengeFrame') do find_frame("iframe[name='acsFrame']") do click_on "Complete authentication" end end end end # Fails SCA authentication def fail_stripe_sca find_frame('body > div > iframe') do # This helps find the inner iframe in the SCA modal's challenge frame which doesn't load immediately sleep 1 find_frame('#challengeFrame') do find_frame("iframe[name='acsFrame']") do click_on "Fail authentication" end end end end # Generic helper for finding an iframe def find_frame(selector, &block) using_wait_time(15) do frame = find(selector) within_frame(frame) do block.call end end end end
To fill out the Stripe Elements JS credit card field with the default
#card-element > div > iframe selector, you can run:
fill_stripe_elements(card: '4242 4242 4242 4242')
To use a different selector if your element doesn't have the ID of
card-element on it, you can pass in the
fill_stripe_elements(card: '4242 4242 4242 4242', selector: '#some-other-selector')
To complete the SCA modal and confirm authentication, you can run:
To fail the SCA modal and test when authentication fails, you can run:
I've been using this with Rails system tests for JumpstartRails.com for a while now and it works great.
👉 Plus, I've created the Payments with Ruby on Rails Master Class to walk through every single step of setting up Stripe payments with Strong Customer Authentication support for your Rails app. We cover everything from one-time payments, subscription billing, receipts, refunds, webhooks, strong customer authentication confirmation, and testing. It took me 3 months to learn, implement, and test Stripe with SCA in my apps, so I made this course to save you the trouble!
If you have any tweaks that improve this, leave a comment below!