Capybara Webkit + Braintree—"Unable to locate frame" - ruby-on-rails

I'm trying to access Braintree's hosted fields with the following code:
within_frame('braintree-hosted-field-number') do
fill_in 'Credit card number', with: '4111-1111-1111-1111'
end
The frame's name is correct, I copied it from the inspect panel on Chrome.
But I get this error
Capybara::Webkit::InvalidResponseError:
Unable to locate frame.
What am I doing wrong? Or, more importantly, how do I debug this/see what's going on?
Edit
Here is my code, as requested. Note that the whole system works fine if I go through and manually fill out the fields and submit the form.
Slim
= f.fields_for :user do |u|
.control-group.col-24.payment-details
label.half
.field-title First Name
= u.text_field :first_name
label.half
.field-title Last Name
= u.text_field :last_name
label.full
.field-title Email for receipt
= u.email_field :email
label.full
.field-title Credit card number
.bt-field#credit-card
label.half
.field-title Expiry date
.bt-field#exp-card
label.half
.field-title CVC
.bt-field#cvv-card
script src="https://js.braintreegateway.com/js/braintree-2.24.0.min.js"
CoffeeScript
braintree.setup(clientToken, "custom", {
id: "donate-form",
onPaymentMethodReceived: (obj)->
formdata = donationForm.getFormData()
formdata.set "payment_method_nonce", obj.nonce
donationForm.send(formdata)
onError: (obj)->
errors = []
switch obj.type
when "VALIDATION"
errors.push "Invalid payment details. Please correct your payment details."
else
errors.push "Something went wrong. Please check your payment details and try again."
donationForm.printErrors("donation-errors", errors)
hostedFields: {
styles: {
"input": {
"font-size": "14px",
"font-weight": "bold",
"font-family": "Lato, Helvetica, Arial, Geneva, sans-serif",
"color": "#464646;",
"transition": colorTransition,
"-webkit-transition": colorTransition
},
".invalid": { color: "#DD0000"} },
number: {selector: "#credit-card"},
cvv: {selector: "#cvv-card"},
expirationDate: {selector: "#exp-card", "placeholder": "dd/mm"}
}
})
Edit 2
donation_module_spec.rb
require "rails_helper"
RSpec.feature "Donation Module", type: :feature do
scenario "Wrong public token" do
visit "/donate?t=BAD_URL&frame=1"
expect(page).to have_content("Are you sure you're installing this on the correct website?")
end
scenario "Public visitor creates a new donation", driver: :webkit do
#load page
website = create(:website)
page.driver.header 'Referer', website.website
visit "/donate?t=#{website.public_token}&frame=1"
#verify page 1 loaded
expect(page).not_to have_content("Are you sure you're installing this on the correct website?")
#fill page 1
find("input[value='20'] ~ div").click
#go to page 2
find("#credit-details").click
#verify page 2 content is loaded
expect(find(".total-cost-text")).to be_visible
#fill page 2
fill_in 'First Name', with: 'Leeroy'
fill_in 'Last Name', with: 'Jenkins'
fill_in 'Email for receipt', with: 'new_donor#email.com'
sleep 5
within_frame('braintree-hosted-field-number') do
fill_in 'Credit card number', with: '4111-1111-1111-1111'
end
within_frame('#braintree-hosted-field-expirationDate') do
fill_in '#expiration', with: '09/19'
end
within_frame('#braintree-hosted-field-cvv') do
fill_in '#cvv', with: '123'
end
find('Make payment').click
# expect to make a new user, new donation, new receipt, emailed receipt
end
end
rails_helper.rb
Modified to show only the related parts:
require 'capybara/rails'
require 'capybara/rspec'
Capybara::Webkit.configure do |config|
config.allow_url("js.braintreegateway.com")
config.allow_url("fonts.googleapis.com")
config.allow_unknown_urls
config.debug = true
end
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false

Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
I don't have an answer for you as to why this might be happening, copying your setup I'm able to get it to work. I do have a couple of additional thoughts that may help.
1) Take a look at the debug output (looks like you already have this enabled with config.debug = true) and make sure there are no errors. Here are the relevant parts of my output -
"Visit(http:/localhost:3000/hostedfields_payment)" started page load
Started request to "http://localhost:3000/hostedfields_payment"
Finished "Visit(http:/localhost:3000/hostedfields_payment)" with response "Success()"
Started request to "https://js.braintreegateway.com/js/braintree-2.17.5.js"
Started request to "https://api.sandbox.braintreegateway.com/merchants/-/client_api/v1/configuration?-
Received 200 from "https://api.sandbox.braintreegateway.com/merchants/-/client_api/v1/configuration?-
Received "FrameFocus(braintree-hosted-field-number)"
Load started
Started request to "https://assets.braintreegateway.com/hosted-fields/2.17.5/hosted-fields-frame.html#91586a91-c55f-4e51-80e6-7cd750f9c750"
Started request to "https://assets.braintreegateway.com/hosted-fields/2.17.5/hosted-fields-frame.html#91586a91-c55f-4e51-80e6-7cd750f9c750"
Started request to "https://assets.braintreegateway.com/hosted-fields/2.17.5/hosted-fields-frame.html#91586a91-c55f-4e51-80e6-7cd750f9c750"
"TimeoutCommand" waiting for load to finish
Started request to "https://assets.braintreegateway.com/hosted-fields/2.17.5/braintree-hosted-fields-internal.min.js"
Received 200 from "https://assets.braintreegateway.com/hosted-fields/2.17.5/hosted-fields-frame.html#91586a91-c55f-4e51-80e6-7cd750f9c750"
Received 200 from "https://assets.braintreegateway.com/hosted-fields/2.17.5/hosted-fields-frame.html#91586a91-c55f-4e51-80e6-7cd750f9c750"
Received 200 from "https://assets.braintreegateway.com/hosted-fields/2.17.5/hosted-fields-frame.html#91586a91-c55f-4e51-80e6-7cd750f9c750"
Received 200 from "https://assets.braintreegateway.com/hosted-fields/2.17.5/braintree-hosted-fields-internal.min.js"
Page finished with true
Load finished
Started "FrameFocus(braintree-hosted-field-number)"
Finished "FrameFocus(braintree-hosted-field-number)" with response "Success()"
Wrote response true ""
Received "FindCss(input#credit-card-number)"
Started "FindCss(input#credit-card-number)"
Finished "FindCss(input#credit-card-number)" with response "Success()"
2) A gnarly way you could check is at the end your sleep 5, print the body to a file and open it up. You can check that the iframes exist.
File.open("looking_for_iframes.html", "w") do |file|
file.print(page.body)
end
Otherwise feel free to reach out to Braintree Support.

Related

Rspec feature test: Cannot visit a path

I have rspec features tests that are all failing because i cannot visit the indicated path. They all seems to be stuck at the root path after logging in. A screenshot shows that the page still remains on the root path. The test steps work on the browser, which means that the routing is correct. Any ideas?
I am getting the below error message for the test:
Failure/Error: page.evaluate_script('jQuery.active').zero?
Extract of my feature spec test:
describe 'follow users' do
let!(:user) { FactoryGirl.create(:user) }
let!(:other_user) { FactoryGirl.create(:friend) }
describe "Managing received friend request", js: true do
let!(:request) { Friendship.create(user_id: other_user.id, friend_id: user.id, accepted: false) }
before do
login_as(user, :scope => :user)
visit followers_path
end
it 'friend request disappear once user clicks accept' do
click_on "Accept"
wait_for_ajax
expect(current_path).to eq(followers_path)
expect(page).to have_css(".pending-requests", text: "You have 0 pending friend requests")
expect(page).to_not have_css(".pending-requests", text: other_user.name)
expect(page).to_not have_link("Accept")
expect(page).to_not have_link("Decline")
end
end
end
The issue here is you're calling 'wait_for_ajax' either on a page that doesn't include jQuery or at a time when it hasn't yet been loaded. The solution is to stop using wait_for_ajax and instead use the Capybara expectations/matchers as designed. There are very very few cases where wait_for_ajax is actually needed and even then it's usually a sign of bad UI decisions (no indication to the user something is happening). You should also not be using the eq matcher with current_path and should be using the Capybara provided have_current_path matcher instead since it has waiting/retrying behavior like all of the Capybara provided matchers.
it 'friend request disappear once user clicks accept' do
click_on "Accept"
expect(page).to have_current_path(followers_path)
expect(page).to have_css(".pending-requests", text: "You have 0 pending friend requests")
expect(page).to_not have_css(".pending-requests", text: other_user.name)
expect(page).to_not have_link("Accept")
expect(page).to_not have_link("Decline")
end
If that doesn't work for you, then either the button click isn't actually triggering page changes (check your test log), your Capybara.default_max_wait_time isn't set high enough for the hardware you're testing on, your login_as statement isn't actually logging in the user (although then I would expect the click on the accept button to fail), or you have a bug in your app.
If it's that login_as isn't actually logging in then make sure the server being used to run the AUT is running in the same process as the tests, if you're using puma that means making sure in the output it doesn't say it' s running in clustered mode.
Try to this approach to wait for all the ajax requests to finish:
def wait_for_ajax
Timeout.timeout(Capybara.default_wait_time) do
active = page.evaluate_script('jQuery.active')
until active == 0
active = page.evaluate_script('jQuery.active')
end
end
end
Taken from: Wait for ajax with capybara 2.0

Rails + Capybara + Braintree—how to feature test BT's Hosted Fields?

TL;DR—How do I access fields within Braintree's Hosted Fields' iframes?
I want to test a UX flow of paying a donation through Braintree. This is my code so far:
require "rails_helper"
RSpec.feature "Donation Module", type: :feature do
scenario "Public visitor creates a new donation" do
#load page
website = create(:website)
Capybara.current_session.driver.header 'Referer', website.website
visit "/donate?t=#{website.public_token}&frame=1"
#verify page loaded
expect(page).not_to have_content("Are you sure you're installing this on the correct website?")
#fill page 1
find("input[value='20']").click
#go to page 2
find("#credit-details").click
#verify page 2 content is loaded
expect(find(".total-cost-text")).to be_visible
#fill page 2
fill_in 'First Name', with: 'Leeroy'
fill_in 'Last Name', with: 'Jenkins'
fill_in 'Email for receipt', with: 'new_donor#email.com'
within_frame('#braintree-hosted-field-number') do
fill_in '#credit-card-number', with: '4111-1111-1111-1111'
end
within_frame('#braintree-hosted-field-expirationDate') do
fill_in '#expiration', with: '09/19'
end
within_frame('#braintree-hosted-field-cvv') do
fill_in '#cvv', with: '123'
end
find('Make payment').click
# expect to make a new user, new donation, new receipt, email receipt
end
end
Currently, it's breaking at the first within_frame saying Capybara::NotSupportedByDriverError:
Capybara::Driver::Base#within_frame
How do I access fields inside BT's iframes?
Well, I am writing here not exactly an answer to this question, but rather corrections to the question, as I was in the similar situation and was facing similar errors such as Selenium::WebDriver::Error::NoSuchFrameError: Unable to locate frame: #braintree-hosted-field-number and Test::Unit::Capybara::ElementNotFound: Unable to find field "#credit-card-number".
The within_frame should have the following format (the #-sign for ID should be removed from both):
within_frame('braintree-hosted-field-number') do
fill_in 'credit-card-number', :with => number
end
And in order to use the selenium driver in Test::Unit, I used the following helper:
def js
Capybara.current_driver = Capybara.javascript_driver
yield
Capybara.current_driver = Capybara.use_default_driver
end
And then wrapped my tests in it:
class SomeTest < ActionDispatch::IntegrationTest
test "should ..." do
js do
within_frame('braintree-hosted-field-number') do
fill_in 'credit-card-number', :with => number
end
# ...
end
end
Hopefully, someone will find it useful while using Unit Tests.
Seems like you're using the rack_test driver? That doesn't support JS or frames so braintree isn't going to work with that. You need to switch to one of the real browser drivers like selenium, capybara-webkit, or poltergeist.

Poltergeist capybara view testing taking long time when running all test in spec in ruby on rails

I'm using capybara with poltergeist for rspec testing in ruby on rails.
We're using stripe for payment gateway.
Request to stripe in already stub and real http connections are disabled.
However when I run the spec file alone.
It passes with the following test result.
Can add billing information to my account
Finished in 14.27 seconds (files took 4.84 seconds to load)
1 example, 0 failures
But when I run all the test it fails due to long time delay for response and I'm getting this output.
Failures:
My code-
scenario "Can add billing information to my account", js: true do
within "#top-menu" do
click_link "ACCOUNT"
end
click_link "Billing"
click_link "Add billing information"
within "#subscription" do
fill_in "Name", with: "John Smith"
fill_in "Email", with: "john.smith#example.com"
fill_in "Phone number", with: "0443 123123"
fill_in "Company", with: "Cribber"
fill_in "Street address", with: "14 Somewhere Street"
fill_in "City", with: "Brisbane"
fill_in "Postcode / Zip", with: "4000"
fill_in "State", with: "QLD"
select "Australia", from: "Country"
select "Australian Dollar", from: "Currency"
fill_in "Card number", with: "4242424242424242"
select Time.now.year + 1, from: "card_expiry_year"
fill_in "CVC", with: "123"
check "subscription_billing_attributes_terms_of_service"
end
click_button "Subscribe"
expect(page).to have_content("Thank you for subscribing to Cribber!")
end
I added sleep(200) after click_button "Subscribe".But it showed the following result.
Can anyone please help?
Thanks in advance for helping.
I tried changing http://localhost to http://127.0.0.1 in .env.test file but I got these error.
The strange thing is that if I run the spec file alone or the feature folder for view spec then I get no error message and the test pass.But if I run
rspec spec/ then the test fails.
Can anyone help?
It looks like the error is explained in your screenshot - while localhost and 127.0.0.1 point to the same place they are technically different origins. You need to find where you're setting the app to make a request to http://localhost/... and change it to 127.0.0.1

Rspec/Capybara not finding inputs

Capybara is acting really strange.
It wasn't finding any input fields at all, ID, name or label. So I changed the test to just check what was rendering and get a huge sass error.
feature "new users are not admin" do
scenario "user signs up" do
visit new_user_registration_path
#fill_in "Username", :with => "newuser"
#fill_in "Email", with: "newuser#example.com"
#fill_in "Password", with: "newuserpassword"
#fill_in "Password Confirmation", with: "newuserpassword"
#click_button "Sign up"
expect(page).to have_content("Sign Up")
end
end
And then this:
Failure/Error: expect(page).to have_content("Sign Up")
expected to find text "Sign Up" in "Sass::SyntaxError at /users/sign_up =================================== > Invalid CSS after \"\": expected selector, was \"===============...\" (in app/assets/stylesheets/application.css) app/views/layouts/application.html.erb, line 5 ---------------------------------------------- ``` ruby 1 2 3 4 > 5 true %> 6 true %> 7 8 9 10 ```
Which is actually a lot more, and seems to be the contents of the error page rails produces (better_errors), but only in tests, not when visiting the actual application. This is also only when the fill_in/click_button is commented out, otherwise it will be "could not find field 'username' etc.
The sass error has "============" in it which is part of how I split my css in sections with a large comment block e.g.
/*=============
Styles
==============*/
But this is all commented out. I don't see what it would cause a problem.
I have no idea what's going on. Any help is appreciated.
Fixed this, it was, for some reason, an un-commented section in bootstrap.css (that for some reason doesn't render an error except via tests).
Works as intended now

Capybara/Poltergeist causing unexpected results in request spec in Rails 3.2 app

Is there an alternative I can use to Capybara's save_and_open_page? I have written a request spec that test the user signup form. Upon successful signup, which this test should yield, this test should be passing, but it's not.
Yet when I do save_and_open_page at the end, all the form fields are blank. I can mirror this in the development environment doing the data entry myself and everything passes, so I am struggling to understand what's wrong. I can't afford to let this go because obviously this is a critical test.
I've only been doing TDD for a little while, so any tips or tricks about this stack (Capybara and Poltergeist) would be helpful. I am not having similar difficulties in other request specs using the same stack.
Here is the request spec:
it 'allows a user to subscribe', js: true do
visit root_url
click_link "Pricing"
click_button "Subscribe", match: :first
fill_in "First name", with: "Marky"
fill_in "Last name", with: "Mark"
fill_in "Company", with: "The Funky Bunch"
fill_in "subscription_email", with: "marky.mark#thefunkybunch.com"
fill_in "Password", with: "MyString"
fill_in "Password confirmation", with: "MyString"
fill_in "Credit Card Number", with: "4242424242424242"
fill_in "Security Code on Card (CVV)", with: "123"
select "July", from: "Card Expiration"
select "2014", from: "card_year"
check "chkACCEPT"
click_button "Subscribe to myapp"
# The line below fails, but a save_and_open page just shows a blank form
current_path.should_not eq(new_subscription_path)
page.should have_content("Thank You")
end
Poltergeist provides screenshots which can be used instead of save_and_open_page:
save_screenshot('/path/to/file.png', :full => true)
However your comment "# The line below fails" seems very consistent to "save_and_open page just shows a blank form".

Resources