require 'extensions/string' require 'watir/exceptions' # so we can trap them require 'watircraft/table' module Taza # An abstraction of a web page, place the elements you care about accessing in here as well as specify the filters that apply when trying to access the element. # # Example: # require 'taza' # class HomePage < Taza::Page # element(:submit) {browser.button(:value, 'Submit')} # filter :title_given, :foo # # def title_given # browser.title.nil? # end # end # # home_page.submit will return the button specified if the filter returned true class Page attr_accessor :browser, :site class << self def elements # :nodoc: @elements ||= {} end def filters # :nodoc: @filters ||= Hash.new { [] } end def fields # :nodoc: @fields ||= [] end def tables # :nodoc: @tables ||= [] end def url string=nil if string.nil? @url else @url = string end end # An element on a page # # Watir Example: # class HomePage < Taza::Page # element(:next_button) {browser.button(:value, 'Next'} # end # # home_page.next_button.click def element(name, &block) name = name.to_s.computerize.to_sym elements[name] = block end # An element on a page that has a value. # Use #field for input elements and data elements. # # class HomePage < Taza::Page # field(:name) {browser.text_field(:name, 'user_name')} # end # # home_page.name_field # returns the text element # home_page.name_field.exists? # home_page.name = "Fred" # sets the text element (A) # home_page.name # returns the value of the text element (B) # # The following Watir elements provide both #set (A) and #display_value (B) methods # text_field (both text boxes and text areas) # file_field # select_list # checkbox # # Most other Watir elements provide #display_value (B) methods only. def field(name, suffix='field', &block) name = name.to_s.computerize.to_sym fields << name element_name = "#{name}_#{suffix}" elements[element_name] = block define_method(name) do send(element_name).display_value end define_method("#{name}=") do |value| send(element_name).set value end element_name end # A filter for element(s) on a page # Example: # class HomePage < Taza::Page # element(:foo) {browser.element_by_xpath('some xpath')} # filter :title_given, :foo # #a filter will apply to all elements if none are specified # filter :some_filter # #a filter will also apply to all elements if the symbol :all is given # filter :another_filter, :all # # def some_filter # true # end # # def some_filter # true # end # # def title_given # browser.title.nil? # end # end def filter(method_name, *elements) elements = [:all] if elements.empty? elements.each do |element| self.filters[element] = self.filters[element] << method_name end end # Provides access to a WatirCraft::Table. # # Requires that an element also be declared on the page that directly # wraps the table element itself. # # Example definition # # class YourCartPage < ::Taza::Page # element(:items_table) {@browser.table(:index, 1)} # table(:items) do # field(:quantity) {@row.cell(:index, 1)} # field(:description) {@row.cell(:index, 2)} # end # field(:total) {@browser.cell(:id, 'totalcell')} # end # # Example usage # # your_cart_page.items.row(:description => 'Pragmatic Project Automation').quantity.should == '1' # # Technical details: this method creates a # subclass and then allows its class methods to define fields and # elements on the table. def table(name, &block) tables << name # create subclass for the table sub_class = Class.new(WatirCraft::Table) sub_class.class_eval &block # add method to the page, it returns an instance of the table subclass define_method(name) do sub_class.new send("#{name}_table") end end end def initialize add_element_methods @active_filters = [] end def add_element_methods # :nodoc: self.class.elements.each do |element_name,element_block| filters = self.class.filters[element_name] + self.class.filters[:all] add_element_method(:filters => filters, :element_name => element_name, :element_block => element_block) end end def add_element_method(params) # :nodoc: self.class.class_eval do define_method(params[:element_name]) do |*args| check_filters(params) self.instance_exec(*args,¶ms[:element_block]) end end end def check_filters(params) # :nodoc: params[:filters].each do |filter_method| unless @active_filters.include?(filter_method) @active_filters << filter_method raise FilterError, "#{filter_method} returned false for #{params[:element_name]}" unless send(filter_method) @active_filters.delete(filter_method) end end end # Go to this page. Url is computed based the page url and the url from the # Site & Settings. def goto @site.goto self.class.url end # Return the full url expected for the page, taking into account the Site # and settings. def full_url File.join(@site.origin, self.class.url) end alias :url :full_url # Enter values into fields on the page using a hash, using the key of # each pair to name the field. def populate hash hash.each do |key, value| send "#{key}=", value end end # Verify that the fields specified by the keys in the hash correspond to the # provided values. def validate hash hash.each do |key, value| send(key).should == value end end # Return the names of the elements defined for the page. def elements self.class.elements.keys.map &:to_s end # Return the names of the fields defined for the page. def fields self.class.fields.map &:to_s end # Return the names of the tables defined for the page. def tables self.class.tables.map &:to_s end # Returns a hash with the names and values of the specified fields. # If no fields are specifieds, all fields on the page are used. def values field_names=fields result = {} field_names.each { |name| result[name.to_sym] = send(name)} result end include Watir::Exception def element_exist? name begin send(name).exist? rescue UnknownFrameException, UnknownObjectException, UnknownFormException, UnknownCellException false end end alias :element_exists? :element_exist? def elements_exist? element_names=elements result = {} element_names.each do |element| result[element.to_sym] = element_exist?(element) end result end alias :elements_exists? :elements_exist? end class FilterError < StandardError; end end