Skip to main content

Fill in Stripe Elements JS for SCA / 3D Secure 2 and Capybara

Chris Oliver October 23, 2019

Stripe Elements Javascript now has support for Strong Customer Authentication (SCA) with 3D Secure 2 (3DS2). This makes handling these in system tests a bit harder. Filling out the credit card fields in the past has been pretty straightforward, but now we have an extra modal to handle with SCA authentication.

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
        click_on "Complete authentication"
      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
        click_on "Fail authentication"
      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 selector option:

fill_stripe_elements(card: '4242 4242 4242 4242', selector: '#some-other-selector')

To complete the SCA modal and confirm authentication, you can run:

complete_stripe_sca

To fail the SCA modal and test when authentication fails, you can run:

fail_stripe_sca

I've been using this with Rails system tests for JumpstartRails.com for a while now and it works great.

If you have any tweaks that improve this, leave a comment below!

P.S. You might enjoy following me on Twitter.


Loading...

Latest from the blog

Start building fast, modern Rails websites in no time with GoRails tutorials.

Subscribe to the newsletter

Join 24,647+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.