Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
81 lines (78 sloc) 3.42 KB
module Watir
class Element
OBSERVER_FILE = "/dom_observer.js".freeze
DOM_OBSERVER = File.read("#{File.dirname(__FILE__)}#{OBSERVER_FILE}").freeze
# This method makes a call to `execute_async_script` which means that the
# DOM observer script must explicitly signal that it is finished by
# invoking a callback. In this case, the callback is nothing more than
# a delay. The delay is being used to allow the DOM to be updated before
# script actions continue.
#
# The method returns true if the DOM has been changed within the element
# context, while false means that the DOM has not yet finished changing.
# Note the wording: "has not finished changing." It's known that the DOM
# is changing because the observer has recognized that. So the question
# this method is helping to answer is "has it finished?"
#
# Consider the following element definition:
#
# p :page_list, id: 'navlist'
#
# You could then do this:
#
# page_list.dom_updated?
#
# That would return true if the DOM content for page_list has finished
# updating. If the DOM was in the process of being updated, this would
# return false. You could also do this:
#
# page_list.wait_until(&:dom_updated?).click
#
# This will use Watir's wait until functionality to wait for the DOM to
# be updated within the context of the element. Note that the "&:" is
# that the object that `dom_updated?` is being called on (in this case
# `page_list`) substitutes the ampersand. You can also structure it like
# this:
#
# page_list.wait_until do |element|
# element.dom_updated?
# end
#
# The default delay of waiting for the DOM to start updating is 1.1
# second. However, you can pass a delay value when you call the method
# to set your own value, which can be useful for particular sensitivities
# in the application you are testing.
def dom_updated?(delay: 1.1)
element_call do
begin
driver.manage.timeouts.script_timeout = delay + 1
driver.execute_async_script(DOM_OBSERVER, wd, delay)
rescue Selenium::WebDriver::Error::StaleElementReferenceError
# This situation can occur when the DOM changes between two calls to
# some element or aspect of the page. In this case, we are expecting
# the DOM to be different so what's being handled here are those hard
# to anticipate race conditions when "weird things happen" and DOM
# updating plus script execution get interleaved.
retry
rescue Selenium::WebDriver::Error::JavascriptError => e
# This situation can occur if the script execution has started before
# a new page is fully loaded. The specific error being checked for
# here is one that occurs when a new page is loaded as that page is
# trying to execute a JavaScript function.
retry if e.message.include?(
'document unloaded while waiting for result'
)
raise
ensure
# Note that this setting here means any user-defined timeout would
# effectively be overwritten.
driver.manage.timeouts.script_timeout = 1
end
end
end
alias dom_has_updated? dom_updated?
alias dom_has_changed? dom_updated?
alias when_dom_updated dom_updated?
alias when_dom_changed dom_updated?
end
end