require 'kookaburra/ui_driver/mixins/has_browser' require 'kookaburra/ui_driver/mixins/has_strategies' require 'kookaburra/ui_driver/mixins/has_subcomponents' module Kookaburra class UIDriver class UIComponent include Kookaburra::Assertion include HasBrowser include HasStrategies extend HasSubcomponents ##### Class macros ##### def self.component_locator(locator) define_method(:component_locator) { locator } end def self.component_path(path) case path when Symbol alias_method :component_path, path else define_method(:component_path) { path } end end def self.path_id_regex(regex) define_method(:path_id_regex) { regex } end ##### Instance methods ##### # Returns the CSS locator used to locate the component in the DOM def component_locator raise "You must define component_locator in subclasses of UIComponent!" end def visible! raise "#{self.class} not currently visible!" unless visible? end def visible? v= component_visible? no_500_error! unless v v end # Default implementation navigates directly to this UIComponent's # `#component_path`. If `opts[:query_params]` is set to a Hash, the # request will be made with the resulting querystring on the URL. def show(opts = {}) unless respond_to?(:component_path) raise "You must either set component_path or redefine the #show method in UIComponent subclasses!" end return if visible? path = component_path path << ( '?' + opts[:query_params].map{|kv| "%s=%s" % kv}.join('&') ) if opts[:query_params] visit path end def refresh visit component_path end def show!(opts = {}) show opts visible! end def at_path? (Array(component_path) + Array(alternate_paths)).include?(browser.current_path) end def component_visible? return false if respond_to?(:component_path) && !at_path? browser.has_css?(component_locator) end def alternate_paths [] end protected # Methods provided by `browser` that will be scoped to this UIComponent. # # These methods are defined on UIComponent and will be delegated to # `browser` after being wrapped with `#in_component` calls. SCOPED_BROWSER_METHODS = :all, :attach_file, :check, :choose, :click_button, :click_link, :click_link_or_button, :click_on, :field_labeled, :fill_in, :find, :find_button, :find_by_id, :find_field, :find_link, :first, :has_button?, :has_checked_field?, :has_content?, :has_css?, :has_field?, :has_link?, :has_no_button?, :has_no_checked_field?, :has_no_content?, :has_no_css?, :has_no_field?, :has_no_link?, :has_no_select?, :has_no_selector?, :has_no_table?, :has_no_text?, :has_no_unchecked_field?, :has_no_xpath?, :has_select?, :has_selector?, :has_table?, :has_text?, :has_unchecked_field?, :has_xpath?, :select, :text, :uncheck, :unselect SCOPED_BROWSER_METHODS.each do |method| define_method(method) do |args| in_component { browser.send(method, *args) } end end def id_from_path browser.current_path =~ path_id_regex $1.present? ? $1.to_i : nil end def in_component(&blk) browser.within(component_locator, &blk) end # Returns the number of elements found by `#all` for the specified criteria def count(*args) all(*args).size end end end end