lib/symbiont/elements.rb in symbiont-0.3.0 vs lib/symbiont/elements.rb in symbiont-0.4.0

- old
+ new

@@ -8,43 +8,120 @@ @elements = Watir::Container.instance_methods end @elements end + def self.settable + @settable ||= [:text_field] + end + + def self.settable?(element) + settable.include? element.to_sym + end + module Element # Iterates through Watir factory methods. Each method is defined # as a method that can be called on a page class. This is what # allows element definitions to be created. Symbiont.elements.each do |element| define_method element do |*signature, &block| identifier, locator = parse_signature(signature) context = context_from_signature(locator, &block) define_element_accessor(identifier, locator, element, &context) + define_set_accessor(identifier, locator, element, &context) if Symbiont.settable?(element) end end private - # @param identifier [String] friendly name of element definition - # @param locator [Array] locators for referencing the element - # @param element [String] name of Watir-based object + # Defines an accessor method for an element that allows the friendly + # name of the element to be proxied to a Watir element object that + # corresponds to the element type. + # + # @param identifier [Symbol] friendly name of element definition + # @param locator [Hash] locators for referencing the element + # @param element [Symbol] name of Watir-based object # @param block [Proc] a context block # # @example - # enable, {:id => 'enableForm'}, checkbox + # This element definition: + # text_field :weight, id: 'wt', index: 0 + # + # passed in like this: + # :weight, {:id => 'wt', :index => 0}, :text_field + # + # This allows access like this: + # @page.weight.set '200' + # + # Access could also be done this way: + # @page.weight(id: 'wt').set '200' + # + # The second approach would lead to the *values variable having + # an array like this: [{:id => 'wt'}]. + # + # A third approach would be to utilize one element definition + # within the context of another. Consider the following element + # definitions: + # article :practice, id: 'practice' + # + # a :page_link do |text| + # practice.a(text: text) + # end + # + # These could be utilized as such: + # on_view(Practice).page_link('Click Me').click + # + # This approach would lead to the *values variable having + # an array like this: ["Click Me"]. def define_element_accessor(identifier, locator, element, &block) define_method "#{identifier}".to_sym do |*values| - #puts "*** *values: #{values}" - if block_given? instance_exec(*values, &block) else reference_element(element, locator) end end end + # Defines an accessor method for an element that allows the value of + # the element to be set via appending an "=" to the friendly name + # (identifier) of the element passed in. + # + # @param identifier [Symbol] friendly name of element definition + # @param locator [Hash] locators for referencing the element + # @param element [Symbol] name of Watir-based object + # @param block [Proc] a context block + # + # @example + # This element definition: + # text_field :weight, id: 'wt' + # + # Can be accessed in two ways: + # @page.weight.set '200' + # @page.weight = '200' + # + # The second approach would lead to the *values variable having + # an array like this: ['200']. The first approach would be + # handled by define_element_accessor instead. + def define_set_accessor(identifier, locator, element, &block) + define_method "#{identifier}=".to_sym do |*values| + puts "*** *values: #{values}" + + accessor = if block_given? + instance_exec(&block) + else + reference_element(element, locator) + end + + if accessor.respond_to?(:set) + accessor.set *values + else + accessor.send_keys *values + end + end + end + # Returns the identifier and locator portions of an element definition. # # @param signature [Array] full element definition # @return [String] identifier and locator portions def parse_signature(signature) @@ -54,9 +131,10 @@ # Returns the block or proc that serves as a context for an element # definition. # # @param locator [Array] locators from element definition # @param block [Proc] a context block + # @return [Proc] the context block or nil if there is no procedure def context_from_signature(*locator, &block) if block_given? block else context = locator.shift