Capybara: click on element found by the icon class - ruby-on-rails

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.

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')

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.

Capybara and remote links

I have this link in records_path page:
link_to "CLICK HERE", edit_record_path(record), remote: true
The controller:
def edit
puts request.format # Just to show you part of the issue
end
And when clicked, it executes the edit.js.coffee and renders a modal for editing the record.
It works great. The problem I have is with Capybara.
context 'when on records list page' do
before { visit records_path }
context 'when clicking on "CLICK HERE"', js: true do
before { click_link('CLICK HERE') }
it 'shows the record name' do
expect(page).to have_content record.name
end
end
end
When I run the test, it raise an error:
Capybara::ElementNotFound: Unable to find link "CLICK HERE"
But if I remove the js: true from the context, it works (It executes the edit method on the RecordsController) but the printed format is html instead of js. I don't even have an edit.html, I just have the edit.js.coffee and that is the one that should be rendered in the test.
What am I doing wrong? If the link has the remote: true prop, and the test has the js: true shouldn't be enough for make it work?
In your setup you don't actually create a record. I am assuming this is the cause of your problem. The edit_record link will not show up if you do not have records to edit. I could be wrong but from what you pasted I think this could be the cause.

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"

Resources