module FakeMechanize
# Agent acts like the original Mechanize::Agent but totally offline.
# It provides a respond_to method to predefine queries and their answers.
class Agent
# Represents a cookie jar built from WWW::Mechanize::CookieJar
attr_accessor :cookie_jar
# Create a new fake agent.
# Can be initialized with a block, see respond_to for more details.
def initialize(&block)
@cookie_jar = WWW::Mechanize::CookieJar.new
@responses = []
@errors = []
@history = []
respond_to(&block) if block_given?
end
def respond_to
reset_responses!
yield Responder.new(@responses, @errors) if block_given?
@errors << ErrorRequest.new(:status => 404, :body => "not found")
end
# Returns true if query defined by method, uri and options was made.
# False otherwise.
# * method can be one of the following: :get, :post.
# * uri is a String that represents the called url.
# * options is an optional hash to specify parameters, headers ... Only :parameters options is actually supported.
def assert_queried(method, uri, options = {})
request = Request.new(:method => method, :uri => uri, :parameters => options[:parameters])
@history.any? {|history_query| history_query == request}
end
# Get method. Called like get method from the real Mechanize gem.
# Get can be achieved by two ways :
# * options is a String representing the url to call and parameters a hash for the parameters.
# * options is a Hash with :url the url and :params the parameters.
def get(options, parameters = nil)
if options.is_a? Hash
# TODO raise a Mechanize exception
raise "no url specified" unless url = options[:url]
parameters = options[:params]
else
url = options
end
return_mechanize_response Request.new(:method => :get, :uri => url, :parameters => parameters)
end
# Post method. Called like post method from the real Mechanize gem.
# url is the url to post.
# query is a Hash of parameters.
def post(url, query = {})
return_mechanize_response Request.new(:method => :post, :uri => url, :parameters => query)
end
HttpVerbs.each do |method|
module_eval <<-EOE, __FILE__, __LINE__
def was_#{method}?(uri, options = {})
assert_queried(:#{method}, uri, options)
end
EOE
end
protected
# Add given_request to history, search if for a matching query
# and returns a response or raise an error if http status is not 200.
def return_mechanize_response(given_request)
@history << given_request
request = search_for_request(given_request)
page = WWW::Mechanize::File.new(URI.parse(given_request.uri), request.response_headers, request.body, request.status)
raise WWW::Mechanize::ResponseCodeError.new(page) if request.status != 200
page
end
# Search through available @responses if given_request matches one of the defined responses.
def search_for_request(given_request)
@responses.find {|request| request == given_request} || search_for_error_request(given_request)
end
# Search an error query in the error query list using match value for a request,
# the higher match will be the one returned (see ErrorRequest::match)
def search_for_error_request(given_request)
@errors.max_by {|request| request.match(given_request)}
end
# Delete all predefined responses
def reset_responses!
@responses.clear
end
end # Agent
end # FakeMechanize