In progress OOP refactoring
This commit is contained in:
parent
9adf2193d2
commit
857b46fe3e
2
Rakefile
2
Rakefile
|
@ -9,8 +9,6 @@ Hoe.new('webrat', Webrat::VERSION) do |p|
|
||||||
p.developer "Bryan Helmkamp", "bryan@brynary.com"
|
p.developer "Bryan Helmkamp", "bryan@brynary.com"
|
||||||
p.developer "Seth Fitzsimmons", "seth@mojodna.net"
|
p.developer "Seth Fitzsimmons", "seth@mojodna.net"
|
||||||
|
|
||||||
# require "rubygems"; require "ruby-debug"; Debugger.start; debugger
|
|
||||||
|
|
||||||
p.description = p.paragraphs_of('README.txt', 4..6).join("\n\n")
|
p.description = p.paragraphs_of('README.txt', 4..6).join("\n\n")
|
||||||
p.url = p.paragraphs_of('README.txt', 1).first.split("\n").first.strip
|
p.url = p.paragraphs_of('README.txt', 1).first.split("\n").first.strip
|
||||||
p.changes = p.paragraphs_of('History.txt', 0..3).join("\n\n")
|
p.changes = p.paragraphs_of('History.txt', 0..3).join("\n\n")
|
||||||
|
|
|
@ -1,6 +1,41 @@
|
||||||
require File.join(File.dirname(__FILE__), "webrat", "rails_extensions")
|
Dir[File.join(File.dirname(__FILE__), "webrat", "*.rb")].each do |file|
|
||||||
require File.join(File.dirname(__FILE__), "webrat", "session")
|
require File.expand_path(file)
|
||||||
|
end
|
||||||
|
|
||||||
module Webrat
|
module Webrat
|
||||||
VERSION = '0.2.1'
|
VERSION = '0.2.1'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module ActionController
|
||||||
|
module Integration
|
||||||
|
class Session
|
||||||
|
|
||||||
|
unless instance_methods.include?("put_via_redirect")
|
||||||
|
include Webrat::RedirectActions
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_page
|
||||||
|
@current_page ||= Webrat::Page.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Issues a GET request for a page, follows any redirects, and verifies the final page
|
||||||
|
# load was successful.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# visits "/"
|
||||||
|
def visits(*args)
|
||||||
|
@current_page = Webrat::Page.new(self, *args)
|
||||||
|
end
|
||||||
|
|
||||||
|
[:fills_in, :clicks_button, :selects, :chooses, :checks, :unchecks].each do |method_name|
|
||||||
|
define_method(method_name) do |*args|
|
||||||
|
current_page.send(method_name, *args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
require File.expand_path(File.join(File.dirname(__FILE__), "field_finder"))
|
||||||
|
|
||||||
|
module Webrat
|
||||||
|
class ButtonFinder < FieldFinder
|
||||||
|
def initialize(root, name = nil)
|
||||||
|
@root = root
|
||||||
|
@id_or_name_or_label = name
|
||||||
|
@element_types = %w[input]
|
||||||
|
@input_types = %w[submit image]
|
||||||
|
|
||||||
|
@candidates = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def find
|
||||||
|
if @id_or_name_or_label.nil?
|
||||||
|
candidates.first
|
||||||
|
else
|
||||||
|
find_by_id(@id_or_name_or_label) ||
|
||||||
|
find_by_name ||
|
||||||
|
find_by_value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def find_by_value
|
||||||
|
candidates.detect { |el| el.attributes["value"] == @id_or_name_or_label }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,82 @@
|
||||||
|
module Webrat
|
||||||
|
class FieldFinder
|
||||||
|
def initialize(root, id_or_name_or_label, element_types, input_types = nil)
|
||||||
|
@root = root
|
||||||
|
@id_or_name_or_label = id_or_name_or_label.to_s
|
||||||
|
@element_types = Array(element_types)
|
||||||
|
@input_types = Array(input_types)
|
||||||
|
|
||||||
|
@candidates = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def find
|
||||||
|
find_by_id(@id_or_name_or_label) ||
|
||||||
|
find_by_name ||
|
||||||
|
find_by_label
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
# def find_select_list_by_name_or_label(name_or_label) # :nodoc:
|
||||||
|
# select = find_element_by_name("select", name_or_label)
|
||||||
|
# return select if select
|
||||||
|
#
|
||||||
|
# label = find_form_label(name_or_label)
|
||||||
|
# label ? field_for_label(label) : nil
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def find_option_by_value(option_value, select=nil) # :nodoc:
|
||||||
|
# options = select.nil? ? (dom / "option") : (select / "option")
|
||||||
|
# options.detect { |el| el.innerHTML == option_value }
|
||||||
|
# end
|
||||||
|
|
||||||
|
def field_for_label(label)
|
||||||
|
inputs_within_label = canidates_within(label)
|
||||||
|
|
||||||
|
if inputs_within_label.any?
|
||||||
|
inputs_within_label.first
|
||||||
|
else
|
||||||
|
find_by_id(label.attributes["for"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_by_id(id)
|
||||||
|
candidates.detect { |el| el.attributes["id"] == id }
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_by_name
|
||||||
|
candidates.detect { |el| el.attributes["name"] == @id_or_name_or_label }
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_by_label
|
||||||
|
label = canididate_labels.sort_by { |el| el.innerText.strip.size }.first
|
||||||
|
label ? field_for_label(label) : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def canididate_labels
|
||||||
|
(@root / "label").select { |el| el.innerText =~ /^\W*#{Regexp.escape(@id_or_name_or_label)}\b/i }
|
||||||
|
end
|
||||||
|
|
||||||
|
def candidates
|
||||||
|
return @candidates if @candidates
|
||||||
|
@candidates = canidates_within(@root)
|
||||||
|
end
|
||||||
|
|
||||||
|
def canidates_within(root)
|
||||||
|
candidates = []
|
||||||
|
|
||||||
|
@element_types.each do |element_type|
|
||||||
|
if "input" == element_type && @input_types.any?
|
||||||
|
@input_types.each do |input_type|
|
||||||
|
candidates += (root / "input[@type=#{input_type}]")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
candidates += (root / element_type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
candidates
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,129 @@
|
||||||
|
module Webrat
|
||||||
|
class Form
|
||||||
|
def initialize(page, form)
|
||||||
|
@page = page
|
||||||
|
@form = form
|
||||||
|
@params = default_params
|
||||||
|
end
|
||||||
|
|
||||||
|
def set(input_element, value)
|
||||||
|
new_param = param_parser.parse_query_parameters("#{input_element.attributes["name"]}=#{value}")
|
||||||
|
merge(new_param)
|
||||||
|
end
|
||||||
|
|
||||||
|
def unset(input_element)
|
||||||
|
@params.delete(input_element.attributes['name'])
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_field(*args)
|
||||||
|
FieldFinder.new(@form, *args).find
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_button(name = nil)
|
||||||
|
ButtonFinder.new(@form, name).find
|
||||||
|
end
|
||||||
|
|
||||||
|
def submit
|
||||||
|
Page.new(@page.session, form_action, form_method, @params)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
# def find_field_by_name(name) # :nodoc:
|
||||||
|
# find_element_by_name("input", name) || find_element_by_name("textarea", name)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def add_default_params_for(form) # :nodoc:
|
||||||
|
# add_default_params_from_inputs_for(form)
|
||||||
|
# add_default_params_from_checkboxes_for(form)
|
||||||
|
# add_default_params_from_radio_buttons_for(form)
|
||||||
|
# add_default_params_from_textareas_for(form)
|
||||||
|
# add_default_params_from_selects_for(form)
|
||||||
|
# end
|
||||||
|
|
||||||
|
def default_params
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_default_params_from_radio_buttons_for(form) # :nodoc:
|
||||||
|
(form / "input[@type='radio][@checked='checked']").each do |input|
|
||||||
|
add_form_data(input, input.attributes["value"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_default_params_from_checkboxes_for(form) # :nodoc:
|
||||||
|
(form / "input[@type='checkbox][@checked='checked']").each do |input|
|
||||||
|
add_form_data(input, input.attributes["value"] || "on")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_default_params_from_selects_for(form) # :nodoc:
|
||||||
|
(form / "select").each do |select|
|
||||||
|
selected_options = select / "option[@selected='selected']"
|
||||||
|
selected_options = select / "option:first" if selected_options.empty?
|
||||||
|
selected_options.each do |option|
|
||||||
|
add_form_data(select, option.attributes["value"] || option.innerHTML)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_default_params_from_inputs_for(form) # :nodoc:
|
||||||
|
(form / "input").each do |input|
|
||||||
|
next unless %w[text password hidden].include?(input.attributes["type"])
|
||||||
|
add_form_data(input, input.attributes["value"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_default_params_from_textareas_for(form) # :nodoc:
|
||||||
|
(form / "textarea").each do |input|
|
||||||
|
add_form_data(input, input.inner_html)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def form_method
|
||||||
|
@form.attributes["method"].blank? ? :get : @form.attributes["method"].downcase
|
||||||
|
end
|
||||||
|
|
||||||
|
def form_action
|
||||||
|
@form.attributes["action"].blank? ? current_url : @form.attributes["action"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def param_parser
|
||||||
|
if defined?(CGIMethods)
|
||||||
|
CGIMethods
|
||||||
|
else
|
||||||
|
ActionController::AbstractRequest
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def merge(new_param)
|
||||||
|
new_param.each do |key, value|
|
||||||
|
case @params[key]
|
||||||
|
when Hash, HashWithIndifferentAccess
|
||||||
|
merge_hash_values(@params[key], value)
|
||||||
|
when Array
|
||||||
|
@params[key] += value
|
||||||
|
else
|
||||||
|
@params[key] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def merge_hash_values(a, b) # :nodoc:
|
||||||
|
a.keys.each do |k|
|
||||||
|
if b.has_key?(k)
|
||||||
|
case [a[k], b[k]].map(&:class)
|
||||||
|
when [Hash, Hash]
|
||||||
|
a[k] = merge_hash_values(a[k], b[k])
|
||||||
|
b.delete(k)
|
||||||
|
when [Array, Array]
|
||||||
|
a[k] += b[k]
|
||||||
|
b.delete(k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
a.merge!(b)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,51 @@
|
||||||
|
module Webrat
|
||||||
|
class Link
|
||||||
|
|
||||||
|
def initialize(link_element)
|
||||||
|
end
|
||||||
|
|
||||||
|
def click
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def authenticity_token
|
||||||
|
return unless onclick && onclick.include?("s.setAttribute('name', 'authenticity_token');") &&
|
||||||
|
onclick =~ /s\.setAttribute\('value', '([a-f0-9]{40})'\);/
|
||||||
|
$LAST_MATCH_INFO.captures.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def onclick
|
||||||
|
end
|
||||||
|
|
||||||
|
def http_method
|
||||||
|
end
|
||||||
|
|
||||||
|
def http_method_from_js(onclick)
|
||||||
|
if !onclick.blank? && onclick.include?("f.submit()")
|
||||||
|
http_method_from_js_form(onclick)
|
||||||
|
else
|
||||||
|
:get
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def http_method_from_js_form(onclick)
|
||||||
|
if onclick.include?("m.setAttribute('name', '_method')")
|
||||||
|
http_method_from_fake_method_param(onclick)
|
||||||
|
else
|
||||||
|
:post
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def http_method_from_fake_method_param(onclick)
|
||||||
|
if onclick.include?("m.setAttribute('value', 'delete')")
|
||||||
|
:delete
|
||||||
|
elsif onclick.include?("m.setAttribute('value', 'put')")
|
||||||
|
:put
|
||||||
|
else
|
||||||
|
raise "No HTTP method for _method param in #{onclick.inspect}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,32 @@
|
||||||
|
# def clicks_link_with_method(link_text, http_method) # :nodoc:
|
||||||
|
# link = all_links.detect { |el| el.innerHTML =~ /#{link_text}/i }
|
||||||
|
# flunk("No link with text #{link_text.inspect} was found") if link.nil?
|
||||||
|
# request_page(http_method, link.attributes["href"])
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def find_shortest_matching_link(links, link_text)
|
||||||
|
# candidates = links.select { |el| el.innerHTML =~ /#{link_text}/i }
|
||||||
|
# candidates.sort_by { |el| el.innerText.strip.size }.first
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def clicks_one_link_of(links, link_text)
|
||||||
|
# link = find_shortest_matching_link(links, link_text)
|
||||||
|
#
|
||||||
|
# flunk("No link with text #{link_text.inspect} was found") if link.nil?
|
||||||
|
#
|
||||||
|
# onclick = link.attributes["onclick"]
|
||||||
|
# href = link.attributes["href"]
|
||||||
|
#
|
||||||
|
# http_method = http_method_from_js(onclick)
|
||||||
|
# authenticity_token = authenticity_token_value(onclick)
|
||||||
|
#
|
||||||
|
# request_page(http_method, href, authenticity_token.blank? ? {} : {"authenticity_token" => authenticity_token}) unless href =~ /^#/ && http_method == :get
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def all_links # :nodoc:
|
||||||
|
# (dom / "a[@href]")
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def links_within(selector) # :nodoc:
|
||||||
|
# (dom / selector / "a[@href]")
|
||||||
|
# end
|
|
@ -0,0 +1,18 @@
|
||||||
|
module Webrat
|
||||||
|
module Logging
|
||||||
|
|
||||||
|
def debug_log(message) # :nodoc:
|
||||||
|
return unless logger
|
||||||
|
logger.debug
|
||||||
|
end
|
||||||
|
|
||||||
|
def logger # :nodoc:
|
||||||
|
if defined? RAILS_DEFAULT_LOGGER
|
||||||
|
RAILS_DEFAULT_LOGGER
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,280 @@
|
||||||
|
require "hpricot"
|
||||||
|
require "English"
|
||||||
|
|
||||||
|
module Webrat
|
||||||
|
class Page
|
||||||
|
include Logging
|
||||||
|
|
||||||
|
attr_reader :session
|
||||||
|
|
||||||
|
def initialize(session, url = nil, method = :get, data = {})
|
||||||
|
@session = session
|
||||||
|
@url = url
|
||||||
|
@method = method
|
||||||
|
@data = data
|
||||||
|
|
||||||
|
reset_dom
|
||||||
|
reloads if @url
|
||||||
|
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:
|
||||||
|
# fills_in "Email", :with => "user@example.com"
|
||||||
|
# fills_in "user[email]", :with => "user@example.com"
|
||||||
|
#
|
||||||
|
# The field value is required, and must be specified in <tt>options[:with]</tt>.
|
||||||
|
# <tt>field</tt> can be either the value of a name attribute (i.e. <tt>user[email]</tt>)
|
||||||
|
# or the text inside a <tt><label></tt> element that points at the <tt><input></tt> field.
|
||||||
|
def fills_in(field, options = {})
|
||||||
|
value = options[:with]
|
||||||
|
flunk("No value was provided") if value.nil?
|
||||||
|
|
||||||
|
form_with_input = nil
|
||||||
|
found_input = nil
|
||||||
|
|
||||||
|
forms.each do |form|
|
||||||
|
found_input = form.find_field(field, %w[input textarea], %w[text password])
|
||||||
|
|
||||||
|
if found_input
|
||||||
|
form_with_input = form
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
flunk("Could not find input #{field.inspect}") if found_input.nil?
|
||||||
|
|
||||||
|
form_with_input.set(found_input, value)
|
||||||
|
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:
|
||||||
|
# checks 'Remember Me'
|
||||||
|
def checks(field)
|
||||||
|
checkbox = find_field_by_name_or_label(field)
|
||||||
|
flunk("Could not find checkbox #{field.inspect}") if checkbox.nil?
|
||||||
|
flunk("Input #{checkbox.inspect} is not a checkbox") unless checkbox.attributes['type'] == 'checkbox'
|
||||||
|
add_form_data(checkbox, checkbox.attributes["value"] || "on")
|
||||||
|
end
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
# unchecks 'Remember Me'
|
||||||
|
def unchecks(field)
|
||||||
|
checkbox = find_field_by_name_or_label(field)
|
||||||
|
flunk("Could not find checkbox #{field.inspect}") if checkbox.nil?
|
||||||
|
flunk("Input #{checkbox.inspect} is not a checkbox") unless checkbox.attributes['type'] == 'checkbox'
|
||||||
|
remove_form_data(checkbox)
|
||||||
|
|
||||||
|
(form_for_node(checkbox) / "input").each do |input|
|
||||||
|
next unless input.attributes["type"] == "hidden" && input.attributes["name"] == checkbox.attributes["name"]
|
||||||
|
add_form_data(input, input.attributes["value"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
# chooses 'First Option'
|
||||||
|
def chooses(field)
|
||||||
|
radio = find_field_by_name_or_label(field)
|
||||||
|
flunk("Could not find radio button #{field.inspect}") if radio.nil?
|
||||||
|
flunk("Input #{radio.inspect} is not a radio button") unless radio.attributes['type'] == 'radio'
|
||||||
|
add_form_data(radio, radio.attributes["value"] || "on")
|
||||||
|
end
|
||||||
|
|
||||||
|
# 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 <tt>options[:from]</tt> 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:
|
||||||
|
# selects "January"
|
||||||
|
# selects "February", :from => "event_month"
|
||||||
|
# selects "February", :from => "Event Month"
|
||||||
|
def selects(option_text, options = {})
|
||||||
|
if options[:from]
|
||||||
|
select = find_select_list_by_name_or_label(options[:from])
|
||||||
|
flunk("Could not find select list #{options[:from].inspect}") if select.nil?
|
||||||
|
option_node = find_option_by_value(option_text, select)
|
||||||
|
flunk("Could not find option #{option_text.inspect}") if option_node.nil?
|
||||||
|
else
|
||||||
|
option_node = find_option_by_value(option_text)
|
||||||
|
flunk("Could not find option #{option_text.inspect}") if option_node.nil?
|
||||||
|
select = option_node.parent
|
||||||
|
end
|
||||||
|
add_form_data(select, option_node.attributes["value"] || option_node.innerHTML)
|
||||||
|
# TODO - Set current form
|
||||||
|
end
|
||||||
|
|
||||||
|
# Saves the currently loaded page out to RAILS_ROOT/tmp/ and opens it in the default
|
||||||
|
# web browser if on OS X. Useful for debugging.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# save_and_open
|
||||||
|
def save_and_open
|
||||||
|
return unless File.exist?(RAILS_ROOT + "/tmp")
|
||||||
|
|
||||||
|
filename = "webrat-#{Time.now.to_i}.html"
|
||||||
|
File.open(RAILS_ROOT + "/tmp/#{filename}", "w") do |f|
|
||||||
|
f.write response.body
|
||||||
|
end
|
||||||
|
`open tmp/#{filename}`
|
||||||
|
end
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# clicks_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.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# clicks_link "Sign up"
|
||||||
|
def clicks_link(link_text)
|
||||||
|
clicks_one_link_of(all_links, link_text)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Works like clicks_link, but only looks for the link text within a given selector
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# clicks_link_within "#user_12", "Vote"
|
||||||
|
def clicks_link_within(selector, link_text)
|
||||||
|
clicks_one_link_of(links_within(selector), link_text)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Works like clicks_link, but forces a GET request
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# clicks_get_link "Log out"
|
||||||
|
def clicks_get_link(link_text)
|
||||||
|
clicks_link_with_method(link_text, :get)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Works like clicks_link, but issues a DELETE request instead of a GET
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# clicks_delete_link "Log out"
|
||||||
|
def clicks_delete_link(link_text)
|
||||||
|
clicks_link_with_method(link_text, :delete)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Works like clicks_link, but issues a POST request instead of a GET
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# clicks_post_link "Vote"
|
||||||
|
def clicks_post_link(link_text)
|
||||||
|
clicks_link_with_method(link_text, :post)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Works like clicks_link, but issues a PUT request instead of a GET
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# clicks_put_link "Update profile"
|
||||||
|
def clicks_put_link(link_text)
|
||||||
|
clicks_link_with_method(link_text, :put)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Verifies that a submit button exists for the form, then submits the form, follows
|
||||||
|
# any redirects, and verifies the final page was successful.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# clicks_button "Login"
|
||||||
|
# clicks_button
|
||||||
|
#
|
||||||
|
# The URL and HTTP method for the form submission are automatically read from the
|
||||||
|
# <tt>action</tt> and <tt>method</tt> attributes of the <tt><form></tt> element.
|
||||||
|
def clicks_button(value = nil)
|
||||||
|
form_with_button = nil
|
||||||
|
found_button = nil
|
||||||
|
|
||||||
|
forms.each do |form|
|
||||||
|
found_button = form.find_button(value)
|
||||||
|
|
||||||
|
if found_button
|
||||||
|
form_with_button = form
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
flunk("Could not find button #{value.inspect}") if found_button.nil?
|
||||||
|
form_with_button.set(found_button, found_button.attributes["value"]) unless found_button.attributes["name"].blank?
|
||||||
|
form_with_button.submit
|
||||||
|
end
|
||||||
|
|
||||||
|
# Reloads the last page requested. Note that this will resubmit forms
|
||||||
|
# and their data.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# reloads
|
||||||
|
def reloads
|
||||||
|
request_page(@url, @method, @data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def submits_form(form_id = nil) # :nodoc:
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def request_page(url, method, data)
|
||||||
|
debug_log "REQUESTING PAGE: #{method.to_s.upcase} #{url} with #{data.inspect}"
|
||||||
|
|
||||||
|
session.send "#{method}_via_redirect", url, data || {}
|
||||||
|
|
||||||
|
if response.body =~ /Exception caught/ || response.body.blank?
|
||||||
|
save_and_open
|
||||||
|
end
|
||||||
|
|
||||||
|
session.assert_response :success
|
||||||
|
reset_dom
|
||||||
|
end
|
||||||
|
|
||||||
|
def response
|
||||||
|
session.response
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_dom
|
||||||
|
@dom = nil
|
||||||
|
@forms = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_button(value = nil) # :nodoc:
|
||||||
|
return nil unless value
|
||||||
|
|
||||||
|
(dom / "input[@type='submit']").detect do |el|
|
||||||
|
el.attributes["value"] =~ /^\W*#{value}\b/i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def form_for_node(node) # :nodoc:
|
||||||
|
return node if node.name == "form"
|
||||||
|
node = node.parent until node.name == "form"
|
||||||
|
node
|
||||||
|
end
|
||||||
|
|
||||||
|
def forms
|
||||||
|
return @forms if @forms
|
||||||
|
|
||||||
|
@forms = (dom / "form").map do |form_element|
|
||||||
|
Form.new(self, form_element)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def dom # :nodoc:
|
||||||
|
return @dom if defined?(@dom) && @dom
|
||||||
|
flunk("You must visit a path before working with the page.") unless @session.response
|
||||||
|
@dom = Hpricot(@session.response.body)
|
||||||
|
end
|
||||||
|
|
||||||
|
def flunk(message)
|
||||||
|
raise message
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,7 @@
|
||||||
|
# For Rails before http://dev.rubyonrails.org/ticket/10497 was committed
|
||||||
module Webrat
|
module Webrat
|
||||||
module RedirectActions
|
module RedirectActions
|
||||||
|
|
||||||
def put_via_redirect(path, parameters = {}, headers = {})
|
def put_via_redirect(path, parameters = {}, headers = {})
|
||||||
put path, parameters, headers
|
put path, parameters, headers
|
||||||
follow_redirect! while redirect?
|
follow_redirect! while redirect?
|
||||||
|
@ -11,15 +13,6 @@ module Webrat
|
||||||
follow_redirect! while redirect?
|
follow_redirect! while redirect?
|
||||||
status
|
status
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Waiting for http://dev.rubyonrails.org/ticket/10497 to be committed.
|
|
||||||
|
|
||||||
module ActionController
|
|
||||||
module Integration
|
|
||||||
class Session
|
|
||||||
include Webrat::RedirectActions unless instance_methods.include?("put_via_redirect")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,526 +0,0 @@
|
||||||
require "hpricot"
|
|
||||||
require "English"
|
|
||||||
|
|
||||||
module Webrat
|
|
||||||
module Session
|
|
||||||
# Issues a GET request for a page, follows any redirects, and verifies the final page
|
|
||||||
# load was successful.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# visits "/"
|
|
||||||
def visits(path)
|
|
||||||
request_page(:get, path)
|
|
||||||
end
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# clicks_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.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# clicks_link "Sign up"
|
|
||||||
def clicks_link(link_text)
|
|
||||||
clicks_one_link_of(all_links, link_text)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Works like clicks_link, but only looks for the link text within a given selector
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# clicks_link_within "#user_12", "Vote"
|
|
||||||
def clicks_link_within(selector, link_text)
|
|
||||||
clicks_one_link_of(links_within(selector), link_text)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Works like clicks_link, but forces a GET request
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# clicks_get_link "Log out"
|
|
||||||
def clicks_get_link(link_text)
|
|
||||||
clicks_link_with_method(link_text, :get)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Works like clicks_link, but issues a DELETE request instead of a GET
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# clicks_delete_link "Log out"
|
|
||||||
def clicks_delete_link(link_text)
|
|
||||||
clicks_link_with_method(link_text, :delete)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Works like clicks_link, but issues a POST request instead of a GET
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# clicks_post_link "Vote"
|
|
||||||
def clicks_post_link(link_text)
|
|
||||||
clicks_link_with_method(link_text, :post)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Works like clicks_link, but issues a PUT request instead of a GET
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# clicks_put_link "Update profile"
|
|
||||||
def clicks_put_link(link_text)
|
|
||||||
clicks_link_with_method(link_text, :put)
|
|
||||||
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:
|
|
||||||
# fills_in "Email", :with => "user@example.com"
|
|
||||||
# fills_in "user[email]", :with => "user@example.com"
|
|
||||||
#
|
|
||||||
# The field value is required, and must be specified in <tt>options[:with]</tt>.
|
|
||||||
# <tt>field</tt> can be either the value of a name attribute (i.e. <tt>user[email]</tt>)
|
|
||||||
# or the text inside a <tt><label></tt> element that points at the <tt><input></tt> field.
|
|
||||||
def fills_in(field, options = {})
|
|
||||||
value = options[:with]
|
|
||||||
return flunk("No value was provided") if value.nil?
|
|
||||||
input = find_field_by_name_or_label(field)
|
|
||||||
return flunk("Could not find input #{field.inspect}") if input.nil?
|
|
||||||
add_form_data(input, value)
|
|
||||||
# TODO - Set current form
|
|
||||||
end
|
|
||||||
|
|
||||||
# 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 <tt>options[:from]</tt> 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:
|
|
||||||
# selects "January"
|
|
||||||
# selects "February", :from => "event_month"
|
|
||||||
# selects "February", :from => "Event Month"
|
|
||||||
def selects(option_text, options = {})
|
|
||||||
if options[:from]
|
|
||||||
select = find_select_list_by_name_or_label(options[:from])
|
|
||||||
return flunk("Could not find select list #{options[:from].inspect}") if select.nil?
|
|
||||||
option_node = find_option_by_value(option_text, select)
|
|
||||||
return flunk("Could not find option #{option_text.inspect}") if option_node.nil?
|
|
||||||
else
|
|
||||||
option_node = find_option_by_value(option_text)
|
|
||||||
return flunk("Could not find option #{option_text.inspect}") if option_node.nil?
|
|
||||||
select = option_node.parent
|
|
||||||
end
|
|
||||||
add_form_data(select, option_node.attributes["value"] || option_node.innerHTML)
|
|
||||||
# TODO - Set current form
|
|
||||||
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:
|
|
||||||
# checks 'Remember Me'
|
|
||||||
def checks(field)
|
|
||||||
checkbox = find_field_by_name_or_label(field)
|
|
||||||
return flunk("Could not find checkbox #{field.inspect}") if checkbox.nil?
|
|
||||||
return flunk("Input #{checkbox.inspect} is not a checkbox") unless checkbox.attributes['type'] == 'checkbox'
|
|
||||||
add_form_data(checkbox, checkbox.attributes["value"] || "on")
|
|
||||||
end
|
|
||||||
|
|
||||||
# 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:
|
|
||||||
# unchecks 'Remember Me'
|
|
||||||
def unchecks(field)
|
|
||||||
checkbox = find_field_by_name_or_label(field)
|
|
||||||
return flunk("Could not find checkbox #{field.inspect}") if checkbox.nil?
|
|
||||||
return flunk("Input #{checkbox.inspect} is not a checkbox") unless checkbox.attributes['type'] == 'checkbox'
|
|
||||||
remove_form_data(checkbox)
|
|
||||||
|
|
||||||
(form_for_node(checkbox) / "input").each do |input|
|
|
||||||
next unless input.attributes["type"] == "hidden" && input.attributes["name"] == checkbox.attributes["name"]
|
|
||||||
add_form_data(input, input.attributes["value"])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# 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:
|
|
||||||
# chooses 'First Option'
|
|
||||||
def chooses(field)
|
|
||||||
radio = find_field_by_name_or_label(field)
|
|
||||||
return flunk("Could not find radio button #{field.inspect}") if radio.nil?
|
|
||||||
return flunk("Input #{radio.inspect} is not a radio button") unless radio.attributes['type'] == 'radio'
|
|
||||||
add_form_data(radio, radio.attributes["value"] || "on")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Verifies that a submit button exists for the form, then submits the form, follows
|
|
||||||
# any redirects, and verifies the final page was successful.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# clicks_button "Login"
|
|
||||||
# clicks_button
|
|
||||||
#
|
|
||||||
# The URL and HTTP method for the form submission are automatically read from the
|
|
||||||
# <tt>action</tt> and <tt>method</tt> attributes of the <tt><form></tt> element.
|
|
||||||
def clicks_button(value = nil)
|
|
||||||
button = value ? find_button(value) : submit_buttons.first
|
|
||||||
return flunk("Could not find button #{value.inspect}") if button.nil?
|
|
||||||
add_form_data(button, button.attributes["value"]) unless button.attributes["name"].blank?
|
|
||||||
submit_form(form_for_node(button))
|
|
||||||
end
|
|
||||||
|
|
||||||
def submits_form(form_id = nil) # :nodoc:
|
|
||||||
end
|
|
||||||
|
|
||||||
# Saves the currently loaded page out to RAILS_ROOT/tmp/ and opens it in the default
|
|
||||||
# web browser if on OS X. Useful for debugging.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# save_and_open_page
|
|
||||||
def save_and_open_page
|
|
||||||
return unless File.exist?(RAILS_ROOT + "/tmp")
|
|
||||||
|
|
||||||
filename = "webrat-#{Time.now.to_i}.html"
|
|
||||||
File.open(RAILS_ROOT + "/tmp/#{filename}", "w") do |f|
|
|
||||||
f.write response.body
|
|
||||||
end
|
|
||||||
`open tmp/#{filename}`
|
|
||||||
end
|
|
||||||
|
|
||||||
# Reloads the last page requested. Note that this will resubmit forms
|
|
||||||
# and their data.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# reloads
|
|
||||||
def reloads
|
|
||||||
request_page(*@last_request_args) if defined?(@last_request_args) && @last_request_args
|
|
||||||
end
|
|
||||||
|
|
||||||
protected # Methods you could call, but probably shouldn't
|
|
||||||
|
|
||||||
def authenticity_token_value(onclick)
|
|
||||||
return unless onclick && onclick.include?("s.setAttribute('name', 'authenticity_token');") &&
|
|
||||||
onclick =~ /s\.setAttribute\('value', '([a-f0-9]{40})'\);/
|
|
||||||
$LAST_MATCH_INFO.captures.first
|
|
||||||
end
|
|
||||||
|
|
||||||
def http_method_from_js(onclick)
|
|
||||||
if !onclick.blank? && onclick.include?("f.submit()")
|
|
||||||
http_method_from_js_form(onclick)
|
|
||||||
else
|
|
||||||
:get
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def http_method_from_js_form(onclick)
|
|
||||||
if onclick.include?("m.setAttribute('name', '_method')")
|
|
||||||
http_method_from_fake_method_param(onclick)
|
|
||||||
else
|
|
||||||
:post
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def http_method_from_fake_method_param(onclick)
|
|
||||||
if onclick.include?("m.setAttribute('value', 'delete')")
|
|
||||||
:delete
|
|
||||||
elsif onclick.include?("m.setAttribute('value', 'put')")
|
|
||||||
:put
|
|
||||||
else
|
|
||||||
raise "No HTTP method for _method param in #{onclick.inspect}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def clicks_link_with_method(link_text, http_method) # :nodoc:
|
|
||||||
link = all_links.detect { |el| el.innerHTML =~ /#{link_text}/i }
|
|
||||||
return flunk("No link with text #{link_text.inspect} was found") if link.nil?
|
|
||||||
request_page(http_method, link.attributes["href"])
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_shortest_matching_link(links, link_text)
|
|
||||||
candidates = links.select { |el| el.innerHTML =~ /#{link_text}/i }
|
|
||||||
candidates.sort_by { |el| el.innerText.strip.size }.first
|
|
||||||
end
|
|
||||||
|
|
||||||
def clicks_one_link_of(links, link_text)
|
|
||||||
link = find_shortest_matching_link(links, link_text)
|
|
||||||
|
|
||||||
return flunk("No link with text #{link_text.inspect} was found") if link.nil?
|
|
||||||
|
|
||||||
onclick = link.attributes["onclick"]
|
|
||||||
href = link.attributes["href"]
|
|
||||||
|
|
||||||
http_method = http_method_from_js(onclick)
|
|
||||||
authenticity_token = authenticity_token_value(onclick)
|
|
||||||
|
|
||||||
request_page(http_method, href, authenticity_token.blank? ? {} : {"authenticity_token" => authenticity_token}) unless href =~ /^#/ && http_method == :get
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_field_by_name_or_label(name_or_label) # :nodoc:
|
|
||||||
input = find_field_by_name(name_or_label)
|
|
||||||
return input if input
|
|
||||||
|
|
||||||
label = find_form_label(name_or_label)
|
|
||||||
label ? input_for_label(label) : nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_select_list_by_name_or_label(name_or_label) # :nodoc:
|
|
||||||
select = find_select_list_by_name(name_or_label)
|
|
||||||
return select if select
|
|
||||||
|
|
||||||
label = find_form_label(name_or_label)
|
|
||||||
label ? select_list_for_label(label) : nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_option_by_value(option_value, select=nil) # :nodoc:
|
|
||||||
options = select.nil? ? option_nodes : (select / "option")
|
|
||||||
options.detect { |el| el.innerHTML == option_value }
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_button(value = nil) # :nodoc:
|
|
||||||
return nil unless value
|
|
||||||
submit_buttons.detect { |el| el.attributes["value"] =~ /^\W*#{value}\b/i }
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_form_data(input_element, value) # :nodoc:
|
|
||||||
form = form_for_node(input_element)
|
|
||||||
data = param_parser.parse_query_parameters("#{input_element.attributes["name"]}=#{value}")
|
|
||||||
merge_form_data(form_number(form), data)
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove_form_data(input_element) # :nodoc:
|
|
||||||
form = form_for_node(input_element)
|
|
||||||
form_number = form_number(form)
|
|
||||||
form_data[form_number] ||= {}
|
|
||||||
form_data[form_number].delete(input_element.attributes['name'])
|
|
||||||
end
|
|
||||||
|
|
||||||
def submit_form(form) # :nodoc:
|
|
||||||
form_number = form_number(form)
|
|
||||||
request_page(form_method(form), form_action(form), form_data[form_number])
|
|
||||||
end
|
|
||||||
|
|
||||||
def merge_form_data(form_number, data) # :nodoc:
|
|
||||||
form_data[form_number] ||= {}
|
|
||||||
|
|
||||||
data.each do |key, value|
|
|
||||||
case form_data[form_number][key]
|
|
||||||
when Hash, HashWithIndifferentAccess; then merge(form_data[form_number][key], value)
|
|
||||||
when Array; then form_data[form_number][key] += value
|
|
||||||
else form_data[form_number][key] = value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def merge(a, b) # :nodoc:
|
|
||||||
a.keys.each do |k|
|
|
||||||
if b.has_key?(k)
|
|
||||||
case [a[k], b[k]].map(&:class)
|
|
||||||
when [Hash, Hash]
|
|
||||||
a[k] = merge(a[k], b[k])
|
|
||||||
b.delete(k)
|
|
||||||
when [Array, Array]
|
|
||||||
a[k] += b[k]
|
|
||||||
b.delete(k)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
a.merge!(b)
|
|
||||||
end
|
|
||||||
|
|
||||||
def request_page(method, url, data = {}) # :nodoc:
|
|
||||||
debug_log "REQUESTING PAGE: #{method.to_s.upcase} #{url} with #{data.inspect}"
|
|
||||||
@current_url = url
|
|
||||||
@last_request_args = [method, url, data]
|
|
||||||
self.send "#{method}_via_redirect", @current_url, data || {}
|
|
||||||
|
|
||||||
if response.body =~ /Exception caught/ || response.body.blank?
|
|
||||||
save_and_open_page
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_response :success
|
|
||||||
reset_dom
|
|
||||||
end
|
|
||||||
|
|
||||||
def input_for_label(label) # :nodoc:
|
|
||||||
if input = (label / "input").first
|
|
||||||
input # nested inputs within labels
|
|
||||||
else
|
|
||||||
# input somewhere else, referenced by id
|
|
||||||
input_id = label.attributes["for"]
|
|
||||||
(dom / "##{input_id}").first
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def select_list_for_label(label) # :nodoc:
|
|
||||||
if select_list = (label / "select").first
|
|
||||||
select_list # nested inputs within labels
|
|
||||||
else
|
|
||||||
# input somewhere else, referenced by id
|
|
||||||
select_list_id = label.attributes["for"]
|
|
||||||
(dom / "##{select_list_id}").first
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def param_parser # :nodoc:
|
|
||||||
if defined?(CGIMethods)
|
|
||||||
CGIMethods
|
|
||||||
else
|
|
||||||
ActionController::AbstractRequest
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def submit_buttons # :nodoc:
|
|
||||||
input_fields.select { |el| el.attributes["type"] == "submit" }
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_field_by_name(name) # :nodoc:
|
|
||||||
find_input_by_name(name) || find_textarea_by_name(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_input_by_name(name) # :nodoc:
|
|
||||||
input_fields.detect { |el| el.attributes["name"] == name }
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_select_list_by_name(name) # :nodoc:
|
|
||||||
select_lists.detect { |el| el.attributes["name"] == name }
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_textarea_by_name(name) # :nodoc:
|
|
||||||
textarea_fields.detect{ |el| el.attributes['name'] == name }
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_form_label(text) # :nodoc:
|
|
||||||
candidates = form_labels.select { |el| el.innerText =~ /^\W*#{text}\b/i }
|
|
||||||
candidates.sort_by { |el| el.innerText.strip.size }.first
|
|
||||||
end
|
|
||||||
|
|
||||||
def form_action(form) # :nodoc:
|
|
||||||
form.attributes["action"].blank? ? current_url : form.attributes["action"]
|
|
||||||
end
|
|
||||||
|
|
||||||
def form_method(form) # :nodoc:
|
|
||||||
form.attributes["method"].blank? ? :get : form.attributes["method"].downcase
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_default_params # :nodoc:
|
|
||||||
(dom / "form").each do |form|
|
|
||||||
add_default_params_for(form)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_default_params_for(form) # :nodoc:
|
|
||||||
add_default_params_from_inputs_for(form)
|
|
||||||
add_default_params_from_checkboxes_for(form)
|
|
||||||
add_default_params_from_radio_buttons_for(form)
|
|
||||||
add_default_params_from_textareas_for(form)
|
|
||||||
add_default_params_from_selects_for(form)
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_default_params_from_inputs_for(form) # :nodoc:
|
|
||||||
(form / "input").each do |input|
|
|
||||||
next unless %w[text password hidden].include?(input.attributes["type"])
|
|
||||||
add_form_data(input, input.attributes["value"])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_default_params_from_checkboxes_for(form) # :nodoc:
|
|
||||||
(form / "input[@type='checkbox][@checked='checked']").each do |input|
|
|
||||||
add_form_data(input, input.attributes["value"] || "on")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_default_params_from_radio_buttons_for(form) # :nodoc:
|
|
||||||
(form / "input[@type='radio][@checked='checked']").each do |input|
|
|
||||||
add_form_data(input, input.attributes["value"])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_default_params_from_textareas_for(form) # :nodoc:
|
|
||||||
(form / "textarea").each do |input|
|
|
||||||
add_form_data(input, input.inner_html)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_default_params_from_selects_for(form) # :nodoc:
|
|
||||||
(form / "select").each do |select|
|
|
||||||
selected_options = select / "option[@selected='selected']"
|
|
||||||
selected_options = select / "option:first" if selected_options.empty?
|
|
||||||
selected_options.each do |option|
|
|
||||||
add_form_data(select, option.attributes["value"] || option.innerHTML)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def form_for_node(node) # :nodoc:
|
|
||||||
return node if node.name == "form"
|
|
||||||
node = node.parent until node.name == "form"
|
|
||||||
node
|
|
||||||
end
|
|
||||||
|
|
||||||
def reset_dom # :nodoc:
|
|
||||||
@form_data = []
|
|
||||||
@dom = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def form_data # :nodoc:
|
|
||||||
@form_data ||= []
|
|
||||||
end
|
|
||||||
|
|
||||||
def all_links # :nodoc:
|
|
||||||
(dom / "a[@href]")
|
|
||||||
end
|
|
||||||
|
|
||||||
def links_within(selector) # :nodoc:
|
|
||||||
(dom / selector / "a[@href]")
|
|
||||||
end
|
|
||||||
|
|
||||||
def form_number(form) # :nodoc:
|
|
||||||
(dom / "form").index(form)
|
|
||||||
end
|
|
||||||
|
|
||||||
def input_fields # :nodoc:
|
|
||||||
(dom / "input")
|
|
||||||
end
|
|
||||||
|
|
||||||
def textarea_fields # :nodoc
|
|
||||||
(dom / "textarea")
|
|
||||||
end
|
|
||||||
|
|
||||||
def form_labels # :nodoc:
|
|
||||||
(dom / "label")
|
|
||||||
end
|
|
||||||
|
|
||||||
def select_lists # :nodoc:
|
|
||||||
(dom / "select")
|
|
||||||
end
|
|
||||||
|
|
||||||
def option_nodes # :nodoc:
|
|
||||||
(dom / "option")
|
|
||||||
end
|
|
||||||
|
|
||||||
def dom # :nodoc:
|
|
||||||
return @dom if defined?(@dom) && @dom
|
|
||||||
raise "You must visit a path before working with the page." unless response
|
|
||||||
@dom = Hpricot(response.body)
|
|
||||||
add_default_params
|
|
||||||
@dom
|
|
||||||
end
|
|
||||||
|
|
||||||
def debug_log(message) # :nodoc:
|
|
||||||
return unless logger
|
|
||||||
logger.debug
|
|
||||||
end
|
|
||||||
|
|
||||||
def logger # :nodoc:
|
|
||||||
if defined? RAILS_DEFAULT_LOGGER
|
|
||||||
RAILS_DEFAULT_LOGGER
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module ActionController
|
|
||||||
module Integration
|
|
||||||
class Session
|
|
||||||
include Webrat::Session
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -20,120 +20,122 @@ class FillsInTest < Test::Unit::TestCase
|
||||||
@session.fills_in "User Text", :with => "filling text area"
|
@session.fills_in "User Text", :with => "filling text area"
|
||||||
@session.clicks_button
|
@session.clicks_button
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_fail_if_input_not_found
|
|
||||||
@response.stubs(:body).returns(<<-EOS)
|
|
||||||
<form method="get" action="/login">
|
|
||||||
</form>
|
|
||||||
EOS
|
|
||||||
@session.expects(:flunk)
|
|
||||||
@session.fills_in "Email", :with => "foo@example.com"
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_should_allow_overriding_default_form_values
|
def test_should_fail_if_input_not_found
|
||||||
@response.stubs(:body).returns(<<-EOS)
|
@response.stubs(:body).returns(<<-EOS)
|
||||||
<form method="post" action="/login">
|
<form method="get" action="/login">
|
||||||
<label for="user_email">Email</label>
|
</form>
|
||||||
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
EOS
|
||||||
<input type="submit" />
|
|
||||||
</form>
|
assert_raises RuntimeError do
|
||||||
EOS
|
@session.fills_in "Email", :with => "foo@example.com"
|
||||||
@session.expects(:post_via_redirect).with("/login", "user" => {"email" => "foo@example.com"})
|
end
|
||||||
@session.fills_in "user[email]", :with => "foo@example.com"
|
end
|
||||||
@session.clicks_button
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_should_choose_the_closest_label_match
|
|
||||||
@response.stubs(:body).returns(<<-EOS)
|
|
||||||
<form method="post" action="/login">
|
|
||||||
<label for="user_mail1">Some other mail</label>
|
|
||||||
<input id="user_mail1" name="user[mail1]" type="text" />
|
|
||||||
<label for="user_mail2">Some mail</label>
|
|
||||||
<input id="user_mail2" name="user[mail2]" type="text" />
|
|
||||||
<input type="submit" />
|
|
||||||
</form>
|
|
||||||
EOS
|
|
||||||
|
|
||||||
@session.expects(:post_via_redirect).with("/login", "user" => {"mail1" => "", "mail2" => "value"})
|
def test_should_allow_overriding_default_form_values
|
||||||
@session.fills_in "Some", :with => "value"
|
@response.stubs(:body).returns(<<-EOS)
|
||||||
@session.clicks_button
|
<form method="post" action="/login">
|
||||||
end
|
<label for="user_email">Email</label>
|
||||||
|
|
||||||
def test_should_choose_the_first_label_match_if_closest_is_a_tie
|
|
||||||
@response.stubs(:body).returns(<<-EOS)
|
|
||||||
<form method="post" action="/login">
|
|
||||||
<label for="user_mail1">Some mail one</label>
|
|
||||||
<input id="user_mail1" name="user[mail1]" type="text" />
|
|
||||||
<label for="user_mail2">Some mail two</label>
|
|
||||||
<input id="user_mail2" name="user[mail2]" type="text" />
|
|
||||||
<input type="submit" />
|
|
||||||
</form>
|
|
||||||
EOS
|
|
||||||
|
|
||||||
@session.expects(:post_via_redirect).with("/login", "user" => {"mail1" => "value", "mail2" => ""})
|
|
||||||
@session.fills_in "Some mail", :with => "value"
|
|
||||||
@session.clicks_button
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_should_anchor_label_matches_to_start_of_label
|
|
||||||
@response.stubs(:body).returns(<<-EOS)
|
|
||||||
<form method="post" action="/login">
|
|
||||||
<label for="user_email">Some mail</label>
|
|
||||||
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
|
||||||
</form>
|
|
||||||
EOS
|
|
||||||
|
|
||||||
assert_raises(RuntimeError) { @session.fills_in "mail", :with => "value" }
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_should_anchor_label_matches_to_word_boundaries
|
|
||||||
@response.stubs(:body).returns(<<-EOS)
|
|
||||||
<form method="post" action="/login">
|
|
||||||
<label for="user_email">Emailtastic</label>
|
|
||||||
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
|
||||||
</form>
|
|
||||||
EOS
|
|
||||||
|
|
||||||
assert_raises(RuntimeError) { @session.fills_in "Email", :with => "value" }
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_should_work_with_inputs_nested_in_labels
|
|
||||||
@response.stubs(:body).returns(<<-EOS)
|
|
||||||
<form method="post" action="/login">
|
|
||||||
<label>
|
|
||||||
Email
|
|
||||||
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
||||||
</label>
|
<input type="submit" />
|
||||||
<input type="submit" />
|
</form>
|
||||||
</form>
|
EOS
|
||||||
EOS
|
@session.expects(:post_via_redirect).with("/login", "user" => {"email" => "foo@example.com"})
|
||||||
@session.expects(:post_via_redirect).with("/login", "user" => {"email" => "foo@example.com"})
|
@session.fills_in "user[email]", :with => "foo@example.com"
|
||||||
@session.fills_in "Email", :with => "foo@example.com"
|
@session.clicks_button
|
||||||
@session.clicks_button
|
end
|
||||||
|
|
||||||
|
def test_should_choose_the_closest_label_match
|
||||||
|
@response.stubs(:body).returns(<<-EOS)
|
||||||
|
<form method="post" action="/login">
|
||||||
|
<label for="user_mail1">Some other mail</label>
|
||||||
|
<input id="user_mail1" name="user[mail1]" type="text" />
|
||||||
|
<label for="user_mail2">Some mail</label>
|
||||||
|
<input id="user_mail2" name="user[mail2]" type="text" />
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
EOS
|
||||||
|
|
||||||
|
@session.expects(:post_via_redirect).with("/login", "user" => {"mail1" => "", "mail2" => "value"})
|
||||||
|
@session.fills_in "Some", :with => "value"
|
||||||
|
@session.clicks_button
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_should_choose_the_first_label_match_if_closest_is_a_tie
|
||||||
|
@response.stubs(:body).returns(<<-EOS)
|
||||||
|
<form method="post" action="/login">
|
||||||
|
<label for="user_mail1">Some mail one</label>
|
||||||
|
<input id="user_mail1" name="user[mail1]" type="text" />
|
||||||
|
<label for="user_mail2">Some mail two</label>
|
||||||
|
<input id="user_mail2" name="user[mail2]" type="text" />
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
EOS
|
||||||
|
|
||||||
|
@session.expects(:post_via_redirect).with("/login", "user" => {"mail1" => "value", "mail2" => ""})
|
||||||
|
@session.fills_in "Some mail", :with => "value"
|
||||||
|
@session.clicks_button
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_should_anchor_label_matches_to_start_of_label
|
||||||
|
@response.stubs(:body).returns(<<-EOS)
|
||||||
|
<form method="post" action="/login">
|
||||||
|
<label for="user_email">Some mail</label>
|
||||||
|
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
||||||
|
</form>
|
||||||
|
EOS
|
||||||
|
|
||||||
|
assert_raises(RuntimeError) { @session.fills_in "mail", :with => "value" }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_should_anchor_label_matches_to_word_boundaries
|
||||||
|
@response.stubs(:body).returns(<<-EOS)
|
||||||
|
<form method="post" action="/login">
|
||||||
|
<label for="user_email">Emailtastic</label>
|
||||||
|
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
||||||
|
</form>
|
||||||
|
EOS
|
||||||
|
|
||||||
|
assert_raises(RuntimeError) { @session.fills_in "Email", :with => "value" }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_should_work_with_inputs_nested_in_labels
|
||||||
|
@response.stubs(:body).returns(<<-EOS)
|
||||||
|
<form method="post" action="/login">
|
||||||
|
<label>
|
||||||
|
Email
|
||||||
|
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
||||||
|
</label>
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
EOS
|
||||||
|
@session.expects(:post_via_redirect).with("/login", "user" => {"email" => "foo@example.com"})
|
||||||
|
@session.fills_in "Email", :with => "foo@example.com"
|
||||||
|
@session.clicks_button
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_should_work_with_full_input_names
|
||||||
|
@response.stubs(:body).returns(<<-EOS)
|
||||||
|
<form method="post" action="/login">
|
||||||
|
<input id="user_email" name="user[email]" type="text" />
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
EOS
|
||||||
|
@session.expects(:post_via_redirect).with("/login", "user" => {"email" => "foo@example.com"})
|
||||||
|
@session.fills_in "user[email]", :with => "foo@example.com"
|
||||||
|
@session.clicks_button
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_should_work_with_symbols
|
||||||
|
@response.stubs(:body).returns(<<-EOS)
|
||||||
|
<form method="post" action="/login">
|
||||||
|
<label for="user_email">Email</label>
|
||||||
|
<input id="user_email" name="user[email]" type="text" />
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
EOS
|
||||||
|
@session.expects(:post_via_redirect).with("/login", "user" => {"email" => "foo@example.com"})
|
||||||
|
@session.fills_in :email, :with => "foo@example.com"
|
||||||
|
@session.clicks_button
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_work_with_full_input_names
|
|
||||||
@response.stubs(:body).returns(<<-EOS)
|
|
||||||
<form method="post" action="/login">
|
|
||||||
<input id="user_email" name="user[email]" type="text" />
|
|
||||||
<input type="submit" />
|
|
||||||
</form>
|
|
||||||
EOS
|
|
||||||
@session.expects(:post_via_redirect).with("/login", "user" => {"email" => "foo@example.com"})
|
|
||||||
@session.fills_in "user[email]", :with => "foo@example.com"
|
|
||||||
@session.clicks_button
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_should_work_with_symbols
|
|
||||||
@response.stubs(:body).returns(<<-EOS)
|
|
||||||
<form method="post" action="/login">
|
|
||||||
<label for="user_email">Email</label>
|
|
||||||
<input id="user_email" name="user[email]" type="text" />
|
|
||||||
<input type="submit" />
|
|
||||||
</form>
|
|
||||||
EOS
|
|
||||||
@session.expects(:post_via_redirect).with("/login", "user" => {"email" => "foo@example.com"})
|
|
||||||
@session.fills_in :email, :with => "foo@example.com"
|
|
||||||
@session.clicks_button
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ require "test/unit"
|
||||||
begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end
|
begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end
|
||||||
require "mocha"
|
require "mocha"
|
||||||
|
|
||||||
|
|
||||||
require "active_support"
|
require "active_support"
|
||||||
|
|
||||||
silence_warnings do
|
silence_warnings do
|
||||||
|
|
Loading…
Reference in New Issue