How to write integration tests for Stripe checkout on Rails?

前端 未结 5 1767
忘掉有多难
忘掉有多难 2020-12-14 02:24

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 wo

相关标签:
5条回答
  • 2020-12-14 03:04

    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:

      stripe_iframe = all('iframe[name=stripe_checkout_app]').last
      Capybara.within_frame stripe_iframe do
        fill_in "email", with: "test-user@example.com"
        ...
      end
    

    However, that does not work in poltergeist or capybara-webkit.

    For poltergeist, parov's suggestion works:

      stripe = page.driver.window_handles.last
      page.within_window stripe do
        fill_in "email", with: "test-user@example.com"
        ...
      end
    

    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?

    0 讨论(0)
  • 2020-12-14 03:11

    I tried James's answer and modified for my current environment. Here is my code (system spec with Chrome headless):

    require 'rails_helper'
    
    describe 'Orders', type: :system do
      before do
        # Temporarily change default_max_wait_time to wait for Stripe response
        @old_wait_time = Capybara.default_max_wait_time
        Capybara.default_max_wait_time = 10
      end
    
      after do
        Capybara.default_max_wait_time = @old_wait_time
      end
    
      scenario 'Payment via Stripe', js: true do
        visit payment_path
        click_button 'Pay with Card'
    
        # Use VCR to avoid actual data creation
        VCR.use_cassette 'orders/payment_via_stripe' do
          expect(page).to have_css('iframe[name="stripe_checkout_app"]')
          stripe_iframe = all('iframe[name=stripe_checkout_app]').last
    
          Capybara.within_frame stripe_iframe do
            # Set values by placeholders
            fill_in 'Card number', with: '4242424242424242'
            fill_in 'MM / YY', with: '08/44'
            fill_in 'CVC', with: '999'
            # You might need to fill more fields...
    
            click_button 'Pay $9.99'
          end
    
          # Confirm payment completed
          expect(page).to have_content 'Payment completed.'
        end
      end
    end
    

    I am using:

    • selenium-webdriver 3.14.0
    • rspec-rails 3.8.0
    • capybara 3.7.1
    • stripe 3.26.0
    • rails 5.2.1
    • ruby 2.5.1
    • vcr 4.0.0
    • webmock 3.4.2
    • Chrome 69

    My app is built according to https://stripe.com/docs/checkout/rails .

    0 讨论(0)
  • 2020-12-14 03:15

    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:

      # optionally ensure the iframe was opened
      expect(page).to have_css('iframe[name="stripe_checkout_app"]')
      # post the form
      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();")
    

    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.

    0 讨论(0)
  • 2020-12-14 03:21

    For capybara-webkit, I was able to get this to work:

      stripe_iframe = page.driver.window_handles.last
      page.within_window stripe_iframe do
        fill_in "email", with: "test-user@example.com" 
        ...
      end
    
    0 讨论(0)
  • 2020-12-14 03:23

    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('jamesdd9302@yahoo.com'); })
            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
    
    0 讨论(0)
提交回复
热议问题