Class: PageFactory
- Inherits:
-
Object
- Object
- PageFactory
- Defined in:
- lib/test-factory/page_factory.rb
Overview
The PageFactory class provides a set of methods that allow the rapid creation of page element definitions–known colloquially as “page objects”. These elements are defined using Watir syntax. Please see www.watir.com if you are not familiar with Watir.
Class Method Summary collapse
-
.button(button_text, *alias_name) ⇒ Object
Use this for buttons that are safe to define by their value attribute.
-
.element(name, &block) ⇒ Object
(also: action, value, p_element, p_action, p_value)
The basic building block for defining and interacting with elements on a web page.
-
.expected_element(element_name, timeout = 30) ⇒ Object
Define this in a page class and when that class is instantiated it will wait until that element appears on the page before continuing with the script.
-
.expected_title(expected_title) ⇒ Object
Define this in a page class and when the class is instantiated it will verify that the browser’s title matches the expected title.
- .inherited(klass) ⇒ Object
-
.link(link_text, *alias_name) ⇒ Object
Use this for links that are safe to define by their text string.
-
.page_url(url) ⇒ Object
Define this in a page class and when you use the “visit” method to instantiate the class it will enter the URL in the browser’s address bar.
-
.undefine(*methods) ⇒ Object
TestFactory doesn’t allow defining a method in a child class with the same name as one already defined in a parent class.
Instance Method Summary collapse
-
#initialize(browser, visit = false) ⇒ PageFactory
constructor
As the PageFactory will be the superclass for all your page classes, having this initialize method here means it’s only written once.
-
#method_missing(sym, *args, &block) ⇒ Object
Catches any “missing” methods and passes them to the browser object–which means that Watir will take care of parsing them, so the assumption is that the method being passed is a valid method for the browser object.
Constructor Details
#initialize(browser, visit = false) ⇒ PageFactory
As the PageFactory will be the superclass for all your page classes, having this initialize method here means it’s only written once.
24 25 26 27 28 29 |
# File 'lib/test-factory/page_factory.rb', line 24 def initialize browser, visit = false @browser = browser goto if visit expected_element if respond_to? :expected_element has_expected_title? if respond_to? :has_expected_title? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(sym, *args, &block) ⇒ Object
Catches any “missing” methods and passes them to the browser object–which means that Watir will take care of parsing them, so the assumption is that the method being passed is a valid method for the browser object.
35 36 37 |
# File 'lib/test-factory/page_factory.rb', line 35 def method_missing sym, *args, &block @browser.send sym, *args, &block end |
Class Method Details
.button(button_text, *alias_name) ⇒ Object
Use this for buttons that are safe to define by their value attribute. This method will return two methods for interacting with the button: one that refers to the button itself, and one that clicks on it. Since it’s assumed that the most common thing done with a button is to click it, the method for clicking it will be named according to the value of the button, and the method for the button itself will have “_button” appended to it. Any special characters are stripped from the string. Capital letters are made lower case. And spaces and dashes are converted to underscores. The last parameter in the method is optional. Use it when you need the method name to be different from the text of the button–for example if the button text is unhelpful, like “Go”, or else it changes (e.g., from “Update” to “Edit”) and you don’t want to have to go through all your data objects and step definitions to update them to the new method name.
146 147 148 |
# File 'lib/test-factory/page_factory.rb', line 146 def , *alias_name elementize(:button, , *alias_name) end |
.element(name, &block) ⇒ Object Also known as: action, value, p_element, p_action, p_value
The basic building block for defining and interacting with elements on a web page. # Use in conjunction with Watir to define all elements on a given page that are important to validate.
Methods that take one or more parameters can be built with this as well.
84 85 86 87 88 89 |
# File 'lib/test-factory/page_factory.rb', line 84 def element name, &block raise "#{name} is being defined twice in #{self}!" if self.instance_methods.include?(name.to_sym) define_method name.to_s do |*thing| Proc.new(&block).call *thing, self end end |
.expected_element(element_name, timeout = 30) ⇒ Object
Define this in a page class and when that class is instantiated it will wait until that element appears on the page before continuing with the script.
54 55 56 57 58 |
# File 'lib/test-factory/page_factory.rb', line 54 def expected_element element_name, timeout=30 define_method 'expected_element' do self.send(element_name).wait_until_present timeout end end |
.expected_title(expected_title) ⇒ Object
Define this in a page class and when the class is instantiated it will verify that the browser’s title matches the expected title. If there isn’t a match, it raises an error and halts the script.
65 66 67 68 69 70 |
# File 'lib/test-factory/page_factory.rb', line 65 def expected_title expected_title define_method 'has_expected_title?' do has_expected_title = expected_title.kind_of?(Regexp) ? expected_title =~ @browser.title : expected_title == @browser.title raise "Expected title '#{expected_title}' instead of '#{@browser.title}'" unless has_expected_title end end |
.inherited(klass) ⇒ Object
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/test-factory/page_factory.rb', line 175 def inherited klass klass.instance_eval { # Creates a method, #wait_for_ajax, usable in your Page Classes, that executes # the 'jQuery.active' Javascript snippet each second until timeout. # # If timeout is exceeded, raises Watir::Wait::TimeoutError exception. The returned error # message is customizable. # define_method 'wait_for_ajax' do |timeout=10, | timeout.times do sleep 0.3 return true if @browser.execute_script('return jQuery.active').to_i == 0 sleep 0.7 end raise Watir::Wait::TimeoutError, "Ajax calls continued beyond #{timeout} seconds. #{}" end } end |
.link(link_text, *alias_name) ⇒ Object
Use this for links that are safe to define by their text string. This method will return two methods for interacting with the link: one that refers to the link itself, and one that clicks on it. Since it’s assumed that the most common thing done with a link is to click it, the method for clicking it will be named according to the text of the link, and the method for the link itself will have “_link” appended to it. Any special characters are stripped from the string. Capital letters are made lower case. And spaces and dashes are converted to underscores.
The last parameter in the method is optional. Use it when you need the method name to be different from the text of the link–for example if the link text is something unhelpful, like “here”, or else the link text gets updated (e.g., what was “Log In” is now “Sign In”, instead) and you don’t want to have to go through all your data objects and step definitions to update them to the new method name.
119 120 121 |
# File 'lib/test-factory/page_factory.rb', line 119 def link link_text, *alias_name elementize(:link, link_text, *alias_name) end |
.page_url(url) ⇒ Object
Define this in a page class and when you use the “visit” method to instantiate the class it will enter the URL in the browser’s address bar.
44 45 46 47 48 |
# File 'lib/test-factory/page_factory.rb', line 44 def page_url url define_method 'goto' do @browser.goto url end end |
.undefine(*methods) ⇒ Object
TestFactory doesn’t allow defining a method in a child class with the same name as one already defined in a parent class. The thinking here is: “Out of sight, out of mind.” Meaning: you or a team mate might not know or have forgotten that a given element is already defined in a parent class, and so define it again. TestFactory’s restriction is there to help prevent this.
However, in some cases you may have a child page class with a special circumstance, where the parent class’s version of the method really doesn’t apply, and you want to use the same method name in this child class because, really, no other method name would fit quite as well.
The #undefine method is for those rare cases. Note: If you start using this method a lot then you should consider that a sign that perhaps you’re putting too many method definitions into parent page classes.
171 172 173 |
# File 'lib/test-factory/page_factory.rb', line 171 def undefine *methods methods.each{ |m| undef_method m } end |