How do I confirm a css element attribute with Capybara? - ruby-on-rails

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

Related

Capybara testing with RSpec in Ruby

on my index page I have this div:
<div class="banner">
<h1 class="glow-header">Galaxy Far, Far Away? Quick Trip to Mars?<br>
Pianeta has you covered.</h1>
<div>
In my testfile this works:
RSpec.describe 'home features' do
it 'displays the name of the app and links to the index-all planets page' do
visit root_path
expect(page).to have_content('Space is full of surprises.')
click_link('Go Beyond')
expect(current_path).to eq('/planets')
expect(page).to have_content('Galaxy Far, Far Away?')
end
end
But I would like it to be working with the h1 included.
I did this:
expect(page).to have_content('<h1 class="glow-header">Galaxy Far, Far Away? Quick Trip to Mars?<br>
Pianeta has you covered.</h1>')
end
But the test failed. What did I do wrong ?
The #has_content?/#has_text? method only checks the text content of the page. It does not look at the HTML tags.
If you want to check for content within a specific HTML element there is a #within method that takes a block and will scope the Capybara lookups within it to be within the matched element. The element referenced by #within must exist or Capybara will raise an exception.
page.within('h1.glow-header') do
expect(page).to have_content('Galaxy Far, Far Away?')
end
If you don't want to deal with scoping using within for a single expectation you could do
expect(page).to have_css('h1.glow-header', text: 'Galaxy Far, Far Away?')
If you've already got a reference to the header you could also do something like
header = find('h1.glow-header')
...
expect(header).to have_text('Galaxy Far, Far Away?')
Additionally you should not be doing expect(current_path).to eq('/planets'). Using RSpecs eq matcher with Capybara will lead to flaky tests as soon as you move to using an asynchronous (JS supporting) driver, because it prevents Capybaras auto waiting/retrying behaviors. Instead you should use the Capybara provided matcher
expect(page).to have_current_path('/planets')

Capybara: click on element found by the icon class

I would like to check that, when click an icon link, the current_path is the path of the 'show' action.
So, given this HTML:
<a class="btn btn-xs" href="/admin/hotels/1">
<i class="fa fa-eye fa-lg"></i>
</a>
And this capybara test:
describe "GET /hotels", js:true do
before :each do
#hotel = create(:hotel)
visit admin.hotels_path
end
it "eye icon links to show" do
find(:css, 'i.fa.fa-eye.fa-lg').find(:xpath,".//..").click
expect(current_path).to eq(admin.hotel_path(#hotel))
end
end
I receive this error message:
1) Hotels index hotel creation GET /hotels eye icon link to show
Failure/Error: expect(current_path).to eq(admin.hotel_path(#hotel))
expected: "/admin/hotels/560bb674467261c7a4000002"
got: "/admin/hotels"
I deduce that find(:css, 'i.fa.fa-eye.fa-lg').find(:xpath,".//..").click is not working as I expect.
The execution of find(:css, 'i.fa.fa-eye.fa-lg').find(:xpath,".//..") is returning:
=> #<Capybara::Element tag="a">
Am I doing something wrong?
The reason the test fails with :js is because clicking the link does only that. It doesn't wait for the results of the click (loading the new page). Because of that calling current_path immediately after still gets the original path. Removing the :js stops using poltergeist and instead uses rack-test which is synchronous but lacks a lot of real browser behavior. In capybara 2.4 you would have needed to check for content that would be on the show page and once that appeared then get the current path, however capybara 2.5 has the have_current_path matcher which will utilize capybaras waiting behavior. Also there is no need to click on the a element, clicking on its contents like a user would do should work just fine. So
find(:css, 'i.fa.fa-eye.fa-lg').click
expect(page).to have_current_path(admin.hotel_path(#hotel))
should work both with and without :js
The problem is:
describe "GET /hotels", js:true do
I've replaced it to:
describe "GET /hotels" do
And then it uses poltergeist fine, without errors.

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"

Unable to find css "ul#items li:first" (Capybara::ElementNotFound)

I have inherited an Rails app, but am unfamiliar with this particular test environment. When the cucumber tests are run we get:
Scenario: Add only an image to a profile by url # features/add_an_image_by_file_url.feature:11
Given I am logged in as a user "admin" # features/step_definitions/user_steps.rb:19
And I create a profile for "Joe Blogs" # features/step_definitions/profile_steps.rb:1
And I have a fake image url "http://fake.com/images/profile.jpg" # features/step_definitions/photo_steps.rb:1
When I follow "New photo" # features/step_definitions/web_steps.rb:32
And I fill in "Url" with "http://fake.com/images/profile.jpg" # features/step_definitions/web_steps.rb:38
And I press "Create" # features/step_definitions/web_steps.rb:26
Then I should see "Photo was successfully uploaded." # features/step_definitions/web_steps.rb:99
And I should see "profile.jpg" within first profile item # features/step_definitions/item_steps.rb:18
Unable to find css "ul#items li:first" (Capybara::ElementNotFound)
(eval):2:in `find'
./features/step_definitions/web_steps.rb:13:in `with_scope'
./features/step_definitions/web_steps.rb:100:in `/^I should see "([^\"]*)"(?: within "([^\"]*)")?$/'
features/add_an_image_by_file_url.feature:19:in `And I should see "profile.jpg" within first profile item'
This come from item_steps:
Then /^I should see "([^\"]*)" within (.*?) profile item$/ do |string, filter|
Then %Q{I should see "#{string}" within "ul#items li:#{filter}"}
end
And web steps concerned:
Then /^I should see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, selector|
with_scope(selector) do
if defined?(Spec::Rails::Matchers)
page.should have_content(text)
else
assert page.has_content?(text)
end
end
end
The HTML in question look like this:
<ul id='items'>
<li class='note clearfix'>
<div class='content'>
<img src="profile.jpg"/>
</div>
</li>
</ul>
What on Earth is going on here?
Well, "what's going on here" is pretty simple:
cucumber executes each step of the scenario using matched step definition
everything goes ok, until
it executes "I should see "profile.jpg" within first profile item"
during this step, cucumber goes to the matched step definition in item_steps
that definition in item_steps calls another step definition from web_steps
this last one checks if the page does really have the given content inside the given scope
and the check fails...
I suppose, the interesting question is "why it doesn't work". Very similar css selector works fine for me when I used it in my cucumber/capybara scenario.
Are you sure the HTML code is really displayed in the browser? There is no conditions in template or in controller which could prevent it from being displayed? What happens when you change 'ul#items li:first' to something more simple, say just 'ul#items'?
Update: the problem is really very simple: profile.jpg IS NOT a text content - it's an "invisible" html code. The only error you have is scenario itself.

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