Capybara can not find element by id - ruby

Capybara is not able to find a <p> tag by it's id in my cucumber test. I'm able to see the element when I save_and_open_page. But I can't locate it with has_css? or find:
pry(#<Object>)> page.html.scan(/notice_sent/).count
=> 1
pry(#<Object>)> page.html.scan(/id=\"notice_sent\"/).count
=> 1
pry(#<Object>)> page.find('#notice_sent')
Capybara::ElementNotFound: Unable to find css "#notice_sent"
from /Users/me/.gem/ruby/2.1.7/gems/capybara-2.4.4/lib/capybara/node/finders.rb:41:in 'block in find'
What am I missing?

By default Capybara doesn't find elements that are not visible on the page. You can try
page.find('#notice_sent', visible: :all)
to see if that's the case. If so, and you're testing an app, then you should perform whatever actions a user would perform that would make that element visible, and then check for its presence.

Though I am a newbie to Capybara, I think this might work for you !!
page.find('#notice_sent', :visible => false)
Also, add this code to your env.rb file.
Capybara.ignore_hidden_elements = false

The accepted answer is good in most cases, however, there are times that elements may dynamically present; and not just hidden. When using find and the element is not present we get an error very similar to when it is present, but hidden. How do we handle that case?
Capybara::Node::Finders#all Also known as: find_all, has the same visibility option as find, but will not throw an error when there are no matches.
page.all('#notice_sent', visible: :all)
This is very similar to where vs find in ActiveRecord, and there are uses for both approaches.
if you want to return the matching element or nil instead of an Array / collection, then you can append first and get a result that closer matches the behavior of find without the error.
page.all('#notice_sent', visible: :all).first

I think, it is time to update capybara for the very beginning.
And, I can not test it out now, but try page.html.find('#notice_sent')

Related

How can I get Watir to make a fresh reference on a non-stale element?

A portion of some tests I am writing calls for checking if an option gets removed from a select list once that option has been used. I am inconsistently getting this error: timed out after 60 seconds, waiting for {:xpath=>"//select[#id = 'newIdentifierType']//option", :index=>31} to be located (Watir::Exception::UnknownObjectException)
It causes my test to fail maybe 2-3 times out of 10 runs and seems kind of random. I think Watir is looking for the "old" select list with this ID since it caches the element and may also include that it had 32 items, but it times out since a select list with this ID and 32 items no longer exists. The new select list has the same ID but only 31 items.
Is there a way to always get a new reference on this element even though it's not technically going stale? Am I experiencing this problem due to a different issue?
My current code for getting the options in the select list:
#browser.elements(:xpath => "//select[#id = 'newIdentifierType']//option")
I am using Ruby/Cucumber with Selenium and Watir Webdriver level. I first tried defining the element as a select_list in a page-object but moved it to the step definitions using #browser.element to see if that would stop the timeout. I thought it may ignore Watir's cached elements and get the most current one with the ID, but that does not appear to be the case.
Please avoid using XPath with Watir. Everything you can do with XPath, Watir has a much more readable API to handle.
To check for a specific option not being there, you should avoid collections and locate directly:
el = browser.select_list(id: "newIdentifierType").option(value: "31"))
# or
el = browser.select_list(id: "newIdentifierType").option(text: "This one"))
Then to see if it has gone away:
el.stale?
# or
el.wait_until(:stale?)
That won't test the right thing if the entire DOM has changed, though, so you might need to just relocate:
browser.select_list(id: "newIdentifierType").option(text: "This one")).present?
If you are intent on using a collection, the correct way to get the list of options is:
options = #browser.select(id: 'newIdentifierType').options
el = options.find { |o| o.text == 'This one' }
# Do things
el.stale?

Make 1 page objects Two Elements ID's to 1 page object Variable

I am using the page object Gem with Watir. During testing I found that I have a field that has the same contents that show in the same location but have separate unique ID's. The difference is before you get to the page.
I tried using Xpaths:
select_list(:selectionSpecial, :xpath => "//select[#id='t_id9' OR #id='t_id7']")
But was met with a script error.
They are static ID's but I want to force them into one variable since that would allow me to use "populate_page_with" feature.
I have a long winded way currently, but I am fishing for a more efficient way that works with the page object Features.
Does anyone know of a way to do this?
Your approach of using xpath can work. The problem is the syntax errors in the xpath selector. It should be:
"//select[#id='t_id9' or #id='t_id7']"
Note:
The start should be a // rather than a \
Using or is case-sensitive; it has to be lower case
There was also a missing closing ' for the first id attribute
Personally, I find css and xpath selectors harder to use. I would go with the id locator with a regex. The following gives the same results, but some will find it easier to read.
select_list(:selectionSpecial, :id => /^t_id(7|9)$/)

#driver.find_element(:id=>"body").text.include?(textcheck) not verifying the text only the id

I am using Selenium-WebDriver for Ruby and I am trying to verify that text is present on a page. I have done many searches and tried many things and the best answer I have found is to use something like
def check_page(textcheck)
if verify {#driver.find_element(:id=>"body").text.include?(textcheck)}
yield it_to "fail"
else
yield it_to "pass"
end
end
The expected outcome if the value of textcheck is present in the body would be pass and if the value of textcheck is not present in the body it would be fail. What is actually happening is if :id=>"body" is present then it is pass and if it is not present then it is fail regardless of .text.include?(textcheck)
If anyone could point me in the right direction for how to verify text is present on a page using Selenium-WebDriver in Ruby it would be greatly appreciated. I have found workarounds for certain cases where I can do
verify {#driver.find_element(:tag_name, 'h1').text!=(textcheck)}
but the element I am trying to verify I can't get to so easily. I looked into css locators and was very confused on how to simplify the tag so I could use it. Any help would be greatly appreciated. Thank you very much. If you require any more information from me please let me know and I will provide it as soon as possible.
I am using Ruby 1.93 with Selenium-WebDriver 2.25 testing in Firefox 14.0.1
I do it this way
#wait = Selenium::WebDriver::Wait.new(:timeout => 30)
begin
#wait.until { #driver.find_element(:tag_name => "body").text.include?("your text")}
rescue
puts "Failure! text is not present on the page"
#Or do one of the options below
#raise
#assert_match "true","false", "The text is not present"
end
UPDATE
Answer to your question in the comments section.
There are two kind of "waits", implicit wait and explicit wait. You can read more about it here. The reason your code failed was because you were searching by "id"=>"body" and not by "tag_name"=>"body". Usually all text is encompassed within the "body" HTML tags in your DOM.

Unable to find method for detecting if element exists on a page

I'm very new to Watir.
I have a bit of Ruby/Watir code that is supposed to detect if an element, exists, and if so, click it, if not, click a different element. Both elements, show up, every time. Unfortunately nothing I've tried works.
if browser.contains_text("/media/images/icons/reviewertools/editreview.jpg")
then browser.image(:src => "/media/images/icons/reviewertools/editreview.jpg").click
else browser.image(:src => "/media/images/icons/reviewertools/savereview.jpg").click
end
This eventually fails with "Unable to locate element, using {:src=>"/media/images/icons/reviewertools/savereview.jpg"} (Watir::Exception::UnknownObjectException)"
It should have clicked /editreview.jpg, which was visible.
I have also tried:
if browser.image("/media/images/icons/reviewertools/savereview.jpg").exists
then browser.image(:src => "/media/images/icons/reviewertools/savereview.jpg").click
as well as:
if browser.image("/media/images/icons/reviewertools/savereview.jpg").exists?
Note that NONE of these cases detect the element, or failing to do that, execute the else clause.
Please, if you respond, provide specific code examples for your suggestions.
There are only methods "exist?" and "exists?". So "exist" won't work. Consult here.
Can you try to identify existence of a different element, such as a link. Does it work for you? There shouldn be no exception. Watir needs to return False in this case.
You need to use the same syntax with both the click and the exists? methods. This has also been pointed out by Kat and Chuck and Kinofrost.
if browser.image(:src => "/media/images/icons/reviewertools/editreview.jpg").exists?
then browser.image(:src => "/media/images/icons/reviewertools/editreview.jpg").click
else browser.image(:src => "/media/images/icons/reviewertools/savereview.jpg").click
end
I'd recommend checking the DOM to double check the src for your image matches what you're putting. Press F12 in IE8, or use whatever tool is relevant to your browser. You could try using IRB to connect to the browser and try and find the image.
If these fail then I'd try locating the image another way. If the image is in a form this can cause problems and you'll have to locate the form before the image.
Or try another way to locate it, just to make sure that it's possible.
browser.image(:index => 3).click
browser.image(:id => 'an_image').click
browser.div(:id => 'image_container').image(:index => 2).click
You can use this link to see what ways you can identify an image, and don't forget that you can use more than one identifier at a time, eg. (:class => /regexofaclass/, :index => 2)
There's nothing wrong with your code as it is (apart from the ? at the end of "exists", and the last line which doesn't contain what you're looking for).
Presuming that this thing really is an 'image' as defined by it's HTML tag, your attempt to identify if the object is there is failing because
you are not using the right method, in Ruby, methods that return a bool end in a question mark
it's not text,
and in the other attempt you provided only a 'what' and not a how, and still used the wrong method.
try this
if browser.image(:src, "/media/images/icons/reviewertools/savereview.jpg").exists?
then browser.image(:src, "/media/images/icons/reviewertools/savereview.jpg").click
Otherwise have a good look at the HTML, are you actually looking at a 'button' perhaps?

How to assert on number of html table rows in ruby using capybara + cucumber

I am trying to get to grips with BDD web development in Ruby using cucumber + capybara and I am stuck at what should be an easy task - just to check the number of rows in a table. The intention of what I'm trying to achieve is something along the lines of:
page.should have_xpath("//table[#id='myTable']")
find("//table[#id='myTable']/tr").length.should == 3
But this doesn't work (missing method length) and I can't find a way to assert against the table length.
Any ideas anyone (please be easy on me tho' I'm a ruby nooby)
Thanks in advance
Neil
Even though have_css? will do the trick, your tests should tell you how they failed, rather than just saying some condition was supposed to be true and it was false. With this in mind, the first example below reads much better than the second:
# IF FAILED => "expected 10, got 7"
page.all('table#myTable tr').count.should == 10
# IF FAILED => "expected true, got false"
page.should have_css("table#myTable tr", :count=>10)
I think you can do this:
page.should have_css("table#mytable tr", :count=>3)
For some reason "has_css" does not work for me, however "all(selector)" works really wel
all("table#movies tr").count
I went with this in the end:
Then /^I should see "(.*)" once$/ do |text|
within_table('myTable') do
should have_xpath("//tr", :text => text, :count => 1)
end
end
which seemed suitably elegant.
I realise the other answers work but this seems to read well.
Any comments?
The method #find only returns one element (I think it just returns the first one if there are several matches) so you don't get a #length method because the result of #find is a Node not an Array.
To prove this to yourself, try
puts find("//table[#id='myTable']/tr").class
What you want is #all, which will return you an Array of all the matching nodes.
In this way you can learn the number of lines in the html table.
area = find_by_id('#areaID').all('tr').size
Assume that there are columns at the beginning of the table.You can reach the actual number in this way.
area = area-1

Resources