Rspec + Capybara - Paypal Express Sandbox checkout timing - ruby-on-rails

My test setup is Rspec + Capybara with Poltergeist / Phantomjs.
I'm trying to test the Paypal express sandbox - sometimes the tests pass sometimes not. Looks like a timing problem.
Here's my test snippet which redirects to Paypal and on success back to my page. I'm using my credit on the sandbox account so no creditcard processing...
Anyone has a working setup for that or any suggestions?
# confirm order and proceed / redirect to paypal
find('button#booking-button').click
using_wait_time(60) do
# login on paypal express sandbox page
within_frame(find('iframe')) do
fill_in 'email', with: Rails.application.secrets.paypal_test_user_email
fill_in 'password', with: Rails.application.secrets.paypal_test_user_password
find('button#btnLogin').click
end
using_wait_time(60) do
# confirm payment and redirect back to my page
find('input#confirmButtonTop').click
using_wait_time(60) do
# check if element on my page exists
expect(page).to have_selector('div#checkout-thank-you')
end
end
end

Jack Kinsella's answer served us very well for 2 years (🙏🏼), but PayPal recently updated their UI in Europe.
You could log in as a guest, but test credit cards are a pain as they keep expiring and filling out the form takes much longer. You'll now first have to accept cookies and indicate that you want to log in.
def pay_with_paypal
paypal_window =
window_opened_by do
within_frame(find(".paypal-buttons iframe")) do
first(".paypal-button").click
end
end
within_window(paypal_window) do
# similar, just couple of extra steps and calling reusable method for details
Capybara.using_wait_time(5) do
# accept cookies
click_button("Accept Cookies") if page.has_button?("Accept Cookies")
# switch to login form (if needed)
click_on("Log In") if page.has_content?("PayPal Guest Checkout")
add_paypal_login_details
click_on("Pay Now")
end
end
end
def add_paypal_login_details
fill_in "login_email", with: "youraccount#test.com"
click_on "Next"
fill_in "login_password", with: "yourpassword"
find("#btnLogin").click
end
I've found that PayPal can shift quite a bit depending on region and whether or not you're running headless Chrome. Using save_and_open_screenshot could help determine your exact scenario.

It depends on what API you are using.
For the REST API (v1), the following worked for me:
# click client side checkout button
paypal_window =
window_opened_by do
within_frame(find('.paypal-button iframe')) do
find('.paypal-button-text').click
end
end
# pay within popup window
within_window(paypal_window) do
click_link 'Log In'
# I am assuming you have a buyer email/password in the sandbox set up
fill_in 'login_email', with: MyConfig['paypal_buyer_email']
click_on 'Next'
fill_in 'password', with: MyConfig['paypal_buyer_password']
click_on 'Log In'
click_on 'Pay Now'
end
At time of writing (for the old SOAP API not the newer REST API), this works:
click_link 'Log In'
using_wait_time(60) do
fill_in 'login_email', with: 'email'
click_on 'btnNext'
fill_in 'password', with: 'password'
click_on 'btnLogin'
click_on 'confirmButtonTop'
end

looks like they changed their layout. form instead of iframe. here's whats working for me some times:
find('button#booking-button').click
using_wait_time(60) do
within('form.proceed.maskable') do
fill_in 'email', with: Rails.application.secrets.paypal_test_user_email
fill_in 'password', with: Rails.application.secrets.paypal_test_user_password
find('button#btnLogin').click
end
using_wait_time(60) do
find('input#confirmButtonTop').click
using_wait_time(60) do
expect(page).to have_selector('div#checkout-thank-you')
end
end
end

Related

Capybara loses cookies between requests

I have the follow test:
def login_user(email, password)
visit new_user_session_path
fill_in 'E-mail', with: email
fill_in 'Password', with: password
click_button 'go'
end
scenario 'some test' do
order = Fabricate(:order_one, company: user.company)
visit "http://127.0.0.1:49645/orders/#{order.id}" # change to visit "/orders/#{order.id}"
login_user(user.email, user.password)
#assert
end
Whats happen is that in first step (visit...) the user is not logged, so I set some informations using cookie. But, when login_user is executed, this cookie is empty.
Usigin selenium-webdriver
Any idea here ?
Thanks in advance
When using a JS capable driver #visit is not guaranteed to have finished loading the page when it returns. Since the cookie is not set in the browser until the response is processed, your login_user is actually telling the browser to stop processing it's current visit and visit somewhere else which stops the cookie from ever being set in the browser. After the first visit you need to wait for something visible on the page to be sure the cookies are correctly set.
scenario 'some test' do
order = Fabricate(:order_one, company: user.company)
visit "http://127.0.0.1:49645/orders/#{order.id}"
expect(page).to have_content('you are not logged in') #or whatever shows on the page visited
login_user(user.email, user.password)
#assert
end

rspec + capybara rails 4 - rake integration testing fails

I'm trying to test devise sign in, sign out and all the other scenarios, however I cannot get a single scenario to past, lets take login failure
in my feature I have
scenario 'user cannot sign in if not registered' do
login_as('user2#example.com', 'meow')
visit overviews_path
save_and_open_page
expect(page).to have_content I18n.t 'devise.failure.not_found_in_database', authentication_keys: 'email'
end
I also have the sign_in helper setup as;
def sign_in(email, password)
user.confirm!
visit new_user_session_path
fill_in 'Email', with: email
fill_in 'password', with: password
click_button 'Log in'
end
however this create an error;
expected to find text "Invalid email or password." in "TypeError at /overviews ======================= > no implicit conversion of Symbol into Integer spec/features/users/sign_in_spec.rb, line 14
any ideas?
You named your helper method sign_in but you're calling login_as in your scenario. You should use one approach or the other, not both.
UPDATE: OK, rechecked the documentation, and you should either use your own helper so that you're emulating an actual user signing in, or the login_as provided by Warden, in which case make sure you're included this in your tests / rspec setup:
include Warden::Test::Helpers
Warden.test_mode!
On a side note, you should confirm your user in your factory/fixture, not in your helper method (where it's probably not defined).

Test capybara devise sign in with subdomain

I want to test sign in process. In my app each user has it's own subdomain. And when I try to test sign in process it allways writes error that password or email is invalid.
Here is test code
scenario do
user = create(:confirmed_user)
Capybara.app_host = "http://#{user.subdomain}.lvh.me"
visit new_user_session_path
fill_in 'user_email', with: user.email
fill_in 'user_password', with: "Passw0rd"
click_link_or_button "Sign in"
end
Login and password are 100% correct.
Also I've tried to do everything that written in this article
http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/
but it didn't help. Also, test for login of admin user without subdomain works perfectly.
Maybe I miss something? Thanks in advance.

"background(:all)" block doesn't work in rpsec feature spec

I'm using rspec, capybara and Selenium to test my whole application stack. I've turned off transactional fixtures, and I'm using database cleaner to clean my database only after the whole suite has been run. These allows me to test things based using objects created in preceding tests.
Anyway, let's say I want to create user a999 (via a form, so a test in itself) and then proceed to test logging him out and logging him back in.
def sign_up(first_name, last_name, profile_name, email, password)
visit "/"
click_link "Register"
fill_in('First name', with: first_name)
fill_in('Last name', with: last_name)
fill_in('Profile name', with: profile_name)
fill_in('Email', with: email)
fill_in('Password', with: password)
fill_in('Password confirmation', with: password)
click_button 'Sign up'
end
feature "user a999 sign up", js: true do
before(:each){
sign_up( #a999.first_name, #a999.last_name, #a999.profile_name, #a999.email, #a999.password )
}
scenario "welcome message" do
expect(page).to have_content ("Welcome," + #a999.first_name)
end
scenario "can log out" do
end
scenario "can log in" do
end
end
The code above almost works. This is what happens when it's run:
The before block signs up the user before the "welcome message" expectation (I see it physically happening in Firefox thanks to Selenium), and then the welcome message appears after a redirect so the "welcome message" spec passes.
However, because I have the before block set to 'each' the before block is run another two times, meaning I now have three a999 users in the database.
Of course, and setting the before block to (:all) should fix this problem. The user is signed up one, and we go from there, signing the exact same user in and out. It's a feature test that tests the whole stack remember, so I want to do this properly, emulate how a real user will be using my app.
def sign_up(first_name, last_name, profile_name, email, password)
visit "/"
click_link "Register"
fill_in('First name', with: first_name)
fill_in('Last name', with: last_name)
fill_in('Profile name', with: profile_name)
fill_in('Email', with: email)
fill_in('Password', with: password)
fill_in('Password confirmation', with: password)
click_button 'Sign up'
end
feature "user a999 sign up", js: true do
before(:all){
sign_up( #a999.first_name, #a999.last_name, #a999.profile_name, #a999.email, #a999.password )
}
scenario "welcome message" do
expect(page).to have_content ("Welcome," + #a999.first_name)
end
scenario "can log out" do
end
scenario "can log in" do
end
end
But with this code nothing happens at all. Seriously, just nothing. Selenium doesn't follow the code in the before block at all! Firefox doesn't even start up.
Why is this? I mean, that should work at the very least.
before(:each) = signs user up before my eyes
before(:all) = completely dead
I can't explain why nothing comes up at all, but based on numerous posts*, you can't reasonable use before(:all) with capybara, since it resets the session between each example.
*Related posts:
Capybara and before(:all) in rspec
capybara/selenium with rspec before :all hook

Why is recaptcha not causing this test to fail?

I am using Rails 3.1.0 and the recaptcha gem from here. I was running a cucumber test that checks that users can sign up. Sign up requires users to fill out the captcha. I know that my test does not touch the captcha:
When /^I create a new account with email: "(.*?)" and password: "(.*?)"$/ do |email, pw|
click_link "Sign up"
fill_in "Email", :with => email
fill_in "Password", :with => pw
fill_in "Password confirmation", :with => pw
click_button "Sign up"
end
But the test still passes. I check success by verifying that the successful sign up message is present on the page and the recaptcha failure message is not present using this step:
Then /^I should (not )?see "(.*)"$/ do |negate, text|
if negate
page.should_not have_content text
else
page.should have_content text
end
end
The controller is almost identical to the first one suggested here.
class RegistrationsController < Devise::RegistrationsController
def create
if verify_recaptcha
super
else
build_resource
clean_up_passwords(resource)
flash.now[:alert] = "There was an error with the recaptcha code below. Please re-enter the code."
flash.delete :recaptcha_error
render :new
end
end
end
Is there any reason why recaptcha would not work in the test environment? It seems to work fine in development.
Recaptcha by default does not verify the captcha in the test and cucumber environments (see verify logic, configuration logic, and default value ). If it weren't for this, either testing would be very difficult or the captcha wouldn't be very useful.
Just to add to Bens answer and give a potential workaround:
To make sure things don't work (it "fails with recaptcha") in RSpec I've done
before do
Recaptcha.configuration.skip_verify_env.delete('test')
end
after do
Recaptcha.configuration.skip_verify_env << 'test'
end
Thanks Ben

Resources