Class: Browsery::PageObjects::Base
- Inherits:
-
Object
- Object
- Browsery::PageObjects::Base
- Extended by:
- ElementContainer
- Includes:
- Utils::Castable, Utils::Loggable, Utils::OverlayAndWidgetHelper, Utils::PageObjectHelper, Minitest::Assertions
- Defined in:
- lib/browsery/page_objects/base.rb
Overview
The base page object. All page objects should be a subclass of this. Every subclass must implement the following class methods:
expected_path
All methods added here will be available to all subclasses, so do so sparingly. This class has access to assertions, which should only be used to validate the page.
Instance Attribute Summary collapse
-
#assertions ⇒ Object
Returns the value of attribute assertions.
-
#driver ⇒ Object
readonly
Returns the value of attribute driver.
-
#failures ⇒ Object
Returns the value of attribute failures.
Class Method Summary collapse
-
.expected_path(*args) ⇒ String
Given a set of arguments (no arguments by default), return the expected path to the page, which must only have file path and query-string.
Instance Method Summary collapse
-
#click_on_link!(link_text, page_name) ⇒ Object
click on a link on any page, cast a new page and return it.
-
#current_path ⇒ String
Returns the current path loaded in the driver.
-
#current_url ⇒ String
Returns the current URL loaded in the driver.
- #find_all(how, what) ⇒ Object
- #find_first(how, what) ⇒ Object
-
#go!(*args) ⇒ Object
Instructs the driver to visit the Base.expected_path.
- #go_to_page!(url, page_type = :base) ⇒ Object
- #go_to_subpage!(url_path, page_type = :base) ⇒ Object
- #headline ⇒ Object
-
#include?(value) ⇒ Boolean
Check that the page includes a certain string.
-
#initialize(driver) ⇒ Base
constructor
Initializes a new page object from the driver.
-
#meta ⇒ Object
Retrieves all META tags with a ‘name` attribute on the current page.
-
#page_object ⇒ Object
interface for Overlay And Widget Helper version of get_widgets! and get_overlay!.
-
#page_source ⇒ Object
returns the all the page source of a page, useful for debugging.
-
#raise_on_error_page ⇒ Object
PageObject validate! helper.
-
#title ⇒ Object
Get page title from any page.
-
#validate! ⇒ Object
By default, any driver state is accepted for any page.
-
#wait(opts = {}) ⇒ Object
Explicitly wait for a certain condition to be true: wait.until { driver.find_element(:css, ‘body.tmpl-srp’) } when timeout is not specified, default timeout 5 sec will be used when timeout is larger than 15, max timeout 15 sec will be used.
-
#wait_for_ajax(timeout = 15) ⇒ Object
Wait on all AJAX requests to finish.
-
#wait_for_dom(timeout = 15) ⇒ Object
Wait for all dom events to load.
- #wait_for_link(link_text) ⇒ Object
- #wait_for_title_change(title) ⇒ Object
-
#wait_for_url_change(original_url) ⇒ Object
example usage: original_url = driver.current_url driver.find_element(*LINK_REGISTER).click # do some action that should cause url to change wait_for_url_change(original_url).
-
#with_page_title_wait(&blk) ⇒ Object
Wrap an action, wait for page title change.
-
#with_rescue(lbl, &blk) ⇒ Object
Wrap blocks acting on Selenium elements and catch errors they raise.
Methods included from ElementContainer
add_to_mapped_items, element, elements, section, sections
Methods included from Utils::OverlayAndWidgetHelper
Methods included from Utils::PageObjectHelper
#connector_is_saucelabs?, #current_page, #is_element_present?, #is_element_present_and_displayed?, #json_save_to_ever_failed, #page, #print_sauce_link, #put_value, #read_yml, #retry_with_count, #take_screenshot, #teardown, #update_sauce_session_name, #update_sauce_session_status, #visual_regression, #wait_for_attribute_to_have_value, #wait_for_element_to_be_present, #wait_for_element_to_display, #with_url_change_wait
Methods included from Utils::Loggable
Methods included from Utils::Castable
Constructor Details
#initialize(driver) ⇒ Base
Initializes a new page object from the driver. When a page is initialized, no validation occurs. As such, do not call this method directly. Rather, use PageObjectHelper#page in a test case, or #cast in another page object.
41 42 43 44 45 46 |
# File 'lib/browsery/page_objects/base.rb', line 41 def initialize(driver) @driver = driver @assertions = 0 @failures = [] end |
Instance Attribute Details
#assertions ⇒ Object
Returns the value of attribute assertions.
22 23 24 |
# File 'lib/browsery/page_objects/base.rb', line 22 def assertions @assertions end |
#driver ⇒ Object (readonly)
Returns the value of attribute driver.
24 25 26 |
# File 'lib/browsery/page_objects/base.rb', line 24 def driver @driver end |
#failures ⇒ Object
Returns the value of attribute failures.
23 24 25 |
# File 'lib/browsery/page_objects/base.rb', line 23 def failures @failures end |
Class Method Details
.expected_path(*args) ⇒ String
Given a set of arguments (no arguments by default), return the expected path to the page, which must only have file path and query-string.
32 33 34 |
# File 'lib/browsery/page_objects/base.rb', line 32 def self.expected_path(*args) raise NotImplementedError, "expected_path is not defined for #{self}" end |
Instance Method Details
#click_on_link!(link_text, page_name) ⇒ Object
click on a link on any page, cast a new page and return it
217 218 219 220 221 222 223 224 225 |
# File 'lib/browsery/page_objects/base.rb', line 217 def click_on_link!(link_text, page_name) driver.find_element(:link, link_text).location_once_scrolled_into_view driver.find_element(:link, link_text).click # check user angent, if it's on IE, wait 2sec for the title change sleep 2 if driver.browser == :ie # todo remove this if every page has wait for title change in validate! #sleep 5 #wait for 5 secs logger.debug "click_on_link '#{link_text}'" cast(page_name) end |
#current_path ⇒ String
Returns the current path loaded in the driver.
59 60 61 |
# File 'lib/browsery/page_objects/base.rb', line 59 def current_path current_url.path end |
#current_url ⇒ String
Returns the current URL loaded in the driver.
66 67 68 |
# File 'lib/browsery/page_objects/base.rb', line 66 def current_url URI.parse(driver.current_url) end |
#find_all(how, what) ⇒ Object
52 53 54 |
# File 'lib/browsery/page_objects/base.rb', line 52 def find_all(how, what) driver.all(how, what) end |
#find_first(how, what) ⇒ Object
48 49 50 |
# File 'lib/browsery/page_objects/base.rb', line 48 def find_first(how, what) driver.find_element(how, what) end |
#go!(*args) ⇒ Object
Instructs the driver to visit the expected_path.
78 79 80 |
# File 'lib/browsery/page_objects/base.rb', line 78 def go!(*args) driver.get(driver.url_for(self.class.expected_path(*args))) end |
#go_to_page!(url, page_type = :base) ⇒ Object
254 255 256 257 |
# File 'lib/browsery/page_objects/base.rb', line 254 def go_to_page!(url, page_type = :base) driver.navigate.to(url) cast(page_type) end |
#go_to_subpage!(url_path, page_type = :base) ⇒ Object
259 260 261 262 |
# File 'lib/browsery/page_objects/base.rb', line 259 def go_to_subpage!(url_path, page_type = :base) driver.navigate.to(driver.url_for(url_path)) cast(page_type) end |
#headline ⇒ Object
99 100 101 |
# File 'lib/browsery/page_objects/base.rb', line 99 def headline driver.find_element(:css, 'body div.site-content h1').text end |
#include?(value) ⇒ Boolean
Check that the page includes a certain string.
86 87 88 |
# File 'lib/browsery/page_objects/base.rb', line 86 def include?(value) driver.page_source.include?(value) end |
#meta ⇒ Object
Retrieves all META tags with a ‘name` attribute on the current page.
91 92 93 94 95 96 97 |
# File 'lib/browsery/page_objects/base.rb', line 91 def = driver.all(:css, 'meta[name]') .inject(Hash.new) do |vals, tag| vals[tag.attribute(:name)] = tag.attribute(:content) if tag.attribute(:name) vals end end |
#page_object ⇒ Object
interface for Overlay And Widget Helper version of get_widgets! and get_overlay!
71 72 73 |
# File 'lib/browsery/page_objects/base.rb', line 71 def page_object self end |
#page_source ⇒ Object
returns the all the page source of a page, useful for debugging
186 187 188 |
# File 'lib/browsery/page_objects/base.rb', line 186 def page_source driver.page_source end |
#raise_on_error_page ⇒ Object
PageObject validate! helper. Raises RuntimeError if one of our error pages is displaying. This can prevent a test from taking the entire implicit_wait before announcing error. [~jacord]
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/browsery/page_objects/base.rb', line 193 def raise_on_error_page logger.debug "raise_on_error_page" title = '' begin title = driver.title rescue ReadTimeout logger.debug 'ReadTimeout exception was thrown while trying to execute driver.title' logger.debug 'ignore exception and proceed' end title = driver.title logger.debug "Page Title: '#{title}'" raise "HTTP 500 Error" if %r/Internal Server Error/ =~ title raise "HTTP 503 Error" if %r/503 Service Temporarily Unavailable/ =~ title raise "HTTP 404 Error" if %r/Error 404: Page Not Found/ =~ title header = driver.find_element('body h1') rescue nil unless header.nil? raise "HTTP 500 Error" if header.text == 'Internal Server Error' end end |
#title ⇒ Object
Get page title from any page
104 105 106 |
# File 'lib/browsery/page_objects/base.rb', line 104 def title driver.title end |
#validate! ⇒ Object
By default, any driver state is accepted for any page. This method should be overridden in subclasses.
110 111 112 |
# File 'lib/browsery/page_objects/base.rb', line 110 def validate! true end |
#wait(opts = {}) ⇒ Object
Explicitly wait for a certain condition to be true:
wait.until { driver.find_element(:css, 'body.tmpl-srp') }
when timeout is not specified, default timeout 5 sec will be used when timeout is larger than 15, max timeout 15 sec will be used
142 143 144 145 146 147 148 149 |
# File 'lib/browsery/page_objects/base.rb', line 142 def wait(opts = {}) if !opts[:timeout].nil? && opts[:timeout] > 15 puts "WARNING: #{opts[:timeout]} sec timeout is NOT supported by wait method, max timeout 15 sec will be used instead" opts[:timeout] = 15 end Selenium::WebDriver::Wait.new(opts) end |
#wait_for_ajax(timeout = 15) ⇒ Object
Wait on all AJAX requests to finish
132 133 134 135 136 |
# File 'lib/browsery/page_objects/base.rb', line 132 def wait_for_ajax(timeout = 15) wait(timeout: timeout, msg: "Timeout after waiting #{timeout} for all ajax requests to finish").until do driver.execute_script 'return window.jQuery != undefined && jQuery.active == 0' end end |
#wait_for_dom(timeout = 15) ⇒ Object
Wait for all dom events to load
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/browsery/page_objects/base.rb', line 115 def wait_for_dom(timeout = 15) uuid = SecureRandom.uuid # make sure body is loaded before appending anything to it wait(timeout: timeout, msg: "Timeout after waiting #{timeout} for body to load").until do is_element_present?(:css, 'body') end driver.execute_script <<-EOS _.defer(function() { $('body').append("<div id='#{uuid}'></div>"); }); EOS wait(timeout: timeout, msg: "Timeout after waiting #{timeout} for all dom events to finish").until do is_element_present?(:css, "div[id='#{uuid}']") end end |
#wait_for_link(link_text) ⇒ Object
235 236 237 238 239 240 241 242 |
# File 'lib/browsery/page_objects/base.rb', line 235 def wait_for_link(link_text) = "waited 15 sec, can't find link #{link_text} on page" wait(timeout: 15, message: ).until{ driver.find_element(:link, link_text) } unless driver.find_element(:link, link_text).displayed? driver.navigate.refresh end end |
#wait_for_title_change(title) ⇒ Object
227 228 229 230 231 232 233 |
# File 'lib/browsery/page_objects/base.rb', line 227 def wait_for_title_change(title) title = driver.title if title.nil? logger.debug("Waiting for title change from '#{title}'") wait(timeout: 15, message: "Waited 15 sec for page transition") .until { driver.title != title } logger.debug("Arrived at #{driver.title}") end |
#wait_for_url_change(original_url) ⇒ Object
example usage: original_url = driver.current_url driver.find_element(*LINK_REGISTER).click # do some action that should cause url to change wait_for_url_change(original_url)
248 249 250 251 252 |
# File 'lib/browsery/page_objects/base.rb', line 248 def wait_for_url_change(original_url) time = 15 = "waited #{time} sec, url is still #{original_url}, was expecting it to change" wait(timeout: time, message: ).until { driver.current_url != original_url } end |
#with_page_title_wait(&blk) ⇒ Object
Wrap an action, wait for page title change. This function eliminates some error-prone boilerplate around fetching page titles
178 179 180 181 182 |
# File 'lib/browsery/page_objects/base.rb', line 178 def with_page_title_wait(&blk) title = driver.title yield wait_for_title_change(title) end |
#with_rescue(lbl, &blk) ⇒ Object
Wrap blocks acting on Selenium elements and catch errors they raise. This probably qualifies as a Dumb LISPer Trick. If there’s a better Ruby-ish way to do this, I welcome it. [~jacord]
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/browsery/page_objects/base.rb', line 154 def with_rescue(lbl, &blk) yield ## run the block ## rescue errors. Rerunning may help, but we can also test for specific ## problems. rescue Selenium::WebDriver::Error::ElementNotVisibleError => e ## The element is in the DOM but e.visible? is 'false'. Retry may help. logger.debug "Retrying #{lbl}: #{e.class}" yield rescue Selenium::WebDriver::Error::StaleElementReferenceError => e ## The page has changed and invalidated your element. Retry may help. logger.debug "Retrying #{lbl}: #{e.class}" yield rescue Selenium::WebDriver::Error::NoSuchElementError => e ## Raised by get_element(s). Retry MAY help, but check first for HTTP ## 500, which may be best handled higher up the stack. logger.debug "Recovering from NoSuchElementError during #{lbl}" raise_on_error_page ## If we got past the above, retry the block. logger.debug "Retrying #{lbl}: #{e.class}" yield end |