Selenium-webdriver in Ruby crashes when element is not found - ruby

When looking at a dynamic element on a webpage, Selenium crashes if the element is not present. As a result I'm having to rescue the application to continue. I figure I'm doing something wrong with the syntax
response = driver.find_element(:class, element).text
If the element is not found, Selenium errors and crashes the application. This happens regardless of my browser configuration.

Selenium is not crashing. Your code has encountered an exceptional condition (attempting to work with an element that is not there). The code is correctly responding to that exceptional condition by raising a NoSuchElementError.
If you are trying to determine if an element is there, you can use Driver#find_elements and check if the Array#size equals 0.
If you are trying to work with an element that is not yet on the page, you'll need to create an explicit wait to poll for the element to show up as in DebanjanB's answer.

You need to wait a bit for the element to be visible before you try to locate it as follows:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
ele = wait.until { driver.find_element(:class, element).displayed? }
response = ele.text

Related

Don't run a cucumber feature if a element on the page is not available but exit without failing

I want to check a page for an element before I start running the feature file for it (It's an element that periodically appears with an event so I only want to run the feature if its present).
The approach I wanted to use was a tagged before hook to see if the element was present and if it wasn't just don't run the feature but exit without 'failing' the step just exit with a message. I tried variants on the below but
1. If I don't have a rescue clause it obviously fails the scenario when the element isn't present
2. If I do have the rescue clause it handles it and passes moving onto the features which will then fail as the event isn't available.
Is there a way to halt running the feature file if the rescue clause is invoked without the 'fail'?
Before('#event') do
begin
find('.event').visible?
rescue Capybara::ElementNotFound
puts 'THE EVENT IS NOT ON'
end
end
You shouldn't be using find if you want to make a decision based on existence. Instead you should be using the predicate methods provided by Capybara (has_selector?, has_css?, has_xpath?, etc) so you don't have to rescue exceptions.
The other thing to know is the Cucumber skip_this_sceanrio method, which means you should end up with something like
Before('#event') do
# visit '/some_page' # May not be needed if you have another `Before` already visiting the needed page
skip_this_scenario('Skipping due to missing event') unless page.has_css?('.event')
end

Ruby Appium assert

I have to initiate a Appium webdriver using code below.
driver=Appium::Driver.new(desired_caps)
And it is working for starting an app and quits during execution.
Can any one please give examples on how to do the assert for element exists and specific value comparison?
You've created "driver", then next step is just
driver.start_driver
Then you can use all methods in appium ruby_lib, for example
driver.text('some text')
driver.button('button_name/id/text')
To check element exist:
exists { button('sign in') } ? puts('true') : puts('false')
You said it started then quit, it might be normal, it quits if test arrives the last step, except you add test steps or put some sleep time.
Highly recommend you to check the examples:
https://github.com/jlipps/appium-ruby-example
and also the ruby_lib doc:
https://github.com/appium/ruby_lib/tree/master/docs

I'm using the Selenium Webdriver gem to try to click on the facebook chat bar, sometimes it work and sometimes it doesn't

I'm using the Selenium Webdriver gem to try to click on the facebook chat bar, sometimes it work and sometimes it doesn't. When it does not work it returns the Selenium Element not visible error, but it clearly is visible. I'm not sure what's wrong with my code.
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome # instantiates a google chrome session
driver.navigate.to 'https://www.facebook.com/' # takes you to facebook.com
emailBar = driver.find_element(:id,"email") #finds email input bar
passwordBar = driver.find_element(:id,"pass") #find password input bar
loginButton = driver.find_element(:id,"u_0_n") #finds login button
emailBar.send_keys "austinspreadsheet#gmail.com" # puts in the email
passwordBar.send_keys "YOURPASSWORD" # puts in the password
loginButton.click # clicks the login button
#THIS IS THE CODE BLOCK THAT DOES NOT WORK
links = driver.find_elements(:class,"fbNubButton") # finds the chat bar
#driver.manage.timeouts.page_load = 10
links[0].click # opens the chat bar
links[1].click # NOTE that sometime it clicks and sometimes it doesn't but if you click both chat box classes it usually works, so the error is ok
I have tried not clicking both chat links and it works less when I do that.
I am using Selenium with Python. In case like yours the issue is related to waiting until all the elements in the page are full loaded.
The basic behavior of Selenium offers you Explicit and Implicit Waits. So basicly you can force the system to wait a default number of second or wait until an element is loaded.
From Selenium documentation (http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp)
Explicit wait
An explicit waits is code you define to wait for a certain condition to occur before proceeding further in the code. The worst case of this is Thread.sleep(), which sets the condition to an exact time period to wait. There are some convenience methods provided that help you write code that will wait only as long as required. WebDriverWait in combination with ExpectedCondition is one way this can be accomplished.
require 'rubygems' # not required for ruby 1.9 or if you installed without gem
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
driver.get "http://somedomain/url_that_delays_loading"
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
begin
element = wait.until { driver.find_element(:id => "some-dynamic-element") }
ensure
driver.quit
end
Implicit wait
An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available. The default setting is 0. Once set, the implicit wait is set for the life of the WebDriver object instance.
require 'rubygems' # not required for ruby 1.9 or if you installed without gem
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
driver.manage.timeouts.implicit_wait = 10 # seconds
driver.get "http://somedomain/url_that_delays_loading"
element = driver.find_element(:id => "some-dynamic-element")
The answer that aberna gives you on this thread has a lot of great information but it isn't going to solve your issue. If you use the Explicit wait method that aberna suggests, you also probably need to make sure the element is visible. Using .findElements on its own doesn't guarantee clickability/visibility . You could try to use expectedconditions .visibilityOfElementLocated which will also check for visibility as well as presence.
Or, alternatively, you can check for presence of the element on the DOM using .findElement but then use the expectedconditions.visibilityOf to check for the visibility part of it.
I am using sleep(5) before run main logic
I was facing the same issue. Solution that worked for me was to maximise my browser window. This solved many of failing specs.
Capybara.current_session.driver.browser.manage.window.maximize

How to handle Watir::Exception::UnknownObjectException:

I'm using watir to automate the deleting of elements using a while loop, but when the scripts reaches the end it errors out since the element that the while loop is dependent on is no longer visible. Is there anyway to have Watir carry on with the test?
Here is an example of my code:
class Delete_element
def org_roster_remove
parameters = Tt_parameters.new
driver = Login.new.log_in(parameters.username3, parameters.password3)
while driver.a(:data_class, 'home.group.edit_group_btn').visible? == true
driver.p(:data_class, 'home.conv.messagePreview').hover
sleep(1)
driver.div(:class, 'delete').click
sleep(1)
driver.a(:data_class, 'home.conv.deleteFromRoster_btn').click
sleep(1)
end
driver.quit
end
end
This is the error:
Watir::Exception::UnknownObjectException: unable to locate element, using {:data_class=>"home.group.edit_group_btn", :tag_name=>"a"}
I would use .present? instead of .visible?
Also consider using .wait_until_visible instead of sleeping. See Watir-webdriver Waiting.
Additionally, investigate a page object framework such as Cheezy's page-object gem

Capybara synchronize with has_no_css?

Since upgrading to Capybara 2.4, I've been running into this issue. Previously, this block worked fine:
page.document.synchronize do
page.should have_no_css('#ajax_indicator', :visible => true)
end
It's meant to force waiting until the ajax indicator disappears before proceeding with the next step.
Since the above returns a RSpec::Expectations::ExpectationNotMetError, the synchronize doesn't rerun the block and instead just throws the error. Not sure why this was working in the version I was using before (I believe 2.1).
The synchronize block only reruns blocks that return something like:
Capybara::ElementNotFound
Capybara::ExpectationNotMet
And whatever a certain driver adds to that list.
See Justin's response for a more comprehensive explanation and examples not using synchronize, or look at my response for the direct solution.
Follow-up: I've since revisited this problem so here's a few tips:
1) document.synchronize more often than not does nothing useful, as mentioned by others most of the finders have built-in wait. You can manually force it to not wait using wait: 0 when that makes sense.
Note that due to this, the following are not equivalent:
!assert_css('#ajax_indicator')
assert_no_css('#ajax_indicator')
The former will wait until the element exists, while the latter will wait until the element doesn't exist, even if they are otherwise logically equivalent.
2) Problems that lead to us initially inserting synchronize were due to a chicken and egg problem of sorts.
#ajax_indicator in this case will appear when there is active loading, then disappear after. We cannot distinguish from the indicator having not appeared yet, and having appeared then disappeared.
Although I have yet to 100% resolve this issue, what has improved our test reliability is looking for indicators to ensure page loading has reached a certain point, e.g.
do_thing_that_triggers_ajax
find('#thing-that-should-exist')
assert_no_selector('#ajax_indicator', visible: true)
This differents from asserting #ajax_indicator exists and then assert it doesn't exist, because in that case if the ajax happens too fast capybara may not catch it in action.
Depending on your scripts, you could possibly find more reliable indicators.
The have_no_css matcher already waits for the element to disappear. The problem seems to be using it within a synchronize block. The synchronize method only re-runs for certain exceptions, which does not include RSpec::Expectations::ExpectationNotMetError.
Removing the synchronize seems to do what you want - ie forces a wait until the element disappears. In other words, just do:
page.should have_no_css('#ajax_indicator', :visible => true)
Working Example
Here is a page, say "wait.htm", that I think reproduces your problem. It has a link that when clicked, waits 6 seconds and then hides the indicator element.
<html>
<head>
<title>wait test</title>
<script type="text/javascript" charset="utf-8">
function setTimeoutDisplay(id, display, timeout) {
setTimeout(function() {
document.getElementById(id).style.display = display;
}, timeout);
}
</script>
</head>
<body>
<div id="ajax_indicator" style="display:block;">indicator</div>
<a id="hide_foo" href="#" onclick="setTimeoutDisplay('ajax_indicator', 'none', 6000);">hide indicator</a>
</body>
</html>
The following spec shows that by using the page.should have_no_css without manually calling synchronize, Capybara is already forcing a wait. When waiting only 2 seconds, the spec fails since the element does not disappear. When waiting 10 seconds, the spec passes since the element has time to disappear.
require 'capybara/rspec'
Capybara.run_server = false
Capybara.current_driver = :selenium
Capybara.app_host = 'file:///C:/test/wait.htm'
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
end
end
RSpec.describe "#have_no_css", :js => true, :type => :feature do
it 'raise exception when element does not disappear in time' do
Capybara.default_wait_time = 2
visit('')
click_link('hide indicator')
page.should have_no_css('#ajax_indicator', :visible => true)
end
it 'passes when element disappears in time' do
Capybara.default_wait_time = 10
visit('')
click_link('hide indicator')
page.should have_no_css('#ajax_indicator', :visible => true)
end
end
Since version of Capybara 2.0 you can customize inline wait time parameter to pass it into the #have_no_css method:
page.should have_no_css('#ajax_indicator', visible: true, wait: 3)
The solution I've settled for is the following:
page.document.synchronize do
page.assert_no_selector('#ajax_indicator', :visible => true)
end
The assert_no_selector method properly throws a Capybara::ExpectationNotMet error and appears to work in the same way as has_no_css, so I'm satisfied with this solution.
I still have no idea why the RSpec error is being thrown for some methods but not others.
Edit: While this works it isn't actually a good idea to do so, see other responses.

Resources