Using Ruby, we can wait for particular element by doing following:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { driver.find_element(:class, 'gritter-item') }
but if I want particular element to disappear from DOM, I write method like:
def disappear_element
begin
driver.find_element(:class, 'gritter-item')
rescue Selenium::WebDriver::Error::NoSuchElementError
true
else
false
end
end
and called it like:
wait.until { disappear_element }
This way I could achieve absence of element. Is there any better way in Ruby to achieve the same?
You can write disappear_element as follow (using find_elements instead of find_element):
def disappear_element
driver.find_elements(:class, 'gritter-item').size == 0
end
Related
I have such code:
until #driver.find_element(:id, "ctl00_cp_lblC").displayed?
puts "invalid page solution"
enter_page
end
and i need to do some method, until page will have some element with some id, now it throw's error, that selenium couldn't locate element with this id. What i do wrong, and how to solve it?
Also maybe it is easier to do with watir?
As mentioned, by RobbieWareham, find_element will throw an exception if the element does not exist. You want to:
Rescue the exception of the element not being found and call your enter_page method
Wrap all of that in a wait.until, so that it does not run indefinitely
This would look like:
wait = Selenium::WebDriver::Wait.new(:timeout => 5) # seconds
begin
element = wait.until do
begin
#driver.find_element(:id, "ctl00_cp_lblC")
rescue
enter_page
end
end
ensure
#driver.quit
end
In Watir, it would be easier. It would simply be:
browser.element(:id => "ctl00_cp_lblC").wait_until_present
Or if you need to do stuff when the element is not present:
browser.wait_until(2) do
present = browser.element(:id => "ctl00_cp_lblC").present?
enter_page unless present
present
end
Webdriver throws an error when an element is not found. Displayed? only shows whether an object is hidden or not. As you have seen, when the object is not even in the html, a NoSuchElementFound exception occurs.
Apologies for the java but you should get the idea;
Boolean elementFound = false;
do {
getDriver().manage().timeouts().implicitlyWait(500, TimeUnit.MILLISECONDS);
try {
elementFound = getDriver().findElement(By.id("ct100_cp_lblC")).isDisplayed();
}
catch (NoSuchElementException e){
}
getDriver().navigate().refresh();
} while (!elementFound);
getDriver().manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
You would need extra code to stop an infinite loop but you shoudl get the idea.
This is a big difference between the Watir & WebDriver APIs, but I suppose it is whatever you are used to.
On my web page, page loads but sub-tabs of page aren't clickable for 20 seconds (sometimes more than this). Page contents are -
<nav id="subTabHeaders">
<div class="selected" data-name="ab">AB</div>
<div class="" data-name="cd">CD</div>
<div class="" data-name="ef">EF</div>
<div class="" data-name="gh">GH</div>
</nav>
I've to click on sub-tab, hence I tried this in following way -
Put sleep & then element.click
But sleep is not ideal way to deal because sometimes it may happen that sub-tab element is clickable before or after the time given to sleep.
Using sleep, I did following -
element = WAIT.until { driver.find_element(:xpath, ".//*[#id='subTabHeaders']/div[3]")}
sleep 20
element.click
If element is clickable after more than the sleep time & we click on element immediate after sleep time expires, (I mean (using above code) suppose element becomes clickable after 30 seconds but we click on element immediate after 20 seconds), actual click action doesn't happen & also click doesn't return any error.
Is there Ruby method to check whether element is clickable or not? So that we'll get to know when to click.
From the ruby bindings page: (see driver examples)
# wait for a specific element to show up
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
wait.until { driver.find_element(:id => "foo") }
So ordinarily you could do something like:
wait = Selenium::WebDriver::Wait.new(:timeout => 40)
wait.until do
element = driver.find_element(:xpath, ".//*[#id='subTabHeaders']/div[3]")
element.click
end
Or more succinctly
wait = Selenium::WebDriver::Wait.new(:timeout => 40)
wait.until { driver.find_element(:xpath, ".//*[#id='subTabHeaders']/div[3]").click }
However, since you say that the click doesn't raise an error, it sounds like the click is in fact working, just your page isn't really ready to display that tab. I'm guessing there's some async javascript going on here.
So what you can try is inside the wait block, check that the click caused the desired change. I'm guessing, but you could try something like:
wait = Selenium::WebDriver::Wait.new(:timeout => 40)
wait.until do
driver.find_element(:xpath, ".//*[#id='subTabHeaders']/div[3]").click
driver.find_element(:xpath, ".//*[#id='subTabHeaders']/div[3][#class='selected']")
end
The important thing here is that #until will wait and repeat until the block gets a true result or the timeout is exceeded.
How about
WebDriverWait wait = new WebDriverWait(driver,30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(subTabHeaders)));
Hope it would help you:
begin
element = WAIT.until { driver.find_element(:xpath, ".//*[#id='subTabHeaders']/div[3]")}
sleep 20
element.click
rescue Selenium::WebDriver::Error::StaleElementReferenceError
p "Indicates that a reference to an element is now “stale” - the element no longer appears in the DOM of the page."
end
OR
you could try this one:
begin
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
wait.until { driver.title.include? "page title" }
driver.find_element(:xpath, ".//*[#id='subTabHeaders']/div[3]")}.click
rescue Selenium::WebDriver::Error::StaleElementReferenceError
p "element is not present"
end
Here is what I use - to test if the link is clickable, else go to another URL:
if (logOutLink.Exists() && ExpectedConditions.ElementToBeClickable(logOutLink).Equals(true))
{
logOutLink.Click();
}
else
{
Browser.Goto("/");
}
I'm pretty new to ruby and am trying to implement a Tk application that will display a window prompting for input at a certain interval. In between the interval I want the window to not display in any taskbars, etc. and so I've implemented the following code that seems to work perfectly the first time through, but after the window displays the second time and I enter text in the TkEntry and click the TkButton the window is dismissed and never returns. I've tried putting in some "puts" calls at key locations to see what is happening and it seems that it never even makes it past the call to "displayUi".
*EDIT:
I'm running ruby 1.9.3p385 (2013-02-06) [i386-mingw32] on a Windows 7 system (in case that makes any difference)
Any help (even if it's providing a different mechanism to accomplish the same goal) would be appreciated, but please keep in mind that I'm a ruby noobie. Thanks!
require "tk"
class Sample
attr_accessor :root, :active
#active = false
def initialize
# init
end
def entry (task)
# do some work here
#active = false
end
def displayUi ()
#active = true
if (#root.nil?)
#root = TkRoot.new { title "Sample App" }
else
# already running just restart
Tk.restart
end
TkLabel.new(#root) {
text 'Sample Text'
pack { padx 15; pady 15; side 'left' }
}
statusInput = TkEntry.new(#root) {
pack('side'=>'left', 'padx'=>10, 'pady'=>10)
}
statusInput.focus
response = TkVariable.new
statusInput.textvariable = response
TkButton.new(#root, :text => "Ok", :command => proc { entry(response.value); #root.destroy }) {
pack('side'=>'left', 'padx'=>10, 'pady'=>10)
}
Tk.mainloop
end
end
i=0
st = Sample.new
while (true)
if (!st.active)
st.displayUi()
end
sleep(1)
end
I implemeting async thread manager and I want to pass reference to thread, where it should save the results of his work. And then when all thread finished i will handle all results.
What I need is to know how to work with 'references'.
lets assume I have variable result (or hash[:result1]), I want to pass it to the thread like
def test_func
return 777;
end
def thread_start(result)
Thread.new do
result = test_func;
end
end
and I want is to get following result
result = 555
thread_start(result);
#thread_wait_logic_there
result == 777; #=> true
hash = {:res1 => 555};
thread_start(hash[:res1])
#thread_wait_logic_there
hash[:res1]==777 #=> true
what should I chnage in my code to make it work?
Ruby version is 1.9.3
You can pass entrire hash to function:
def test_func
return 777;
end
def thread_start(hash, key)
Thread.new do
hash[key] = test_func;
end
end
Then this will work:
hash = {:res1 => 555};
thread_start(hash, :res1)
hash[:res1]==777 #=> true
Also if you want to be sure that you getting result after computations finished you must wait for thread, like this:
hash = {:res1 => 555};
thread_start(hash, :res1).join
hash[:res1]==777 #=> true
Edit: Added key,join
Is there anyway to check whether an element is present in Selenium web driver? I try to use this code:
if #driver.find_element(:link, "Save").displayed? == true
but it will break in exception, which is not what I expected because I still want the script to continue running.
I'm not Ruby expert and can make some syntax errors but you can get general idea:
if #driver.find_elements(:link, "Save").size() > 0
This code doesn't throw NoSuchElementException
But this method will "hang" for a while if you have implicitlyWait more than zero and there is no elements on the page.
The second issue - if element exists on the page but not displayed you'll get true.
To workaround try to create method:
def is_element_present(how, what)
#driver.manage.timeouts.implicit_wait = 0
result = #driver.find_elements(how, what).size() > 0
if result
result = #driver.find_element(how, what).displayed?
end
#driver.manage.timeouts.implicit_wait = 30
return result
end
#driver.find_element throws an exception called NoSuchElementError.
So you can write your own method which uses try catch block and return true when there is no exception and false when there is an exception.
If it's expected that the element should be on the page no matter what: use a selenium wait object with element.displayed?, rather than using begin/rescue:
wait = Selenium::WebDriver::Wait.new(:timeout => 15)
element = $driver.find_element(id: 'foo')
wait.until { element.displayed? } ## Or `.enabled?` etc.
This is useful in instances where parts of the page take longer to properly render than others.
I am using selenium-webdriver version 3.14.0 released earlier this month. I was trying to put a check on #web_driver_instance.find_element(:xpath, "//div[contains(text(), 'text_under_search')]").displayed? using:
element_exists = #wait.until { #web_driver_instance.find_element(:xpath, "//div[contains(text(), 'text_under_search')]").displayed? }
unless element_exists
#do something if the element does not exist
end
Above failed with NoSuchElementError exception so i tried using below:
begin
#wait.until { #web_driver_instance.find_element(:xpath, "//div[contains(text(), 'text_under_search')]").displayed? }
rescue NoSuchElementError
#do something if the element does not exist
end
This also did not work for me and failed again with NoSuchElementError exception.
Since text presence i was checking was likely to be unique on the page, tried below and this worked for me:
unless /text_under_search_without_quotes/.match?(#web_driver_instance.page_source)
#do something if the text does not exist
end
Find Element
Solution #1
expect(is_visible?(page.your_element)).to be(false)
[or]
expect(is_visible?(#driver.find_element(:css => 'locator_value'))).to be(false)
[or]
expect(is_visible?(#driver.first(:css => 'locator_value'))).to be(true)
=> Generic ruby method
def is_visible?(element)
begin
element.displayed?
return true
rescue => e
p e.message
return false
end
end
Solution #2
expect(is_visible?(".locator_value")).to be(false) # default css locator
[or]
expect(is_visible?("locator_value", 'xpath')).to be(true)
[or]
expect(is_visible?("locator_value", 'css')).to be(false)
[or]
expect(is_visible?("locator_value", 'id')).to be(false)
=> Generic ruby method
def is_visible?(value, locator = 'css')
begin
#driver.first(eval(":#{locator}") => value).displayed?
return true
rescue => e
p e.message
return false
end
end
Find Elements (list of elements)
Solution #1
=> Variable declared in the page class
proceed_until(#driver.find_elements(:css => 'locator_value').size == 0)
[or]
proceed_until(#driver.all(:css => 'locator_value').size == 0)
=> Generic ruby method
def proceed_until(action)
init = 0
until action
sleep 1
init += 1
raise ArgumentError.new("Assertion not matching") if init == 9
end
end