require 'howitzer/web/capybara_context_holder' module Howitzer module Web # This module combines section dsl methods module SectionDsl include CapybaraContextHolder def self.included(base) #:nodoc: base.extend(ClassMethods) end # This module holds section dsl class methods module ClassMethods # This class is for private usage only class SectionScope attr_accessor :section_class # Instantiates an anynomous or named section and executes block code in the section scope def initialize(name, *args, &block) @args = args self.section_class = if block Class.new(Howitzer::Web::BaseSection) else "#{name}_section".classify.constantize end instance_eval(&block) if block_given? end # # Defines an element on the section # # @see Howitzer::PageDsl::ClassMethods#element def element(*args) section_class.send(:element, *args) end # Delegates a section describing to the section class def section(name, *args, &block) section_class.send(:section, name, *args, &block) end # Returns a selector for the section. # @note If anonymous section uses, then inline selector should be specified. # Otherwise arguments should be defined with `.me` dsl method in named section # @return [Array] # @raise [ArgumentError] when finder arguments were not specified def finder_args @finder_args ||= begin return @args if @args.present? section_class.default_finder_args || raise(ArgumentError, 'Missing finder arguments') end end end protected # DSL method which defines named or anonymous section within a page or a section # @note This method generates following dynamic methods: # # section_name_section - equals capybara #find(...) method # # section_name_sections - equals capybara #all(...) method # # section_name_sections.first - equals capybara #first(...) method # # has_section_name_section? - equals capybara #has_selector(...) method # # has_no_section_name_section? - equals capybara #has_no_selector(...) method # @note It is possible to use nested anonymous sections # @param name [Symbol, String] an unique section name # @param args [Array] original Capybara arguments. For details, see `Capybara::Node::Finders#all. # (In most cases should be ommited for named sections because the section selector is specified # with `#me` method. But must be specified for anonymous sections) # @param block [Proc] this block can contain nested sections and elements # @example Named section # class MenuSection < Howitzer::Web::Section # me :xpath, ".//*[@id='panel']" # end # class HomePage < Howitzer::Web::Page # section :menu # end # HomePage.on { is_expected.to have_menu_section } # @example Anonymous section # class HomePage < Howitzer::Web::Page # section :info_panel, '#panel' do # element :edit_button, '.edit' # element :title_field, '.title' # # def edit_info(title: nil) # edit_button_element.click # title_field_element.set(title) # end # end # end # HomePage.on { info_panel.edit_info(title: 'Test Title') } # @example Anonymous nested section # class HomePage < Howitzer::Web::Page # section :info_panel, '#panel' do # element :edit_button, '.edit' # # section :form, '.form' do # element :title_field, '.title' # end # end # end # HomePage.on { info_panel_section.edit_info(title: 'Test Title') } # @!visibility public def section(name, *args, &block) scope = SectionScope.new(name, *args, &block) define_section_method(scope.section_class, name, scope.finder_args) define_sections_method(scope.section_class, name, scope.finder_args) define_has_section_method(name, scope.finder_args) define_has_no_section_method(name, scope.finder_args) end private def define_section_method(klass, name, args) define_method("#{name}_section") do klass.new(self, capybara_context.find(*args)) end end def define_sections_method(klass, name, args) define_method("#{name}_sections") do capybara_context.all(*args).map { |el| klass.new(self, el) } end end def define_has_section_method(name, args) define_method("has_#{name}_section?") do capybara_context.has_selector?(*args) end end def define_has_no_section_method(name, args) define_method("has_no_#{name}_section?") do capybara_context.has_no_selector?(*args) end end end end end end require 'howitzer/web/base_section'