require "forwardable"
require "ostruct"
require "webrat/core/mime"
require "webrat/core/save_and_open_page"
module Webrat
# A page load or form submission returned an unsuccessful response code (500-599)
class PageLoadError < WebratError
end
def self.session_class
case Webrat.configuration.mode
when :rails
RailsSession
when :merb
MerbSession
when :selenium
SeleniumSession
when :rack
RackSession
when :sinatra
SinatraSession
when :mechanize
MechanizeSession
else
raise WebratError.new(<<-STR)
Unknown Webrat mode: #{Webrat.configuration.mode.inspect}
Please ensure you have a Webrat configuration block that specifies a mode
in your test_helper.rb, spec_helper.rb, or env.rb (for Cucumber).
For example:
Webrat.configure do |config|
config.mode = :rails
end
STR
end
end
class Session
extend Forwardable
include Logging
include SaveAndOpenPage
attr_reader :current_url
attr_reader :elements
def initialize(context = nil) #:nodoc:
@http_method = :get
@data = {}
@default_headers = {}
@custom_headers = {}
@context = context
reset
end
def current_dom #:nodoc:
current_scope.dom
end
# For backwards compatibility -- removing in 1.0
def current_page #:nodoc:
page = OpenStruct.new
page.url = @current_url
page.http_method = @http_method
page.data = @data
page
end
def doc_root #:nodoc:
nil
end
def header(key, value)
@custom_headers[key] = value
end
def http_accept(mime_type)
header('Accept', Webrat::MIME.mime_type(mime_type))
end
def basic_auth(user, pass)
encoded_login = ["#{user}:#{pass}"].pack("m*")
header('HTTP_AUTHORIZATION', "Basic #{encoded_login}")
end
def headers #:nodoc:
@default_headers.dup.merge(@custom_headers.dup)
end
def request_page(url, http_method, data) #:nodoc:
h = headers
h['HTTP_REFERER'] = @current_url if @current_url
debug_log "REQUESTING PAGE: #{http_method.to_s.upcase} #{url} with #{data.inspect} and HTTP headers #{h.inspect}"
if h.empty?
send "#{http_method}", url, data || {}
else
send "#{http_method}", url, data || {}, h
end
save_and_open_page if exception_caught? && Webrat.configuration.open_error_files?
raise PageLoadError.new("Page load was not successful (Code: #{response_code.inspect}):\n#{formatted_error}") unless success_code?
reset
@current_url = url
@http_method = http_method
@data = data
request_page(response.location, :get, data) if response.redirect?
return response
end
def success_code? #:nodoc:
(200..499).include?(response_code)
end
def exception_caught? #:nodoc:
response_body =~ /Exception caught/
end
def current_scope #:nodoc:
scopes.last || page_scope
end
# Reloads the last page requested. Note that this will resubmit forms
# and their data.
def reloads
request_page(@current_url, @http_method, @data)
end
webrat_deprecate :reload, :reloads
# Works like click_link, but only looks for the link text within a given selector
#
# Example:
# click_link_within "#user_12", "Vote"
def click_link_within(selector, link_text)
within(selector) do
click_link(link_text)
end
end
webrat_deprecate :clicks_link_within, :click_link_within
def within(selector)
scopes.push(Scope.from_scope(self, current_scope, selector))
ret = yield(current_scope)
scopes.pop
return ret
end
# Issues a GET request for a page, follows any redirects, and verifies the final page
# load was successful.
#
# Example:
# visit "/"
def visit(url = nil, http_method = :get, data = {})
request_page(url, http_method, data)
end
webrat_deprecate :visits, :visit
# Subclasses can override this to show error messages without html
def formatted_error #:nodoc:
response_body
end
def scopes #:nodoc:
@_scopes ||= []
end
def page_scope #:nodoc:
@_page_scope ||= Scope.from_page(self, response, response_body)
end
def dom
page_scope.dom
end
def xml_content_type?
false
end
def simulate
return if Webrat.configuration.mode == :selenium
yield
end
def automate
return unless Webrat.configuration.mode == :selenium
yield
end
def_delegators :current_scope, :fill_in, :fills_in
def_delegators :current_scope, :set_hidden_field
def_delegators :current_scope, :submit_form
def_delegators :current_scope, :check, :checks
def_delegators :current_scope, :uncheck, :unchecks
def_delegators :current_scope, :choose, :chooses
def_delegators :current_scope, :select, :selects
def_delegators :current_scope, :select_datetime, :selects_datetime
def_delegators :current_scope, :select_date, :selects_date
def_delegators :current_scope, :select_time, :selects_time
def_delegators :current_scope, :attach_file, :attaches_file
def_delegators :current_scope, :click_area, :clicks_area
def_delegators :current_scope, :click_link, :clicks_link
def_delegators :current_scope, :click_button, :clicks_button
def_delegators :current_scope, :field_labeled
def_delegators :current_scope, :field_by_xpath
def_delegators :current_scope, :field_with_id
def_delegators :current_scope, :select_option
private
def reset
@elements = {}
@_scopes = nil
@_page_scope = nil
end
end
end