How to properly evaluate if a page has certain content with capybara? - ruby-on-rails

I am currently trying to evaluate the result of clicking the "Pay" button on my site with Capybara if the form has invalid params. It seems like the test is doing everything correctly, filling out all fields correctly, clicking the "Pay" button, but then it is not "seeing" my .alert selector with the text "Email can't be blank, Email is invalid". I am not sure why it is not "seeing" this. Its as if its not even there. My controller is setting flash and then rendering the page with the flash method. Is Capybara trying to evaluate if the current page has the flash? The code for my current test is below. Any help is appreciated. Ive been going through the documentation but must be missing something about expect().
feature "order features", type: :feature do
feature "making a new order" do
before(:each) do
visit "/orders/new"
end
scenario "with invalid params", js: true do
fill_in "Your Name *", with: "Benedict Cumberbatch"
select("CAM Academy", from: 'order_school_name')
fill_in "Street Address *", with: "221b Baker St."
fill_in "City", with: "Vancouver"
select("WA", from: 'order_state')
fill_in "Zip code *", with: "98671"
fill_in "groupNumberBooks", with: 1
fill_stripe_elements(card: '4242 4242 4242 4242', selector: "#card-element-1 > div > iframe")
click_button "Pay"
expect(page).to have_selector('.alert', text: "Email can't be blank, Email is invalid")
end
end
end
On a side note, I have also tried expect(page).to have_content("Email can't be blank"). This also does not work. What am I missing here?
edit: the exact error message I am getting is:
Failures:
1) order features making a new order with invalid params
Failure/Error: expect(page).to have_selector('alert', text: "Email can't be blank, Email is invalid")
expected to find css "alert" but there were no matches
# ./spec/features/order_features_spec.rb:19:in `block (3 levels) in <top (required)>'
I have gone to the specified path and have manually filled out these fields and have evaluated what is being presented on the page when the render is called and the flash[:alert] is set.

It sounds like your test is probably hitting the real stripe (sandbox instance) which means the failure is going to take longer than most of your tests. This means that Capybara.default_max_wait_time isn't long enough for the page to actually update to show the error message. You could increase Capybara.default_max_wait_time or you can tell individual expectations to allow longer wait times for a match using the wait parameter
expect(page).to have_selector('.alert', text: "Email can't be blank, Email is invalid", wait: 20)
which will wait up to 20 seconds for the expected element to appear on the page

Related

How do I confirm a css element attribute with Capybara?

This may seem unusually basic but how do I confirm the presence of a pop up confirmation?
<a data-confirm="delete this video?" rel="nofollow" data-method="delete" href="/videos/21">Delete</a>
<a is the "tag"/"element" and data-confirm is an attribute. I want to test for the existence of the "data-confirm" attribute within the <a> element/tag
I have tried
expect(page).to have_css("a.data-confirm.delete this video?")
from
capybara assert attributes of an element
but no joy.
Edit:
I've tried the expectation from Arup's comment below
expect(page).to have_content "Content"
click_link "Delete"
expect(page).to have_css('a[data-confirm="delete this video?"]')
But it raises the following (same) error
Failures:
1) Visiting the video index page should search and save movies
Failure/Error: expect(page).to have_css('a[data-confirm="delete this video?"]')
expected #has_css?("a[data-confirm=\"delete this video?\"]") to return true, got false
but the page source shows it there and it is clearly working for the user
Any assistance would be very appreciated
You can write this expectation as:
expect(page).to have_css('a[data-confirm="delete this video?"]')
The answer by Arup is correct for the title of the question (and as he stated in the comments it's just valid CSS - https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors), however it's not actually testing the more detailed part of the question "how do I confirm the presence of a pop up confirmation". All it is doing is confirming the correct data attribute is on the link element to trigger the rails provided JS that should show a confirm.
If you wanted to actually test the confirm box is shown you would need to swap to using a JS capable driver - https://github.com/teamcapybara/capybara/tree/2.17_stable#drivers - and then use something like the following in your test
expect(page).to have_content "Content"
accept_confirm "delete this video?" do
click_link "Delete" # The action that will make the system modal confirm box appear
end
See - http://www.rubydoc.info/gems/capybara/Capybara/Session#accept_confirm-instance_method

Toggling a Bootstrap collapsible is failing in Rails/Capybara feature tests

I'm new to Capybara and feature testing. I've been trying test a minor feature on a Rails app that toggles comments on a post into and out of view. The first test for toggling the comments into view passes, but the second test for toggling them out of view doesn't. (I am using the headless-chrome webdriver).
context 'viewing comments', js: true do
scenario 'toggling comments into view' do
#post.comments.create(body: 'This is a comment.', user_id: #commenter.id)
visit authenticated_root_path
click_button 'Toggle comments'
expect(page).to have_content('This is a comment')
end
scenario 'toggling comments out of view' do
#post.comments.create(body: 'This is a comment.', user_id: #commenter.id)
visit authenticated_root_path
click_button 'Toggle comments'
expect(page).to have_content('This is a comment')
click_button 'Toggle comments'
expect(page).to_not have_content('This is a comment')
end
end
Initially, I had click_button 'Toggle comments' twice, back-to-back. Neither iteration of the test work. I also tried using sleep n in between the two actions, but to no avail.
Failures:
1) Comment management viewing comments toggling comments out of view
Failure/Error: expect(page).to_not have_content('This is a comment')
expected not to find text "This is a comment" in "OdinFB PROFILE REQUESTS 0 LOG OUT The Feed Create post Luna Lovegood said... Body of post 0 Likes 1 Comments Like Comment Share Toggle comments This is a comment. Morfin Gaunt on Sep 18 2017 at 4:22PM"
The button itself works when the app is fired up locally. It appears to become inactive once activated the first time around in testing.
Any insight would be appreciated, and thanks for reading.
What's happening here is the second button click is occurring after the expected text becomes visible on the page but before the animation has completed. The bootstrap collapse code then gets confused and doesn't collapse the comments since it considers them not fully opened yet. A sleep for a second or so immediately before the second click_button will fix this since it delays long enough for the animation to complete. The other option (and better from a test time perspective) is to disable animations in test mode.

Testing ruby with rails, Element not found

I get the error:
Capybara::ElementNotFound:
Unable to find field "user_email"
And this is the test code:
feature 'User' do
given!(:user) { User.new(email: 'testuserid#example.com', encrypted_password: 'test') }
scenario 'opens sign_up page' do
visit new_user_session_path
expect(page).to have_content 'unique text on the page'
end
scenario 'signs in with invalid email' do
visit new_user_session_path
fill_in('user_email',with: 'ssd')
expect(page).to have_content 'unique text on the page'
end
end
My HTML file consists of this code literally:
unique text on the page
<br>
<input type="text" id="user_email">
So this proves that the path is correct because my first scenario runs correctly. It is visiting the right page. But still I get this error for second scenario in fill_in.
I have also tried element = page.find("user_email"), it gives same error.
What am I possibly doing wrong?
I have been scratching my head like hell.
Usually the reason for this is that the input isn't actually visible on the page. You can verify this by doing
fill_in('user_email', with: 'ssd', visible: false)
If that succeeds in finding the element, then you need to change your test to first perform whatever actions make the field visible before attempting to fill it in.
Your code seems right. Maybe you are visiting wrong url or you have used user_email id once more. But you can give a try with alternative syntax like following :
find("input[id$='user_email']").set "ssd"

Devise/Capybara Ambiguous match

I am using devise to create a sign up wizard,
but capybara(2.0.2) raises
Feature: Signing up
In order to be attributed for my work
As a user
I want to be able to sign u
Scenario: Signing up
Given I am on the homepage
When I follow "Sign up"
And I fill in "Email" with "user#ticketee.com"
And I fill in "Password" with "password"
Ambiguous match, found 2 elements matching field "Password" (Capybara::Ambiguous)
./features/step_definitions/web_steps.rb:10:in `/^(?:|I )fill in "([^"]*)" with "([^"]*)"$/'
features/signing_up.feature:10:in `And I fill in "Password" with "password"'
And I fill in "Password confirmation" with "password"
And I press "Sign up"
Then I should see "You have signed up successfully."
step definition is
When /^(?:|I )fill in "([^"]*)" with "([^"]*)"$/ do |field, value|
fill_in(field, :with => value)
end
With Capybara 2.1, this works:
fill_in("Password", with: '123456', :match => :prefer_exact)
fill_in("Password confirmation", with: '123456', :match => :prefer_exact)
From here :prefer_exact is the behaviour present in Capybara 1.x. If multiple matches are found, some of which are exact, and some of which are not, then the first eaxctly matching element is returned.
In version 2.0 Capybara's find method raises a Capybara::Ambiguous exception when several elements matching specified locator where found. Capybara doesn't want to make an ambiguous choice for you.
The proper solution is to use another locator (e.g. find('#id').set('password') or fill_in('field_name', with: 'password')
Read "Ambiguous Matches" section of Capybara 2.0 Upgrade guide for a bit longer explanation of the same.

Capybara + Webkit: How to test client side validations - "required" input elements?

Using Rspec and Capybara, I'm trying to test a failing validation for a form, where a "required" input is not filled in, so it fails. New navigators understanding HTML5 provide built-in validations, and I understand Capybara is using that as well. Before, I was using
page.should have_error
which doesn't work for me anymore.
Someone knows how to test this now?
Many thanks!
David
HTML5 client side validations are tricky to find. I found this post with a great answer.
The code is:
describe "when I leave required field empty" do
it "I get an the correct html5 validation error" do
#Leave the field empty
click_on "Save" # or whichever button triggers the submit
message = page.find("#field_id_attr").native.attribute("validationMessage")
expect(message).to eq "Please fill out this field."
end
end
Basically the way it works is that the field element has an attribute called "validationMessage" and the process is:
Click submit - this triggers the error message
Get a reference to the native(html) attribute(as opposed to the Capybara page object attribute) called "validationMessage". This will give you the value or the message itself.
Assert that the value is as expected.
I am not familiar with RSpec so I am not sure about what does have_error.
You should think about what you want to test exactly.
You surely don't want to test the exact behavior (what message is displayed, and how) as it is specific to each browser. What you want to test, because this is not specific to the browser, is the fact that the form is not submitted.
For instance, for a basic html form at root, with a required radio button "My value".
# Check form can not be submitted without the radio button
visit '/'
click_button 'Submit'
assert_equal '/', current_path
# Check form can be submitted with the radio button
visit '/'
choose 'My value'
click_button 'Submit'
assert_equal '/next', current_path
You should also consider to test only the presence of required in your html code, as the browser is supposed to work as expected (test only your code, not other's code)
If there is an error message, you can something along the lines of
page.should have_content("error")
This depends on how you handle the errors, and whether you use javascript or not.
This is an old post, however I will try to answer it
have_error is a method provided by webkit, to check e.g. if ajax requests or javascript in general running fine
I use to test my validations in my model specs:
describe 'validations' do
it { is_expected.to validate_presence_of :competitor_name }
it { is_expected.to validate_presence_of :chassi }
it { is_expected.to validate_presence_of :auction }
it { is_expected.to validate_presence_of :car_template_id }
end
or like
expect(FactoryGirl.create(:customer)).to be_valid
to check if my Factory is valid.
If you need to check your notices by targeting invalid inputs, you could test the html of your notice by capybara with the following:
it 'searches for specific order_car by chassi and model' do
visit order_cars_search_detailed_path
fill_in 'order_car_chassi', with: '123456'
select 'Octavia', from: 'order_car_car_template_car_template_id'
click_button 'Search Order'
expect(page).to have_content('THIS IS MY NOTICE')
expect(page).to have_content('123456')
end
Hope I could help some others running into this question.

Resources