require "webrat/core/elements/form" require "webrat/core/locators" require "webrat/core_extensions/deprecate" module Webrat # An HTML element (link, button, field, etc.) that Webrat expected was not found on the page class NotFoundError < WebratError end class Scope include Logging include Locators def self.from_page(session, response, response_body) #:nodoc: new(session) do @response = response @response_body = response_body end end def self.from_scope(session, scope, selector) #:nodoc: new(session) do @scope = scope @selector = selector end end attr_reader :session def initialize(session, &block) #:nodoc: @selector, @dom = nil @session = session instance_eval(&block) if block_given? if @selector && scoped_dom.nil? raise Webrat::NotFoundError.new("The scope was not found on the page: #{@selector.inspect}") end end # Verifies an input field or textarea exists on the current page, and stores a value for # it which will be sent when the form is submitted. # # Examples: # fill_in "Email", :with => "user@example.com" # fill_in "user[email]", :with => "user@example.com" # # The field value is required, and must be specified in options[:with]. # field can be either the value of a name attribute (i.e. user[email]) # or the text inside a element that points at the field. def fill_in(field_locator, options = {}) field = locate_field(field_locator, TextField, TextareaField, PasswordField) field.raise_error_if_disabled field.set(options[:with]) end webrat_deprecate :fills_in, :fill_in # Verifies that a hidden field exists on the current page and sets # the value to that given by the :to option. # # Example: # set_hidden_field 'user_id', :to => 1 def set_hidden_field(field_locator, options = {}) field = locate_field(field_locator, HiddenField) field.set(options[:to]) end # Verifies that an input checkbox exists on the current page and marks it # as checked, so that the value will be submitted with the form. # # Example: # check 'Remember Me' def check(field_locator) locate_field(field_locator, CheckboxField).check end webrat_deprecate :checks, :check # Verifies that an input checkbox exists on the current page and marks it # as unchecked, so that the value will not be submitted with the form. # # Example: # uncheck 'Remember Me' def uncheck(field_locator) locate_field(field_locator, CheckboxField).uncheck end webrat_deprecate :unchecks, :uncheck # Verifies that an input radio button exists on the current page and marks it # as checked, so that the value will be submitted with the form. # # Example: # choose 'First Option' def choose(field_locator) locate_field(field_locator, RadioField).choose end webrat_deprecate :chooses, :choose # Verifies that a an option element exists on the current page with the specified # text. You can optionally restrict the search to a specific select list by # assigning options[:from] the value of the select list's name or # a label. Stores the option's value to be sent when the form is submitted. # # Examples: # select "January" # select "February", :from => "event_month" # select "February", :from => "Event Month" def select(option_text, options = {}) select_option(option_text, options[:from]).choose end webrat_deprecate :selects, :select # Verifies that a an option element exists on the current page with the specified # text. You can optionally restrict the search to a specific select list by # assigning options[:from] the value of the select list's name or # a label. Remove the option's value before the form is submitted. # # Examples: # unselect "January" # unselect "February", :from => "event_month" # unselect "February", :from => "Event Month" def unselect(option_text, options={}) select_option(option_text, options[:from]).unchoose end webrat_deprecate :unselects, :unselect DATE_TIME_SUFFIXES = { :year => '1i', :month => '2i', :day => '3i', :hour => '4i', :minute => '5i' } # Verifies that date elements (year, month, day) exist on the current page # with the specified values. You can optionally restrict the search to a specific # date's elements by assigning options[:from] the value of the date's # label. Selects all the date elements with date provided. The date provided may # be a string or a Date/Time object. # # Rail's convention is used for detecting the date elements. All elements # are assumed to have a shared prefix. You may also specify the prefix # by assigning options[:id_prefix]. # # Examples: # select_date "January 23, 2004" # select_date "April 26, 1982", :from => "Birthday" # select_date Date.parse("December 25, 2000"), :from => "Event" # select_date "April 26, 1982", :id_prefix => 'birthday' def select_date(date_to_select, options ={}) date = date_to_select.is_a?(Date) || date_to_select.is_a?(Time) ? date_to_select : Date.parse(date_to_select) id_prefix = locate_id_prefix(options) do year_field = FieldByIdLocator.new(@session, dom, /(.*?)_#{DATE_TIME_SUFFIXES[:year]}$/).locate raise NotFoundError.new("No date fields were found") unless year_field && year_field.id =~ /(.*?)_1i/ $1 end select date.year, :from => "#{id_prefix}_#{DATE_TIME_SUFFIXES[:year]}" select date.strftime('%B'), :from => "#{id_prefix}_#{DATE_TIME_SUFFIXES[:month]}" select date.day, :from => "#{id_prefix}_#{DATE_TIME_SUFFIXES[:day]}" end webrat_deprecate :selects_date, :select_date # Verifies that time elements (hour, minute) exist on the current page # with the specified values. You can optionally restrict the search to a specific # time's elements by assigning options[:from] the value of the time's # label. Selects all the time elements with date provided. The time provided may # be a string or a Time object. # # Rail's convention is used for detecting the time elements. All elements are # assumed to have a shared prefix. You may specify the prefix by assigning # options[:id_prefix]. # # Note: Just like Rails' time_select helper this assumes the form is using # 24 hour select boxes, and not 12 hours with AM/PM. # # Examples: # select_time "9:30" # select_date "3:30PM", :from => "Party Time" # select_date Time.parse("10:00PM"), :from => "Event" # select_date "10:30AM", :id_prefix => 'meeting' def select_time(time_to_select, options ={}) time = time_to_select.is_a?(Time) ? time_to_select : Time.parse(time_to_select) id_prefix = locate_id_prefix(options) do hour_field = FieldByIdLocator.new(@session, dom, /(.*?)_#{DATE_TIME_SUFFIXES[:hour]}$/).locate raise NotFoundError.new("No time fields were found") unless hour_field && hour_field.id =~ /(.*?)_4i/ $1 end select time.hour.to_s.rjust(2,'0'), :from => "#{id_prefix}_#{DATE_TIME_SUFFIXES[:hour]}" select time.min.to_s.rjust(2,'0'), :from => "#{id_prefix}_#{DATE_TIME_SUFFIXES[:minute]}" end webrat_deprecate :selects_time, :select_time # Verifies and selects all the date and time elements on the current page. # See #select_time and #select_date for more details and available options. # # Examples: # select_datetime "January 23, 2004 10:30AM" # select_datetime "April 26, 1982 7:00PM", :from => "Birthday" # select_datetime Time.parse("December 25, 2000 15:30"), :from => "Event" # select_datetime "April 26, 1982 5:50PM", :id_prefix => 'birthday' def select_datetime(time_to_select, options ={}) time = time_to_select.is_a?(Time) ? time_to_select : Time.parse(time_to_select) options[:id_prefix] ||= (options[:from] ? FieldByIdLocator.new(@session, dom, options[:from]).locate : nil) select_date time, options select_time time, options end webrat_deprecate :selects_datetime, :select_datetime # Verifies that an input file field exists on the current page and sets # its value to the given +file+, so that the file will be uploaded # along with the form. An optional content_type may be given. # # Example: # attach_file "Resume", "/path/to/the/resume.txt" # attach_file "Photo", "/path/to/the/image.png", "image/png" def attach_file(field_locator, path, content_type = nil) locate_field(field_locator, FileField).set(path, content_type) end webrat_deprecate :attaches_file, :attach_file # Issues a request for the URL pointed to by an area tag # on the current page, follows any redirects, and verifies the # final page load was successful. # # The area used is the first area whose title or id contains the # given +area_name+ (case is ignored). # # Example: # click_area 'Australia' def click_area(area_name) find_area(area_name).click end webrat_deprecate :clicks_area, :click_area # Issues a request for the URL pointed to by a link on the current page, # follows any redirects, and verifies the final page load was successful. # # click_link has very basic support for detecting Rails-generated # JavaScript onclick handlers for PUT, POST and DELETE links, as well as # CSRF authenticity tokens if they are present. # # Javascript imitation can be disabled by passing the option :javascript => false # # Passing a :method in the options hash overrides the HTTP method used # for making the link request # # It will try to find links by (in order of precedence): # innerHTML, with simple   handling # title # id # # innerHTML and title are matchable by text subtring or Regexp # id is matchable by full text equality or Regexp # # Example: # click_link "Sign up" # click_link "Sign up", :javascript => false # click_link "Sign up", :method => :put def click_link(text_or_title_or_id, options = {}) find_link(text_or_title_or_id).click(options) end webrat_deprecate :clicks_link, :click_link # Verifies that a submit button exists for the form, then submits the form, follows # any redirects, and verifies the final page was successful. # # Example: # click_button "Login" # click_button # # The URL and HTTP method for the form submission are automatically read from the # action and method attributes of the
element. def click_button(value = nil) find_button(value).click end webrat_deprecate :clicks_button, :click_button # Submit the form with the given id. # # Note that +click_button+ is usually preferrable for simulating # form submissions, as you may specify part of the button text # rather than the form id. # # Example: # submit_form 'login' def submit_form(id) FormLocator.new(@session, dom, id).locate.submit end def dom # :nodoc: return @dom if @dom if @selector @dom = scoped_dom else @dom = page_dom end return @dom end protected def page_dom #:nodoc: return @response.dom if @response.respond_to?(:dom) dom = Webrat::XML.document(@response_body) Webrat::XML.define_dom_method(@response, dom) return dom end def scoped_dom @scope.dom.css(@selector).first end def locate_field(field_locator, *field_types) #:nodoc: if field_locator.is_a?(Field) field_locator else field(field_locator, *field_types) end end def locate_id_prefix(options, &location_strategy) #:nodoc: return options[:id_prefix] if options[:id_prefix] if options[:from] if (label = LabelLocator.new(@session, dom, options[:from]).locate) label.for_id else raise NotFoundError.new("Could not find the label with text #{options[:from]}") end else yield end end def forms #:nodoc: @forms ||= Form.load_all(@session, dom) end end end