lib/page-object/accessors.rb in page-object-2.2.6 vs lib/page-object/accessors.rb in page-object-2.3.0
- old
+ new
@@ -1,1175 +1,1201 @@
-require 'erb'
-require 'page-object/locator_generator'
-
-module PageObject
- #
- # Contains the class level methods that are inserted into your page objects
- # when you include the PageObject module. These methods will generate another
- # set of methods that provide access to the elements on the web pages.
- #
- module Accessors
-
- #
- # Set some values that can be used within the class. This is
- # typically used to provide values that help build dynamic urls in
- # the page_url method
- #
- # @param [Hash] the value to set the params
- #
- def params=(the_params)
- @params = the_params
- end
-
- #
- # Return the params that exist on this page class
- #
- def params
- @params ||= {}
- end
-
- #
- # Specify the url for the page. A call to this method will generate a
- # 'goto' method to take you to the page.
- #
- # @param [String] the url for the page.
- # @param [Symbol] a method name to call to get the url
- #
- def page_url(url)
- define_method("goto") do
- platform.navigate_to self.page_url_value
- end
-
- define_method('page_url_value') do
- lookup = url.kind_of?(Symbol) ? self.send(url) : url
- erb = ERB.new(%Q{#{lookup}})
- merged_params = self.class.instance_variable_get("@merged_params")
- params = merged_params ? merged_params : self.class.params
- erb.result(binding)
- end
- end
- alias_method :direct_url, :page_url
-
- #
- # Creates a method that waits the expected_title of a page to match the actual.
- # @param [String] expected_title the literal expected title for the page
- # @param [Regexp] expected_title the expected title pattern for the page
- # @param [optional, Integer] timeout default value is nil - do not wait
- # @return [boolean]
- # @raise An exception if expected_title does not match actual title
- #
- # @example Specify 'Google' as the expected title of a page
- # expected_title "Google"
- # page.has_expected_title?
- #
- def wait_for_expected_title(expected_title, timeout=::PageObject.default_element_wait)
- define_method("wait_for_expected_title?") do
- error_message = lambda { "Expected title '#{expected_title}' instead of '#{title}'" }
-
- has_expected_title = (expected_title === title)
- wait_until(timeout, error_message.call) do
- has_expected_title = (expected_title === title)
- end unless has_expected_title
-
- raise error_message.call unless has_expected_title
- has_expected_title
- end
- end
-
- #
- # Creates a method that compares the expected_title of a page against the actual.
- # @param [String] expected_title the literal expected title for the page
- # @param [Regexp] expected_title the expected title pattern for the page
- # @return [boolean]
- # @raise An exception if expected_title does not match actual title
- #
- # @example Specify 'Google' as the expected title of a page
- # expected_title "Google"
- # page.has_expected_title?
- #
- def expected_title(expected_title)
- define_method("has_expected_title?") do
- page_title = title
- has_expected_title = (expected_title === page_title)
- raise "Expected title '#{expected_title}' instead of '#{page_title}'" unless has_expected_title
- has_expected_title
- end
- end
-
- #
- # Creates a method that provides a way to initialize a page based upon an expected element.
- # This is useful for pages that load dynamic content.
- # @param [Symbol] the name given to the element in the declaration
- # @param [optional, Integer] timeout default value is 5 seconds
- # @return [boolean]
- #
- # @example Specify a text box named :address expected on the page within 10 seconds
- # expected_element(:address, 10)
- # page.has_expected_element?
- #
- def expected_element(element_name, timeout=::PageObject.default_element_wait)
- define_method("has_expected_element?") do
- self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_present timeout
- end
- end
-
- #
- # Creates a method that provides a way to initialize a page based upon an expected element to become visible.
- # This is useful for pages that load dynamic content and might have hidden elements that are not shown.
- # @param [Symbol] the name given to the element in the declaration
- # @param [optional, Integer] timeout default value is 5 seconds
- # @param [optional, boolean] also check that element to be visible if set to true
- # @return [boolean]
- #
- # @example Specify a text box named :address expected on the page within 10 seconds
- # expected_element_visible(:address, 10)
- # page.has_expected_element_visible?
- #
- def expected_element_visible(element_name, timeout=::PageObject.default_element_wait, check_visible=false)
- define_method("has_expected_element_visible?") do
- self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_present timeout
- self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_visible timeout
- end
- end
-
- #
- # Identify an element as existing within a frame . A frame parameter
- # is passed to the block and must be passed to the other calls to PageObject.
- # You can nest calls to in_frame by passing the frame to the next level.
- #
- # @example
- # in_frame(:id => 'frame_id') do |frame|
- # text_field(:first_name, :id => 'fname', :frame => frame)
- # end
- #
- # @param [Hash] identifier how we find the frame. The valid keys are:
- # * :id
- # * :index
- # * :name
- # * :regexp
- # @param frame passed from a previous call to in_frame. Used to nest calls
- # @param block that contains the calls to elements that exist inside the frame.
- #
- def in_frame(identifier, frame=nil, &block)
- frame = frame.nil? ? [] : frame.dup
- frame << {frame: identifier}
- block.call(frame)
- end
-
- #
- # Identify an element as existing within an iframe. A frame parameter
- # is passed to the block and must be passed to the other calls to PageObject.
- # You can nest calls to in_frame by passing the frame to the next level.
- #
- # @example
- # in_iframe(:id => 'frame_id') do |frame|
- # text_field(:first_name, :id => 'fname', :frame => frame)
- # end
- #
- # @param [Hash] identifier how we find the frame. The valid keys are:
- # * :id
- # * :index
- # * :name
- # * :regexp
- # @param frame passed from a previous call to in_iframe. Used to nest calls
- # @param block that contains the calls to elements that exist inside the iframe.
- #
- def in_iframe(identifier, frame=nil, &block)
- frame = frame.nil? ? [] : frame.dup
- frame << {iframe: identifier}
- block.call(frame)
- end
-
- #
- # adds four methods to the page object - one to set text in a text field,
- # another to retrieve text from a text field, another to return the text
- # field element, another to check the text field's existence.
- #
- # @example
- # text_field(:first_name, :id => "first_name")
- # # will generate 'first_name', 'first_name=', 'first_name_element',
- # # 'first_name?' methods
- #
- # @param [String] the name used for the generated methods
- # @param [Hash] identifier how we find a text field.
- # @param optional block to be invoked when element method is called
- #
- def text_field(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'text_field_for', &block)
- define_method(name) do
- return platform.text_field_value_for identifier.clone unless block_given?
- self.send("#{name}_element").value
- end
- define_method("#{name}=") do |value|
- return platform.text_field_value_set(identifier.clone, value) unless block_given?
- self.send("#{name}_element").value = value
- end
- end
-
- #
- # adds three methods to the page object - one to get the text from a hidden field,
- # another to retrieve the hidden field element, and another to check the hidden
- # field's existence.
- #
- # @example
- # hidden_field(:user_id, :id => "user_identity")
- # # will generate 'user_id', 'user_id_element' and 'user_id?' methods
- #
- # @param [String] the name used for the generated methods
- # @param [Hash] identifier how we find a hidden field.
- # @param optional block to be invoked when element method is called
- #
- def hidden_field(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'hidden_field_for', &block)
- define_method(name) do
- return platform.hidden_field_value_for identifier.clone unless block_given?
- self.send("#{name}_element").value
- end
- end
- alias_method :hidden, :hidden_field
-
- #
- # adds four methods to the page object - one to set text in a text area,
- # another to retrieve text from a text area, another to return the text
- # area element, and another to check the text area's existence.
- #
- # @example
- # text_area(:address, :id => "address")
- # # will generate 'address', 'address=', 'address_element',
- # # 'address?' methods
- #
- # @param [String] the name used for the generated methods
- # @param [Hash] identifier how we find a text area.
- # @param optional block to be invoked when element method is called
- #
- def text_area(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'text_area_for', &block)
- define_method(name) do
- return platform.text_area_value_for identifier.clone unless block_given?
- self.send("#{name}_element").value
- end
- define_method("#{name}=") do |value|
- return platform.text_area_value_set(identifier.clone, value) unless block_given?
- self.send("#{name}_element").value = value
- end
- end
- alias_method :textarea, :text_area
-
- #
- # adds five methods - one to select an item in a drop-down,
- # another to fetch the currently selected item text, another
- # to retrieve the select list element, another to check the
- # drop down's existence and another to get all the available options
- # to select from.
- #
- # @example
- # select_list(:state, :id => "state")
- # # will generate 'state', 'state=', 'state_element', 'state?', "state_options" methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a select list.
- # @param optional block to be invoked when element method is called
- #
- def select_list(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'select_list_for', &block)
- define_method(name) do
- return platform.select_list_value_for identifier.clone unless block_given?
- self.send("#{name}_element").value
- end
- define_method("#{name}=") do |value|
- return platform.select_list_value_set(identifier.clone, value) unless block_given?
- self.send("#{name}_element").select(value)
- end
- define_method("#{name}_options") do
- element = self.send("#{name}_element")
- (element && element.options) ? element.options.collect(&:text) : []
- end
- end
- alias_method :select, :select_list
-
- #
- # adds three methods - one to select a link, another
- # to return a PageObject::Elements::Link object representing
- # the link, and another that checks the link's existence.
- #
- # @example
- # link(:add_to_cart, :text => "Add to Cart")
- # # will generate 'add_to_cart', 'add_to_cart_element', and 'add_to_cart?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a link.
- # @param optional block to be invoked when element method is called
- #
- def link(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'link_for', &block)
- define_method(name) do
- return platform.click_link_for identifier.clone unless block_given?
- self.send("#{name}_element").click
- end
- end
- alias_method :a, :link
-
- #
- # adds five methods - one to check, another to uncheck, another
- # to return the state of a checkbox, another to return
- # a PageObject::Elements::CheckBox object representing the checkbox, and
- # a final method to check the checkbox's existence.
- #
- # @example
- # checkbox(:active, :name => "is_active")
- # # will generate 'check_active', 'uncheck_active', 'active_checked?',
- # # 'active_element', and 'active?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a checkbox.
- # @param optional block to be invoked when element method is called
- #
- def checkbox(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'checkbox_for', &block)
- define_method("check_#{name}") do
- return platform.check_checkbox(identifier.clone) unless block_given?
- self.send("#{name}_element").check
- end
- define_method("uncheck_#{name}") do
- return platform.uncheck_checkbox(identifier.clone) unless block_given?
- self.send("#{name}_element").uncheck
- end
- define_method("#{name}_checked?") do
- return platform.checkbox_checked?(identifier.clone) unless block_given?
- self.send("#{name}_element").checked?
- end
- end
-
- #
- # adds four methods - one to select, another to return if a radio button
- # is selected, another method to return a PageObject::Elements::RadioButton
- # object representing the radio button element, and another to check
- # the radio button's existence.
- #
- # @example
- # radio_button(:north, :id => "north")
- # # will generate 'select_north', 'north_selected?',
- # # 'north_element', and 'north?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a radio button.
- # @param optional block to be invoked when element method is called
- #
- def radio_button(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'radio_button_for', &block)
- define_method("select_#{name}") do
- return platform.select_radio(identifier.clone) unless block_given?
- self.send("#{name}_element").select
- end
- define_method("#{name}_selected?") do
- return platform.radio_selected?(identifier.clone) unless block_given?
- self.send("#{name}_element").selected?
- end
- end
- alias_method :radio, :radio_button
-
- #
- # adds five methods to help interact with a radio button group -
- # a method to select a radio button in the group by given value/text,
- # a method to return the values of all radio buttons in the group, a method
- # to return if a radio button in the group is selected (will return
- # the text of the selected radio button, if true), a method to return
- # an array of PageObject::Elements::RadioButton objects representing
- # the radio button group, and finally a method to check the existence
- # of the radio button group.
- #
- # @example
- # radio_button_group(:color, :name => "preferred_color")
- # will generate 'select_color', 'color_values', 'color_selected?',
- # 'color_elements', and 'color?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] shared identifier for the radio button group. Typically, a 'name' attribute.
- # The valid keys are:
- # * :name
- #
- def radio_button_group(name, identifier)
- define_method("select_#{name}") do |value|
- platform.radio_buttons_for(identifier.clone).each do |radio_elem|
- if radio_elem.value == value
- return radio_elem.select
- end
- end
- end
- define_method("#{name}_values") do
- result = []
- platform.radio_buttons_for(identifier.clone).each do |radio_elem|
- result << radio_elem.value
- end
- return result
- end
- define_method("#{name}_selected?") do
- platform.radio_buttons_for(identifier.clone).each do |radio_elem|
- return radio_elem.value if radio_elem.selected?
- end
- return false
- end
- define_method("#{name}_elements") do
- return platform.radio_buttons_for(identifier.clone)
- end
- define_method("#{name}?") do
- return platform.radio_buttons_for(identifier.clone).any?
- end
- end
- alias_method :radio_group, :radio_button_group
-
- #
- # adds three methods - one to click a button, another to
- # return the button element, and another to check the button's existence.
- #
- # @example
- # button(:purchase, :id => 'purchase')
- # # will generate 'purchase', 'purchase_element', and 'purchase?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a button.
- # @param optional block to be invoked when element method is called
- #
- def button(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'button_for', &block)
- define_method(name) do
- return platform.click_button_for identifier.clone unless block_given?
- self.send("#{name}_element").click
- end
- end
-
- #
- # adds three methods - one to retrieve the text from a div,
- # another to return the div element, and another to check the div's existence.
- #
- # @example
- # div(:message, :id => 'message')
- # # will generate 'message', 'message_element', and 'message?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a div.
- # @param optional block to be invoked when element method is called
- #
- def div(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'div_for', &block)
- define_method(name) do
- return platform.div_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to retrieve the text from a span,
- # another to return the span element, and another to check the span's existence.
- #
- # @example
- # span(:alert, :id => 'alert')
- # # will generate 'alert', 'alert_element', and 'alert?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a span.
- # @param optional block to be invoked when element method is called
- #
- def span(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'span_for', &block)
- define_method(name) do
- return platform.span_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to return the text for the table, one
- # to retrieve the table element, and another to
- # check the table's existence.
- #
- # @example
- # table(:cart, :id => 'shopping_cart')
- # # will generate a 'cart', 'cart_element' and 'cart?' method
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a table.
- # @param optional block to be invoked when element method is called
- #
- def table(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'table_for', &block)
- define_method(name) do
- return platform.table_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to retrieve the text from a table cell,
- # another to return the table cell element, and another to check the cell's
- # existence.
- #
- # @example
- # cell(:total, :id => 'total_cell')
- # # will generate 'total', 'total_element', and 'total?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a cell.
- # @param optional block to be invoked when element method is called
- #
- def cell(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'cell_for', &block)
- define_method("#{name}") do
- return platform.cell_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
- alias_method :td, :cell
-
-
- #
- # adds three methods - one to retrieve the text from a table row,
- # another to return the table row element, and another to check the row's
- # existence.
- #
- # @example
- # row(:sums, :id => 'sum_row')
- # # will generate 'sums', 'sums_element', and 'sums?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a cell.
- # @param optional block to be invoked when element method is called
- #
- def row(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'row_for', &block)
- define_method("#{name}") do
- return platform.row_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to retrieve the image element, another to
- # check the load status of the image, and another to check the
- # image's existence.
- #
- # @example
- # image(:logo, :id => 'logo')
- # # will generate 'logo_element', 'logo_loaded?', and 'logo?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find an image.
- # @param optional block to be invoked when element method is called
- #
- def image(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'image_for', &block)
- define_method("#{name}_loaded?") do
- return platform.image_loaded_for identifier.clone unless block_given?
- self.send("#{name}_element").loaded?
- end
- end
- alias_method :img, :image
-
- #
- # adds two methods - one to retrieve the form element, and another to
- # check the form's existence.
- #
- # @example
- # form(:login, :id => 'login')
- # # will generate 'login_element' and 'login?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a form.
- # @param optional block to be invoked when element method is called
- #
- def form(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'form_for', &block)
- end
-
- #
- # adds three methods - one to retrieve the text from a list item,
- # another to return the list item element, and another to check the list item's
- # existence.
- #
- # @example
- # list_item(:item_one, :id => 'one')
- # # will generate 'item_one', 'item_one_element', and 'item_one?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a list item.
- # @param optional block to be invoked when element method is called
- #
- def list_item(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'list_item_for', &block)
- define_method(name) do
- return platform.list_item_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
- alias_method :li, :list_item
-
- #
- # adds three methods - one to return the text within the unordered
- # list, one to retrieve the unordered list element, and another to
- # check it's existence.
- #
- # @example
- # unordered_list(:menu, :id => 'main_menu')
- # # will generate 'menu', 'menu_element' and 'menu?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find an unordered list.
- # @param optional block to be invoked when element method is called
- #
- def unordered_list(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'unordered_list_for', &block)
- define_method(name) do
- return platform.unordered_list_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
- alias_method :ul, :unordered_list
-
- #
- # adds three methods - one to return the text within the ordered
- # list, one to retrieve the ordered list element, and another to
- # test it's existence.
- #
- # @example
- # ordered_list(:top_five, :id => 'top')
- # # will generate 'top_five', 'top_five_element' and 'top_five?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find an ordered list.
- # @param optional block to be invoked when element method is called
- #
- def ordered_list(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'ordered_list_for', &block)
- define_method(name) do
- return platform.ordered_list_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
- alias_method :ol, :ordered_list
-
- #
- # adds three methods - one to retrieve the text of a h1 element, another to
- # retrieve a h1 element, and another to check for it's existence.
- #
- # @example
- # h1(:title, :id => 'title')
- # # will generate 'title', 'title_element', and 'title?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a H1. You can use a multiple parameters
- # by combining of any of the following except xpath.
- # @param optional block to be invoked when element method is called
- #
- def h1(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier,'h1_for', &block)
- define_method(name) do
- return platform.h1_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to retrieve the text of a h2 element, another
- # to retrieve a h2 element, and another to check for it's existence.
- #
- # @example
- # h2(:title, :id => 'title')
- # # will generate 'title', 'title_element', and 'title?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a H2.
- # @param optional block to be invoked when element method is called
- #
- def h2(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'h2_for', &block)
- define_method(name) do
- return platform.h2_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to retrieve the text of a h3 element,
- # another to return a h3 element, and another to check for it's existence.
- #
- # @example
- # h3(:title, :id => 'title')
- # # will generate 'title', 'title_element', and 'title?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a H3.
- # @param optional block to be invoked when element method is called
- #
- def h3(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'h3_for', &block)
- define_method(name) do
- return platform.h3_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to retrieve the text of a h4 element,
- # another to return a h4 element, and another to check for it's existence.
- #
- # @example
- # h4(:title, :id => 'title')
- # # will generate 'title', 'title_element', and 'title?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a H4.
- # @param optional block to be invoked when element method is called
- #
- def h4(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'h4_for', &block)
- define_method(name) do
- return platform.h4_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to retrieve the text of a h5 element,
- # another to return a h5 element, and another to check for it's existence.
- #
- # @example
- # h5(:title, :id => 'title')
- # # will generate 'title', 'title_element', and 'title?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a H5.
- # @param optional block to be invoked when element method is called
- #
- def h5(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'h5_for', &block)
- define_method(name) do
- return platform.h5_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to retrieve the text of a h6 element,
- # another to return a h6 element, and another to check for it's existence.
- #
- # @example
- # h6(:title, :id => 'title')
- # # will generate 'title', 'title_element', and 'title?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a H6.
- # @param optional block to be invoked when element method is called
- #
- def h6(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'h6_for', &block)
- define_method(name) do
- return platform.h6_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to retrieve the text of a paragraph, another
- # to retrieve a paragraph element, and another to check the paragraph's existence.
- #
- # @example
- # paragraph(:title, :id => 'title')
- # # will generate 'title', 'title_element', and 'title?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a paragraph.
- # @param optional block to be invoked when element method is called
- #
- def paragraph(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'paragraph_for', &block)
- define_method(name) do
- return platform.paragraph_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
- alias_method :p, :paragraph
-
- #
- # adds three methods - one to set the file for a file field, another to retrieve
- # the file field element, and another to check it's existence.
- #
- # @example
- # file_field(:the_file, :id => 'file_to_upload')
- # # will generate 'the_file=', 'the_file_element', and 'the_file?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a file_field.
- # @param optional block to be invoked when element method is called
- #
- def file_field(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'file_field_for', &block)
- define_method("#{name}=") do |value|
- return platform.file_field_value_set(identifier.clone, value) unless block_given?
- self.send("#{name}_element").value = value
- end
- end
-
- #
- # adds three methods - one to retrieve the text from a label,
- # another to return the label element, and another to check the label's existence.
- #
- # @example
- # label(:message, :id => 'message')
- # # will generate 'message', 'message_element', and 'message?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a label.
- # @param optional block to be invoked when element method is called
- #
- def label(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'label_for', &block)
- define_method(name) do
- return platform.label_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to click the area,
- # another to return the area element, and another to check the area's existence.
- #
- # @example
- # area(:message, :id => 'message')
- # # will generate 'message', 'message_element', and 'message?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find an area.
- # @param optional block to be invoked when element method is called
- #
- def area(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'area_for', &block)
- define_method(name) do
- return platform.click_area_for identifier.clone unless block_given?
- self.send("#{name}_element").click
- end
- end
-
- #
- # adds two methods - one to return the canvas element and another to check
- # the canvas's existence.
- #
- # @example
- # canvas(:my_canvas, :id => 'canvas_id')
- # # will generate 'my_canvas_element' and 'my_canvas?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a canvas.
- # @param optional block to be invoked when element method is called
- #
- def canvas(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'canvas_for', &block)
- end
-
- #
- # adds two methods - one to return the audio element and another to check
- # the audio's existence.
- #
- # @example
- # audio(:acdc, :id => 'audio_id')
- # # will generate 'acdc_element' and 'acdc?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find an audio element.
- # @param optional block to be invoked when element method is called
- #
- def audio(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'audio_for', &block)
- end
-
- #
- # adds two methods - one to return the video element and another to check
- # the video's existence.
- #
- # @example
- # video(:movie, :id => 'video_id')
- # # will generate 'movie_element' and 'movie?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a video element.
- # @param optional block to be invoked when element method is called
- #
- def video(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'video_for', &block)
- end
-
- #
- # adds three methods - one to retrieve the text of a b element, another to
- # retrieve a b element, and another to check for it's existence.
- #
- # @example
- # b(:bold, :id => 'title')
- # # will generate 'bold', 'bold_element', and 'bold?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a b.
- # @param optional block to be invoked when element method is called
- #
- def b(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier,'b_for', &block)
- define_method(name) do
- return platform.b_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
-
- #
- # adds three methods - one to retrieve the text of a i element, another to
- # retrieve a i element, and another to check for it's existence.
- #
- # @example
- # i(:italic, :id => 'title')
- # # will generate 'italic', 'italic_element', and 'italic?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a i.
- # @param optional block to be invoked when element method is called
- #
- def i(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier,'i_for', &block)
- define_method(name) do
- return platform.i_text_for identifier.clone unless block_given?
- self.send("#{name}_element").text
- end
- end
- alias_method :icon, :i
-
- #
- # adds two methods - one to retrieve a svg, and another to check
- # the svg's existence.
- #
- # @example
- # svg(:circle, :id => 'circle')
- # # will generate 'circle_element', and 'circle?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Hash] identifier how we find a svg.
- # @param optional block to be invoked when element method is called
- #
- def svg(name, identifier={:index => 0}, &block)
- standard_methods(name, identifier, 'svg_for', &block)
- end
-
-
- #
- # adds three methods - one to retrieve the text of an element, another
- # to retrieve an element, and another to check the element's existence.
- #
- # @example
- # element(:title, :header, :id => 'title')
- # # will generate 'title', 'title_element', and 'title?' methods
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Symbol] the name of the tag for the element
- # @param [Hash] identifier how we find an element.
- # @param optional block to be invoked when element method is called
- #
- def element(name, tag=:element, identifier={ :index => 0 }, &block)
- #
- # sets tag as element if not defined
- #
- if tag.is_a?(Hash)
- identifier = tag
- tag = :element
- end
-
- standard_methods(name, identifier, 'element_for', &block)
-
- define_method("#{name}") do
- element = self.send("#{name}_element")
-
- %w(Button TextField Radio Hidden CheckBox FileField).each do |klass|
- next unless element.element.class.to_s == "Watir::#{klass}"
- self.class.send(klass.gsub(/(.)([A-Z])/,'\1_\2').downcase, name, identifier, &block)
- return self.send name
- end
- element.text
- end
- define_method("#{name}_element") do
- return call_block(&block) if block_given?
- platform.element_for(tag, identifier.clone)
- end
- define_method("#{name}?") do
- self.send("#{name}_element").exists?
- end
- define_method("#{name}=") do |value|
- element = self.send("#{name}_element")
-
- klass = case element.element
- when Watir::TextField
- 'text_field'
- when Watir::TextArea
- 'text_area'
- when Watir::Select
- 'select_list'
- when Watir::FileField
- 'file_field'
- else
- raise "Can not set a #{element.element} element with #="
- end
- self.class.send(klass, name, identifier, &block)
- self.send("#{name}=", value)
- end
- end
-
- #
- # adds a method to return a collection of generic Element objects
- # for a specific tag.
- #
- # @example
- # elements(:title, :header, :id => 'title')
- # # will generate ''title_elements'
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Symbol] the name of the tag for the element
- # @param [Hash] identifier how we find an element.
- # @param optional block to be invoked when element method is called
- #
- def elements(name, tag=:element, identifier={:index => 0}, &block)
- #
- # sets tag as element if not defined
- #
- if tag.is_a?(Hash)
- identifier = tag
- tag = :element
- end
-
- define_method("#{name}_elements") do
- return call_block(&block) if block_given?
- platform.elements_for(tag, identifier.clone)
- end
- end
-
- #
- # adds a method to return a page object rooted at an element
- #
- # @example
- # page_section(:navigation_bar, NavigationBar, :id => 'nav-bar')
- # # will generate 'navigation_bar'
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Class] the class to instantiate for the element
- # @param [Hash] identifier how we find an element.
- #
- def page_section(name, section_class, identifier)
- define_method(name) do
- platform.page_for(identifier, section_class)
- end
- end
-
- #
- # adds a method to return a collection of page objects rooted at elements
- #
- # @example
- # page_sections(:articles, Article, :class => 'article')
- # # will generate 'articles'
- #
- # @param [Symbol] the name used for the generated method
- # @param [Class] the class to instantiate for each element
- # @param [Hash] identifier how we find an element.
- #
- def page_sections(name, section_class, identifier)
- define_method(name) do
- platform.pages_for(identifier, section_class)
- end
- end
-
- #
- # methods to generate accessors for types that follow the same
- # pattern as element
- #
- # @example
- # article(:my_article, :id => "article_id")
- # will generate 'my_article', 'my_article_element' and 'my_article?'
- # articles(:my_article, :id => 'article_id')
- # will generate 'my_article_elements'
- #
- # @param [Symbol] the name used for the generated methods
- # @param [Symbol] the name of the tag for the element
- # @param [Hash] identifier how we find an element.
- # @param optional block to be invoked when element method is called
- #
- LocatorGenerator::BASIC_ELEMENTS.each do |tag|
- define_method(tag) do |name, *identifier, &block|
- identifier = identifier[0] ? identifier[0] : {:index => 0}
- element(name, tag, identifier, &block)
- end
- define_method("#{tag}s") do |name, *identifier, &block|
- identifier = identifier[0] ? identifier[0] : {:index => 0}
- elements(name, tag, identifier, &block)
- end unless tag == :param
- end
-
- def standard_methods(name, identifier, method, &block)
- define_method("#{name}_element") do
- return call_block(&block) if block_given?
- platform.send(method, identifier.clone)
- end
- define_method("#{name}?") do
- return call_block(&block).exists? if block_given?
- platform.send(method, identifier.clone).exists?
- end
- end
-
- #
- # adds a method that will return an indexed property. The property will respond to
- # the [] method with an object that has a set of normal page_object properties that
- # correspond to the definitions included in the identifier_list parameter, with the
- # "what" of the "how and what" substituted based on the index provided to the []
- # method.
- #
- # @example
- # indexed_property(:title, [
- # [:text_field, :field_1, :id => 'table[%s].field_1'],
- # [:button, :button_1, :id => 'table[%s].button_1'],
- # [:text_field, :field_2, :name => 'table[%s].field_2']
- # ])
- # # will generate a title method that responds to []. title['foo'] will return an object
- # # that responds to the normal methods expected for two text_fields and a button with the
- # # given names, using the given how and what with 'foo' substituted for the %s. title[123]
- # # will do the same, using the integer 123 instead.
- #
- # @param [Symbol] the name used for the generated method
- # @param [Array] definitions an array of definitions to define on the indexed property. Each
- # entry in the array should contain two symbols and a hash, corresponding to one of the standard
- # page_object properties with a single substitution marker in each value in the hash,
- # e.g. [:text_field, :field_1, :id => 'table[%s].field_1']
- #
- def indexed_property (name, identifier_list)
- define_method("#{name}") do
- IndexedProperties::TableOfElements.new(@browser, identifier_list)
- end
- end
-
- #
- # methods to fetch multiple elements of the same type
- #
- # adds a method to the page object to return all of the matching elements
- #
- # @example
- # text_fields(:first_name, :id => "first_name")
- # # will generate 'first_name_elements'
- #
- # @param [String] the name used for the generated methods
- # @param [Hash] identifier how we find a text field. You can use a multiple parameters
- # by combining of any of the following except xpath. The valid
- # keys are the same ones supported by the standard methods.
- # @param optional block to be invoked when element method is called
- #
- idx = LocatorGenerator::ADVANCED_ELEMENTS.find_index { |type| type == :checkbox }
- elements = LocatorGenerator::ADVANCED_ELEMENTS.clone
- elements[idx] = :checkboxe
- elements.each do |method_name|
- define_method("#{method_name}s") do |name, *identifier, &block|
- define_method("#{name}_elements") do
- return call_block(&block) unless block.nil?
- platform_method = (method_name == :checkboxe) ? 'checkboxs_for' : "#{method_name.to_s}s_for"
- platform.send platform_method, (identifier.first ? identifier.first.clone : {})
- end
- end
- end
- end
-end
+require 'erb'
+require 'page-object/locator_generator'
+
+module PageObject
+ #
+ # Contains the class level methods that are inserted into your page objects
+ # when you include the PageObject module. These methods will generate another
+ # set of methods that provide access to the elements on the web pages.
+ #
+ module Accessors
+
+ #
+ # Set some values that can be used within the class. This is
+ # typically used to provide values that help build dynamic urls in
+ # the page_url method
+ #
+ # @param [Hash] the value to set the params
+ #
+ def params=(the_params)
+ @params = the_params
+ end
+
+ #
+ # Return the params that exist on this page class
+ #
+ def params
+ @params ||= {}
+ end
+
+ #
+ # Specify the url for the page. A call to this method will generate a
+ # 'goto' method to take you to the page.
+ #
+ # @param [String] the url for the page.
+ # @param [Symbol] a method name to call to get the url
+ #
+ def page_url(url)
+ define_method("goto") do
+ platform.navigate_to self.page_url_value
+ end
+
+ define_method('page_url_value') do
+ lookup = url.kind_of?(Symbol) ? self.send(url) : url
+ erb = ERB.new(%Q{#{lookup}})
+ merged_params = self.class.instance_variable_get("@merged_params")
+ params = merged_params ? merged_params : self.class.params
+ erb.result(binding)
+ end
+ end
+ alias_method :direct_url, :page_url
+
+ #
+ # Creates a method that waits the expected_title of a page to match the actual.
+ # @param [String] expected_title the literal expected title for the page
+ # @param [Regexp] expected_title the expected title pattern for the page
+ # @param [optional, Integer] timeout default value is nil - do not wait
+ # @return [boolean]
+ # @raise An exception if expected_title does not match actual title
+ #
+ # @example Specify 'Google' as the expected title of a page
+ # expected_title "Google"
+ # page.has_expected_title?
+ #
+ def wait_for_expected_title(expected_title, timeout=::PageObject.default_element_wait)
+ define_method("wait_for_expected_title?") do
+ error_message = lambda { "Expected title '#{expected_title}' instead of '#{title}'" }
+
+ has_expected_title = (expected_title === title)
+ wait_until(timeout, error_message.call) do
+ has_expected_title = (expected_title === title)
+ end unless has_expected_title
+
+ raise error_message.call unless has_expected_title
+ has_expected_title
+ end
+ end
+
+ #
+ # Creates a method that compares the expected_title of a page against the actual.
+ # @param [String] expected_title the literal expected title for the page
+ # @param [Regexp] expected_title the expected title pattern for the page
+ # @return [boolean]
+ # @raise An exception if expected_title does not match actual title
+ #
+ # @example Specify 'Google' as the expected title of a page
+ # expected_title "Google"
+ # page.has_expected_title?
+ #
+ def expected_title(expected_title)
+ define_method("has_expected_title?") do
+ page_title = title
+ has_expected_title = (expected_title === page_title)
+ raise "Expected title '#{expected_title}' instead of '#{page_title}'" unless has_expected_title
+ has_expected_title
+ end
+ end
+
+ #
+ # Creates a method that provides a way to initialize a page based upon an expected element.
+ # This is useful for pages that load dynamic content.
+ # @param [Symbol] the name given to the element in the declaration
+ # @param [optional, Integer] timeout default value is 5 seconds
+ # @return [boolean]
+ #
+ # @example Specify a text box named :address expected on the page within 10 seconds
+ # expected_element(:address, 10)
+ # page.has_expected_element?
+ #
+ def expected_element(element_name, timeout=::PageObject.default_element_wait)
+ define_method("has_expected_element?") do
+ self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_present timeout
+ end
+ end
+
+ #
+ # Creates a method that provides a way to initialize a page based upon an expected element to become visible.
+ # This is useful for pages that load dynamic content and might have hidden elements that are not shown.
+ # @param [Symbol] the name given to the element in the declaration
+ # @param [optional, Integer] timeout default value is 5 seconds
+ # @param [optional, boolean] also check that element to be visible if set to true
+ # @return [boolean]
+ #
+ # @example Specify a text box named :address expected on the page within 10 seconds
+ # expected_element_visible(:address, 10)
+ # page.has_expected_element_visible?
+ #
+ def expected_element_visible(element_name, timeout=::PageObject.default_element_wait, check_visible=false)
+ define_method("has_expected_element_visible?") do
+ self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_present timeout
+ self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_visible timeout
+ end
+ end
+
+ #
+ # Identify an element as existing within a frame . A frame parameter
+ # is passed to the block and must be passed to the other calls to PageObject.
+ # You can nest calls to in_frame by passing the frame to the next level.
+ #
+ # @example
+ # in_frame(:id => 'frame_id') do |frame|
+ # text_field(:first_name, :id => 'fname', :frame => frame)
+ # end
+ #
+ # @param [Hash] identifier how we find the frame. The valid keys are:
+ # * :id
+ # * :index
+ # * :name
+ # * :regexp
+ # @param frame passed from a previous call to in_frame. Used to nest calls
+ # @param block that contains the calls to elements that exist inside the frame.
+ #
+ def in_frame(identifier, frame=nil, &block)
+ frame = frame.nil? ? [] : frame.dup
+ frame << {frame: identifier}
+ block.call(frame)
+ end
+
+ #
+ # Identify an element as existing within an iframe. A frame parameter
+ # is passed to the block and must be passed to the other calls to PageObject.
+ # You can nest calls to in_frame by passing the frame to the next level.
+ #
+ # @example
+ # in_iframe(:id => 'frame_id') do |frame|
+ # text_field(:first_name, :id => 'fname', :frame => frame)
+ # end
+ #
+ # @param [Hash] identifier how we find the frame. The valid keys are:
+ # * :id
+ # * :index
+ # * :name
+ # * :regexp
+ # @param frame passed from a previous call to in_iframe. Used to nest calls
+ # @param block that contains the calls to elements that exist inside the iframe.
+ #
+ def in_iframe(identifier, frame=nil, &block)
+ frame = frame.nil? ? [] : frame.dup
+ frame << {iframe: identifier}
+ block.call(frame)
+ end
+
+ #
+ # adds four methods to the page object - one to set text in a text field,
+ # another to retrieve text from a text field, another to return the text
+ # field element, another to check the text field's existence.
+ #
+ # @example
+ # text_field(:first_name, :id => "first_name")
+ # # will generate 'first_name', 'first_name=', 'first_name_element',
+ # # 'first_name?' methods
+ #
+ # @param [String] the name used for the generated methods
+ # @param [Hash] identifier how we find a text field.
+ # @param optional block to be invoked when element method is called
+ #
+ def text_field(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'text_field_for', &block)
+ define_method(name) do
+ return platform.text_field_value_for identifier.clone unless block_given?
+ self.send("#{name}_element").value
+ end
+ define_method("#{name}=") do |value|
+ return platform.text_field_value_set(identifier.clone, value) unless block_given?
+ self.send("#{name}_element").value = value
+ end
+ end
+
+ #
+ # adds four methods to the page object - one to set value in a date field,
+ # another to retrieve value from a date field, another to return the date
+ # field element, another to check the date field's existence.
+ #
+ # @example
+ # date_field(:date_of_birth, :id => "date_of_birth")
+ # # will generate 'date_of_birth', 'date_of_birth=', 'date_of_birth_element',
+ # # 'date_of_birth?' methods
+ #
+ # @param [String] the name used for the generated methods
+ # @param [Hash] identifier how we find a date field.
+ # @param optional block to be invoked when element method is called
+ #
+ def date_field(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'date_field_for', &block)
+ define_method(name) do
+ return platform.date_field_value_for identifier.clone unless block_given?
+ self.send("#{name}_element").value
+ end
+ define_method("#{name}=") do |value|
+ return platform.date_field_value_set(identifier.clone, value) unless block_given?
+ self.send("#{name}_element").value = value
+ end
+ end
+
+ #
+ # adds three methods to the page object - one to get the text from a hidden field,
+ # another to retrieve the hidden field element, and another to check the hidden
+ # field's existence.
+ #
+ # @example
+ # hidden_field(:user_id, :id => "user_identity")
+ # # will generate 'user_id', 'user_id_element' and 'user_id?' methods
+ #
+ # @param [String] the name used for the generated methods
+ # @param [Hash] identifier how we find a hidden field.
+ # @param optional block to be invoked when element method is called
+ #
+ def hidden_field(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'hidden_field_for', &block)
+ define_method(name) do
+ return platform.hidden_field_value_for identifier.clone unless block_given?
+ self.send("#{name}_element").value
+ end
+ end
+ alias_method :hidden, :hidden_field
+
+ #
+ # adds four methods to the page object - one to set text in a text area,
+ # another to retrieve text from a text area, another to return the text
+ # area element, and another to check the text area's existence.
+ #
+ # @example
+ # text_area(:address, :id => "address")
+ # # will generate 'address', 'address=', 'address_element',
+ # # 'address?' methods
+ #
+ # @param [String] the name used for the generated methods
+ # @param [Hash] identifier how we find a text area.
+ # @param optional block to be invoked when element method is called
+ #
+ def text_area(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'text_area_for', &block)
+ define_method(name) do
+ return platform.text_area_value_for identifier.clone unless block_given?
+ self.send("#{name}_element").value
+ end
+ define_method("#{name}=") do |value|
+ return platform.text_area_value_set(identifier.clone, value) unless block_given?
+ self.send("#{name}_element").value = value
+ end
+ end
+ alias_method :textarea, :text_area
+
+ #
+ # adds five methods - one to select an item in a drop-down,
+ # another to fetch the currently selected item text, another
+ # to retrieve the select list element, another to check the
+ # drop down's existence and another to get all the available options
+ # to select from.
+ #
+ # @example
+ # select_list(:state, :id => "state")
+ # # will generate 'state', 'state=', 'state_element', 'state?', "state_options" methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a select list.
+ # @param optional block to be invoked when element method is called
+ #
+ def select_list(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'select_list_for', &block)
+ define_method(name) do
+ return platform.select_list_value_for identifier.clone unless block_given?
+ self.send("#{name}_element").value
+ end
+ define_method("#{name}=") do |value|
+ return platform.select_list_value_set(identifier.clone, value) unless block_given?
+ self.send("#{name}_element").select(value)
+ end
+ define_method("#{name}_options") do
+ element = self.send("#{name}_element")
+ (element && element.options) ? element.options.collect(&:text) : []
+ end
+ end
+ alias_method :select, :select_list
+
+ #
+ # adds three methods - one to select a link, another
+ # to return a PageObject::Elements::Link object representing
+ # the link, and another that checks the link's existence.
+ #
+ # @example
+ # link(:add_to_cart, :text => "Add to Cart")
+ # # will generate 'add_to_cart', 'add_to_cart_element', and 'add_to_cart?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a link.
+ # @param optional block to be invoked when element method is called
+ #
+ def link(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'link_for', &block)
+ define_method(name) do
+ return platform.click_link_for identifier.clone unless block_given?
+ self.send("#{name}_element").click
+ end
+ end
+ alias_method :a, :link
+
+ #
+ # adds five methods - one to check, another to uncheck, another
+ # to return the state of a checkbox, another to return
+ # a PageObject::Elements::CheckBox object representing the checkbox, and
+ # a final method to check the checkbox's existence.
+ #
+ # @example
+ # checkbox(:active, :name => "is_active")
+ # # will generate 'check_active', 'uncheck_active', 'active_checked?',
+ # # 'active_element', and 'active?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a checkbox.
+ # @param optional block to be invoked when element method is called
+ #
+ def checkbox(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'checkbox_for', &block)
+ define_method("check_#{name}") do
+ return platform.check_checkbox(identifier.clone) unless block_given?
+ self.send("#{name}_element").check
+ end
+ define_method("uncheck_#{name}") do
+ return platform.uncheck_checkbox(identifier.clone) unless block_given?
+ self.send("#{name}_element").uncheck
+ end
+ define_method("#{name}_checked?") do
+ return platform.checkbox_checked?(identifier.clone) unless block_given?
+ self.send("#{name}_element").checked?
+ end
+ end
+
+ #
+ # adds four methods - one to select, another to return if a radio button
+ # is selected, another method to return a PageObject::Elements::RadioButton
+ # object representing the radio button element, and another to check
+ # the radio button's existence.
+ #
+ # @example
+ # radio_button(:north, :id => "north")
+ # # will generate 'select_north', 'north_selected?',
+ # # 'north_element', and 'north?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a radio button.
+ # @param optional block to be invoked when element method is called
+ #
+ def radio_button(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'radio_button_for', &block)
+ define_method("select_#{name}") do
+ return platform.select_radio(identifier.clone) unless block_given?
+ self.send("#{name}_element").select
+ end
+ define_method("#{name}_selected?") do
+ return platform.radio_selected?(identifier.clone) unless block_given?
+ self.send("#{name}_element").selected?
+ end
+ end
+ alias_method :radio, :radio_button
+
+ #
+ # adds five methods to help interact with a radio button group -
+ # a method to select a radio button in the group by given value/text,
+ # a method to return the values of all radio buttons in the group, a method
+ # to return if a radio button in the group is selected (will return
+ # the text of the selected radio button, if true), a method to return
+ # an array of PageObject::Elements::RadioButton objects representing
+ # the radio button group, and finally a method to check the existence
+ # of the radio button group.
+ #
+ # @example
+ # radio_button_group(:color, :name => "preferred_color")
+ # will generate 'select_color', 'color_values', 'color_selected?',
+ # 'color_elements', and 'color?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] shared identifier for the radio button group. Typically, a 'name' attribute.
+ # The valid keys are:
+ # * :name
+ #
+ def radio_button_group(name, identifier)
+ define_method("select_#{name}") do |value|
+ platform.radio_buttons_for(identifier.clone).each do |radio_elem|
+ if radio_elem.value == value
+ return radio_elem.select
+ end
+ end
+ end
+ define_method("#{name}_values") do
+ result = []
+ platform.radio_buttons_for(identifier.clone).each do |radio_elem|
+ result << radio_elem.value
+ end
+ return result
+ end
+ define_method("#{name}_selected?") do
+ platform.radio_buttons_for(identifier.clone).each do |radio_elem|
+ return radio_elem.value if radio_elem.selected?
+ end
+ return false
+ end
+ define_method("#{name}_elements") do
+ return platform.radio_buttons_for(identifier.clone)
+ end
+ define_method("#{name}?") do
+ return platform.radio_buttons_for(identifier.clone).any?
+ end
+ end
+ alias_method :radio_group, :radio_button_group
+
+ #
+ # adds three methods - one to click a button, another to
+ # return the button element, and another to check the button's existence.
+ #
+ # @example
+ # button(:purchase, :id => 'purchase')
+ # # will generate 'purchase', 'purchase_element', and 'purchase?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a button.
+ # @param optional block to be invoked when element method is called
+ #
+ def button(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'button_for', &block)
+ define_method(name) do
+ return platform.click_button_for identifier.clone unless block_given?
+ self.send("#{name}_element").click
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text from a div,
+ # another to return the div element, and another to check the div's existence.
+ #
+ # @example
+ # div(:message, :id => 'message')
+ # # will generate 'message', 'message_element', and 'message?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a div.
+ # @param optional block to be invoked when element method is called
+ #
+ def div(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'div_for', &block)
+ define_method(name) do
+ return platform.div_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text from a span,
+ # another to return the span element, and another to check the span's existence.
+ #
+ # @example
+ # span(:alert, :id => 'alert')
+ # # will generate 'alert', 'alert_element', and 'alert?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a span.
+ # @param optional block to be invoked when element method is called
+ #
+ def span(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'span_for', &block)
+ define_method(name) do
+ return platform.span_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to return the text for the table, one
+ # to retrieve the table element, and another to
+ # check the table's existence.
+ #
+ # @example
+ # table(:cart, :id => 'shopping_cart')
+ # # will generate a 'cart', 'cart_element' and 'cart?' method
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a table.
+ # @param optional block to be invoked when element method is called
+ #
+ def table(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'table_for', &block)
+ define_method(name) do
+ return platform.table_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text from a table cell,
+ # another to return the table cell element, and another to check the cell's
+ # existence.
+ #
+ # @example
+ # cell(:total, :id => 'total_cell')
+ # # will generate 'total', 'total_element', and 'total?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a cell.
+ # @param optional block to be invoked when element method is called
+ #
+ def cell(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'cell_for', &block)
+ define_method("#{name}") do
+ return platform.cell_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+ alias_method :td, :cell
+
+
+ #
+ # adds three methods - one to retrieve the text from a table row,
+ # another to return the table row element, and another to check the row's
+ # existence.
+ #
+ # @example
+ # row(:sums, :id => 'sum_row')
+ # # will generate 'sums', 'sums_element', and 'sums?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a cell.
+ # @param optional block to be invoked when element method is called
+ #
+ def row(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'row_for', &block)
+ define_method("#{name}") do
+ return platform.row_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the image element, another to
+ # check the load status of the image, and another to check the
+ # image's existence.
+ #
+ # @example
+ # image(:logo, :id => 'logo')
+ # # will generate 'logo_element', 'logo_loaded?', and 'logo?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find an image.
+ # @param optional block to be invoked when element method is called
+ #
+ def image(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'image_for', &block)
+ define_method("#{name}_loaded?") do
+ return platform.image_loaded_for identifier.clone unless block_given?
+ self.send("#{name}_element").loaded?
+ end
+ end
+ alias_method :img, :image
+
+ #
+ # adds two methods - one to retrieve the form element, and another to
+ # check the form's existence.
+ #
+ # @example
+ # form(:login, :id => 'login')
+ # # will generate 'login_element' and 'login?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a form.
+ # @param optional block to be invoked when element method is called
+ #
+ def form(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'form_for', &block)
+ end
+
+ #
+ # adds three methods - one to retrieve the text from a list item,
+ # another to return the list item element, and another to check the list item's
+ # existence.
+ #
+ # @example
+ # list_item(:item_one, :id => 'one')
+ # # will generate 'item_one', 'item_one_element', and 'item_one?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a list item.
+ # @param optional block to be invoked when element method is called
+ #
+ def list_item(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'list_item_for', &block)
+ define_method(name) do
+ return platform.list_item_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+ alias_method :li, :list_item
+
+ #
+ # adds three methods - one to return the text within the unordered
+ # list, one to retrieve the unordered list element, and another to
+ # check it's existence.
+ #
+ # @example
+ # unordered_list(:menu, :id => 'main_menu')
+ # # will generate 'menu', 'menu_element' and 'menu?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find an unordered list.
+ # @param optional block to be invoked when element method is called
+ #
+ def unordered_list(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'unordered_list_for', &block)
+ define_method(name) do
+ return platform.unordered_list_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+ alias_method :ul, :unordered_list
+
+ #
+ # adds three methods - one to return the text within the ordered
+ # list, one to retrieve the ordered list element, and another to
+ # test it's existence.
+ #
+ # @example
+ # ordered_list(:top_five, :id => 'top')
+ # # will generate 'top_five', 'top_five_element' and 'top_five?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find an ordered list.
+ # @param optional block to be invoked when element method is called
+ #
+ def ordered_list(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'ordered_list_for', &block)
+ define_method(name) do
+ return platform.ordered_list_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+ alias_method :ol, :ordered_list
+
+ #
+ # adds three methods - one to retrieve the text of a h1 element, another to
+ # retrieve a h1 element, and another to check for it's existence.
+ #
+ # @example
+ # h1(:title, :id => 'title')
+ # # will generate 'title', 'title_element', and 'title?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a H1. You can use a multiple parameters
+ # by combining of any of the following except xpath.
+ # @param optional block to be invoked when element method is called
+ #
+ def h1(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier,'h1_for', &block)
+ define_method(name) do
+ return platform.h1_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text of a h2 element, another
+ # to retrieve a h2 element, and another to check for it's existence.
+ #
+ # @example
+ # h2(:title, :id => 'title')
+ # # will generate 'title', 'title_element', and 'title?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a H2.
+ # @param optional block to be invoked when element method is called
+ #
+ def h2(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'h2_for', &block)
+ define_method(name) do
+ return platform.h2_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text of a h3 element,
+ # another to return a h3 element, and another to check for it's existence.
+ #
+ # @example
+ # h3(:title, :id => 'title')
+ # # will generate 'title', 'title_element', and 'title?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a H3.
+ # @param optional block to be invoked when element method is called
+ #
+ def h3(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'h3_for', &block)
+ define_method(name) do
+ return platform.h3_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text of a h4 element,
+ # another to return a h4 element, and another to check for it's existence.
+ #
+ # @example
+ # h4(:title, :id => 'title')
+ # # will generate 'title', 'title_element', and 'title?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a H4.
+ # @param optional block to be invoked when element method is called
+ #
+ def h4(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'h4_for', &block)
+ define_method(name) do
+ return platform.h4_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text of a h5 element,
+ # another to return a h5 element, and another to check for it's existence.
+ #
+ # @example
+ # h5(:title, :id => 'title')
+ # # will generate 'title', 'title_element', and 'title?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a H5.
+ # @param optional block to be invoked when element method is called
+ #
+ def h5(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'h5_for', &block)
+ define_method(name) do
+ return platform.h5_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text of a h6 element,
+ # another to return a h6 element, and another to check for it's existence.
+ #
+ # @example
+ # h6(:title, :id => 'title')
+ # # will generate 'title', 'title_element', and 'title?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a H6.
+ # @param optional block to be invoked when element method is called
+ #
+ def h6(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'h6_for', &block)
+ define_method(name) do
+ return platform.h6_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text of a paragraph, another
+ # to retrieve a paragraph element, and another to check the paragraph's existence.
+ #
+ # @example
+ # paragraph(:title, :id => 'title')
+ # # will generate 'title', 'title_element', and 'title?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a paragraph.
+ # @param optional block to be invoked when element method is called
+ #
+ def paragraph(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'paragraph_for', &block)
+ define_method(name) do
+ return platform.paragraph_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+ alias_method :p, :paragraph
+
+ #
+ # adds three methods - one to set the file for a file field, another to retrieve
+ # the file field element, and another to check it's existence.
+ #
+ # @example
+ # file_field(:the_file, :id => 'file_to_upload')
+ # # will generate 'the_file=', 'the_file_element', and 'the_file?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a file_field.
+ # @param optional block to be invoked when element method is called
+ #
+ def file_field(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'file_field_for', &block)
+ define_method("#{name}=") do |value|
+ return platform.file_field_value_set(identifier.clone, value) unless block_given?
+ self.send("#{name}_element").value = value
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text from a label,
+ # another to return the label element, and another to check the label's existence.
+ #
+ # @example
+ # label(:message, :id => 'message')
+ # # will generate 'message', 'message_element', and 'message?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a label.
+ # @param optional block to be invoked when element method is called
+ #
+ def label(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'label_for', &block)
+ define_method(name) do
+ return platform.label_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to click the area,
+ # another to return the area element, and another to check the area's existence.
+ #
+ # @example
+ # area(:message, :id => 'message')
+ # # will generate 'message', 'message_element', and 'message?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find an area.
+ # @param optional block to be invoked when element method is called
+ #
+ def area(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'area_for', &block)
+ define_method(name) do
+ return platform.click_area_for identifier.clone unless block_given?
+ self.send("#{name}_element").click
+ end
+ end
+
+ #
+ # adds two methods - one to return the canvas element and another to check
+ # the canvas's existence.
+ #
+ # @example
+ # canvas(:my_canvas, :id => 'canvas_id')
+ # # will generate 'my_canvas_element' and 'my_canvas?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a canvas.
+ # @param optional block to be invoked when element method is called
+ #
+ def canvas(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'canvas_for', &block)
+ end
+
+ #
+ # adds two methods - one to return the audio element and another to check
+ # the audio's existence.
+ #
+ # @example
+ # audio(:acdc, :id => 'audio_id')
+ # # will generate 'acdc_element' and 'acdc?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find an audio element.
+ # @param optional block to be invoked when element method is called
+ #
+ def audio(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'audio_for', &block)
+ end
+
+ #
+ # adds two methods - one to return the video element and another to check
+ # the video's existence.
+ #
+ # @example
+ # video(:movie, :id => 'video_id')
+ # # will generate 'movie_element' and 'movie?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a video element.
+ # @param optional block to be invoked when element method is called
+ #
+ def video(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'video_for', &block)
+ end
+
+ #
+ # adds three methods - one to retrieve the text of a b element, another to
+ # retrieve a b element, and another to check for it's existence.
+ #
+ # @example
+ # b(:bold, :id => 'title')
+ # # will generate 'bold', 'bold_element', and 'bold?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a b.
+ # @param optional block to be invoked when element method is called
+ #
+ def b(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier,'b_for', &block)
+ define_method(name) do
+ return platform.b_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+
+ #
+ # adds three methods - one to retrieve the text of a i element, another to
+ # retrieve a i element, and another to check for it's existence.
+ #
+ # @example
+ # i(:italic, :id => 'title')
+ # # will generate 'italic', 'italic_element', and 'italic?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a i.
+ # @param optional block to be invoked when element method is called
+ #
+ def i(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier,'i_for', &block)
+ define_method(name) do
+ return platform.i_text_for identifier.clone unless block_given?
+ self.send("#{name}_element").text
+ end
+ end
+ alias_method :icon, :i
+
+ #
+ # adds two methods - one to retrieve a svg, and another to check
+ # the svg's existence.
+ #
+ # @example
+ # svg(:circle, :id => 'circle')
+ # # will generate 'circle_element', and 'circle?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Hash] identifier how we find a svg.
+ # @param optional block to be invoked when element method is called
+ #
+ def svg(name, identifier={:index => 0}, &block)
+ standard_methods(name, identifier, 'svg_for', &block)
+ end
+
+
+ #
+ # adds three methods - one to retrieve the text of an element, another
+ # to retrieve an element, and another to check the element's existence.
+ #
+ # @example
+ # element(:title, :header, :id => 'title')
+ # # will generate 'title', 'title_element', and 'title?' methods
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Symbol] the name of the tag for the element
+ # @param [Hash] identifier how we find an element.
+ # @param optional block to be invoked when element method is called
+ #
+ def element(name, tag=:element, identifier={ :index => 0 }, &block)
+ #
+ # sets tag as element if not defined
+ #
+ if tag.is_a?(Hash)
+ identifier = tag
+ tag = :element
+ end
+
+ standard_methods(name, identifier, 'element_for', &block)
+
+ define_method("#{name}") do
+ element = self.send("#{name}_element")
+
+ %w(Button TextField Radio Hidden CheckBox FileField).each do |klass|
+ next unless element.element.class.to_s == "Watir::#{klass}"
+ self.class.send(klass.gsub(/(.)([A-Z])/,'\1_\2').downcase, name, identifier, &block)
+ return self.send name
+ end
+ element.text
+ end
+ define_method("#{name}_element") do
+ return call_block(&block) if block_given?
+ platform.element_for(tag, identifier.clone)
+ end
+ define_method("#{name}?") do
+ self.send("#{name}_element").exists?
+ end
+ define_method("#{name}=") do |value|
+ element = self.send("#{name}_element")
+
+ klass = case element.element
+ when Watir::TextField
+ 'text_field'
+ when Watir::TextArea
+ 'text_area'
+ when Watir::Select
+ 'select_list'
+ when Watir::FileField
+ 'file_field'
+ else
+ raise "Can not set a #{element.element} element with #="
+ end
+ self.class.send(klass, name, identifier, &block)
+ self.send("#{name}=", value)
+ end
+ end
+
+ #
+ # adds a method to return a collection of generic Element objects
+ # for a specific tag.
+ #
+ # @example
+ # elements(:title, :header, :id => 'title')
+ # # will generate ''title_elements'
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Symbol] the name of the tag for the element
+ # @param [Hash] identifier how we find an element.
+ # @param optional block to be invoked when element method is called
+ #
+ def elements(name, tag=:element, identifier={:index => 0}, &block)
+ #
+ # sets tag as element if not defined
+ #
+ if tag.is_a?(Hash)
+ identifier = tag
+ tag = :element
+ end
+
+ define_method("#{name}_elements") do
+ return call_block(&block) if block_given?
+ platform.elements_for(tag, identifier.clone)
+ end
+ end
+
+ #
+ # adds a method to return a page object rooted at an element
+ #
+ # @example
+ # page_section(:navigation_bar, NavigationBar, :id => 'nav-bar')
+ # # will generate 'navigation_bar'
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Class] the class to instantiate for the element
+ # @param [Hash] identifier how we find an element.
+ #
+ def page_section(name, section_class, identifier)
+ define_method(name) do
+ platform.page_for(identifier, section_class)
+ end
+ end
+
+ #
+ # adds a method to return a collection of page objects rooted at elements
+ #
+ # @example
+ # page_sections(:articles, Article, :class => 'article')
+ # # will generate 'articles'
+ #
+ # @param [Symbol] the name used for the generated method
+ # @param [Class] the class to instantiate for each element
+ # @param [Hash] identifier how we find an element.
+ #
+ def page_sections(name, section_class, identifier)
+ define_method(name) do
+ platform.pages_for(identifier, section_class)
+ end
+ end
+
+ #
+ # methods to generate accessors for types that follow the same
+ # pattern as element
+ #
+ # @example
+ # article(:my_article, :id => "article_id")
+ # will generate 'my_article', 'my_article_element' and 'my_article?'
+ # articles(:my_article, :id => 'article_id')
+ # will generate 'my_article_elements'
+ #
+ # @param [Symbol] the name used for the generated methods
+ # @param [Symbol] the name of the tag for the element
+ # @param [Hash] identifier how we find an element.
+ # @param optional block to be invoked when element method is called
+ #
+ LocatorGenerator::BASIC_ELEMENTS.each do |tag|
+ define_method(tag) do |name, *identifier, &block|
+ identifier = identifier[0] ? identifier[0] : {:index => 0}
+ element(name, tag, identifier, &block)
+ end
+ define_method("#{tag}s") do |name, *identifier, &block|
+ identifier = identifier[0] ? identifier[0] : {:index => 0}
+ elements(name, tag, identifier, &block)
+ end unless tag == :param
+ end
+
+ def standard_methods(name, identifier, method, &block)
+ define_method("#{name}_element") do
+ return call_block(&block) if block_given?
+ platform.send(method, identifier.clone)
+ end
+ define_method("#{name}?") do
+ return call_block(&block).exists? if block_given?
+ platform.send(method, identifier.clone).exists?
+ end
+ end
+
+ #
+ # adds a method that will return an indexed property. The property will respond to
+ # the [] method with an object that has a set of normal page_object properties that
+ # correspond to the definitions included in the identifier_list parameter, with the
+ # "what" of the "how and what" substituted based on the index provided to the []
+ # method.
+ #
+ # @example
+ # indexed_property(:title, [
+ # [:text_field, :field_1, :id => 'table[%s].field_1'],
+ # [:button, :button_1, :id => 'table[%s].button_1'],
+ # [:text_field, :field_2, :name => 'table[%s].field_2']
+ # ])
+ # # will generate a title method that responds to []. title['foo'] will return an object
+ # # that responds to the normal methods expected for two text_fields and a button with the
+ # # given names, using the given how and what with 'foo' substituted for the %s. title[123]
+ # # will do the same, using the integer 123 instead.
+ #
+ # @param [Symbol] the name used for the generated method
+ # @param [Array] definitions an array of definitions to define on the indexed property. Each
+ # entry in the array should contain two symbols and a hash, corresponding to one of the standard
+ # page_object properties with a single substitution marker in each value in the hash,
+ # e.g. [:text_field, :field_1, :id => 'table[%s].field_1']
+ #
+ def indexed_property (name, identifier_list)
+ define_method("#{name}") do
+ IndexedProperties::TableOfElements.new(@browser, identifier_list)
+ end
+ end
+
+ #
+ # methods to fetch multiple elements of the same type
+ #
+ # adds a method to the page object to return all of the matching elements
+ #
+ # @example
+ # text_fields(:first_name, :id => "first_name")
+ # # will generate 'first_name_elements'
+ #
+ # @param [String] the name used for the generated methods
+ # @param [Hash] identifier how we find a text field. You can use a multiple parameters
+ # by combining of any of the following except xpath. The valid
+ # keys are the same ones supported by the standard methods.
+ # @param optional block to be invoked when element method is called
+ #
+ idx = LocatorGenerator::ADVANCED_ELEMENTS.find_index { |type| type == :checkbox }
+ elements = LocatorGenerator::ADVANCED_ELEMENTS.clone
+ elements[idx] = :checkboxe
+ elements.each do |method_name|
+ define_method("#{method_name}s") do |name, *identifier, &block|
+ define_method("#{name}_elements") do
+ return call_block(&block) unless block.nil?
+ platform_method = (method_name == :checkboxe) ? 'checkboxs_for' : "#{method_name.to_s}s_for"
+ platform.send platform_method, (identifier.first ? identifier.first.clone : {})
+ end
+ end
+ end
+ end
+end