Import from subversion

This commit is contained in:
Bryan Helmkamp 2008-03-02 15:14:52 -05:00
commit a86f8ca56f
17 changed files with 1387 additions and 0 deletions

18
CHANGELOG Normal file
View File

@ -0,0 +1,18 @@
== SVN
* Allow specifying the input name/label when doing a select (Patch from David Chelimsky)
* Raise a specific exception if the developer tries to manipulate form elements before loading a page (Patch from James Deville)
* Add basic support for Rails-generated JavaScript link tags
* Ensure Rails-style checkboxes work properly (checkboxes followed by a hidden input with the same name)
* Add support for alternate POST, PUT and DELETE link clicking (Patch from Kyle Hargraves)
* Add support for checkboxes (Patches from Kyle Hargraves and Jarkko Laine)
* Improve matching for labels in potentially ambiguous cases
* Add support for textarea fields (Patch from Sacha Schlegel)
* Fix Edge Rails (a.k.a. 2.0 RC) compatibility (Patch from David Chelimsky)
* Support param hashes nested more than one level (Patch from David Chelimsky)
== 0.1.0 / 2007-11-28
* 1 major enhancement
* Birthday!

19
MIT-LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2007 Bryan Helmkamp, Seth Fitzsimmons
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

78
README Normal file
View File

@ -0,0 +1,78 @@
= Webrat - Ruby Acceptance Testing for Web applications
by Bryan Helmkamp <bryan@brynary.com> and Seth Fitzsimmons <seth@mojodna.net>.
Initial development sponsored by EastMedia (http://www.eastmedia.com).
== DESCRIPTION:
Webrat lets you quickly write robust and thorough acceptance tests for a Ruby
web application. By leveraging the DOM, it can run tests similarly to an
in-browser testing solution without the associated performance hit (and
browser dependency). The result is tests that are less fragile and more
effective at verifying that the app will respond properly to users.
When comparing Webrat with an in-browser testing solution like Watir or
Selenium, the primary consideration should be how much JavaScript the
application uses. In-browser testing is currently the only way to test JS, and
that may make it a requirement for your project. If JavaScript is not central
to your application, Webrat is a simpler, effective solution that will let you
run your tests much faster and more frequently. (Benchmarks forthcoming.)
== SYNOPSIS:
def test_sign_up
visits "/"
clicks_link "Sign up"
fills_in "Email", :with => "good@example.com"
select "Free account"
clicks_button "Register"
...
end
Behind the scenes, this will perform the following work:
1. Verify that loading the home page is successful
2. Verify that a "Sign up" link exists on the home page
3. Verify that loading the URL pointed to by the "Sign up" link leads to a
successful page
4. Verify that there is an "Email" input field on the Sign Up page
5. Verify that there is an select field on the Sign Up page with an option for
"Free account"
6. Verify that there is a "Register" submit button on the page
7. Verify that submitting the Sign Up form with the values "good@example.com"
and "Free account" leads to a successful page
Take special note of the things _not_ specified in that test, that might cause
tests to break unnecessarily as your application evolves:
* The input field IDs or names (e.g. "user_email" or "user[email]"), which
could change if you rename a model
* The ID of the form element (Webrat can do a good job of guessing, even if
there are multiple forms on the page.)
* The URLs of links followed
* The URL the form submission should be sent to, which could change if you
adjust your routes or controllers
* The HTTP method for the login request
A test written with Webrat can handle these changes smoothly.
== REQUIREMENTS:
* Rails >= 1.2.6
* Hpricot >= 0.6
* Rails integration tests in Test::Unit _or_
* RSpec stories (using an RSpec version >= revision 2997)
== INSTALL:
$ ruby script/plugin install http://svn.eastmedia.net/public/plugins/webrat/
== HISTORY:
See CHANGELOG in this directory.
== LICENSE:
Copyright (c) 2007 Bryan Helmkamp, Seth Fitzsimmons.
See MIT-LICENSE in this directory.

26
Rakefile Normal file
View File

@ -0,0 +1,26 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
desc 'Default: run unit tests.'
task :default => :test
desc 'Test the webrat plugin.'
Rake::TestTask.new(:test) do |t|
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Generate RDoc documentation for the Webrat plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'Webrat'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end
desc "Upload rdoc to brynary.com"
task :publish_rdoc => :rdoc do
sh "scp -r rdoc/ brynary.com:/apps/uploads/webrat"
end

5
TODO Normal file
View File

@ -0,0 +1,5 @@
Option button support
Full support for multiple forms on a page
Track the current form based on the location of the last manipulated input, use this as a default for clicks_button
Make current_url work with redirections
Support for a hash mapping page names to page URLs

3
init.rb Normal file
View File

@ -0,0 +1,3 @@
if RAILS_ENV == "test"
require File.join(File.dirname(__FILE__), "lib", "webrat")
end

1
install.rb Normal file
View File

@ -0,0 +1 @@
puts IO.read(File.join(File.dirname(__FILE__), 'README'))

2
lib/webrat.rb Normal file
View File

@ -0,0 +1,2 @@
require File.join(File.dirname(__FILE__), "webrat", "rails_extensions")
require File.join(File.dirname(__FILE__), "webrat", "session")

View File

@ -0,0 +1,22 @@
module ActionController
module Integration
class Session
# Waiting for http://dev.rubyonrails.org/ticket/10497 to be committed.
def put_via_redirect(path, parameters = {}, headers = {})
put path, parameters, headers
follow_redirect! while redirect?
status
end
# Waiting for http://dev.rubyonrails.org/ticket/10497 to be committed.
def delete_via_redirect(path, parameters = {}, headers = {})
delete path, parameters, headers
follow_redirect! while redirect?
status
end
end
end
end

438
lib/webrat/session.rb Normal file
View File

@ -0,0 +1,438 @@
require "hpricot"
require "English"
module ActionController
module Integration
class 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)
link = links.detect { |el| el.innerHTML =~ /#{link_text}/i }
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})
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 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
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 = 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_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"] == value }
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|
if form_data[form_number][key].is_a?(Hash)
merge(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) and Hash === a[k] and Hash === b[k]
a[k] = merge(a[k], b[k])
b.delete(k)
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
self.send "#{method}_via_redirect", @current_url, data || {}
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_textateas_for(form)
end
def add_default_params_from_inputs_for(form) # :nodoc:
(form / "input").each do |input|
next if input.attributes["value"].blank? || !%w[text 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").each do |input|
next if input.attributes["type"] != "checkbox"
if input.attributes["checked"] == "checked"
add_form_data(input, input.attributes["value"] || "on")
end
end
end
def add_default_params_from_textateas_for(form) # :nodoc:
(form / "textarea").each do |input|
add_form_data(input, input.inner_html)
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 links # :nodoc:
(dom / "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 @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
end

121
test/checks_test.rb Normal file
View File

@ -0,0 +1,121 @@
require File.dirname(__FILE__) + "/helper"
class ChecksTest < Test::Unit::TestCase
def setup
@session = ActionController::Integration::Session.new
@session.stubs(:assert_response)
@session.stubs(:get_via_redirect)
@session.stubs(:response).returns(@response=mock)
end
def test_should_fail_if_no_checkbox_found
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
</form>
EOS
@session.expects(:flunk)
@session.checks "remember_me"
end
def test_should_fail_if_input_is_not_a_checkbox
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<input type="text" name="remember_me" />
</form>
EOS
@session.expects(:flunk)
@session.checks "remember_me"
end
def test_should_check_rails_style_checkboxes
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<input id="user_tos" name="user[tos]" type="checkbox" value="1" />
<input name="user[tos]" type="hidden" value="0" />
<label for="user_tos">TOS</label>
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect).with("/login", "user" => {"tos" => "1"})
@session.checks "TOS"
@session.clicks_button
end
def test_should_result_in_the_value_on_being_posted_if_not_specified
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<input type="checkbox" name="remember_me" />
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", "remember_me" => "on")
@session.checks "remember_me"
@session.clicks_button
end
def test_should_result_in_a_custom_value_being_posted
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<input type="checkbox" name="remember_me" value="yes" />
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", "remember_me" => "yes")
@session.checks "remember_me"
@session.clicks_button
end
end
class UnchecksTest < Test::Unit::TestCase
def setup
@session = ActionController::Integration::Session.new
@session.stubs(:assert_response)
@session.stubs(:get_via_redirect)
@session.stubs(:response).returns(@response=mock)
end
def test_should_fail_if_no_checkbox_found
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
</form>
EOS
@session.expects(:flunk)
@session.unchecks "remember_me"
end
def test_should_fail_if_input_is_not_a_checkbox
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<input type="text" name="remember_me" />
</form>
EOS
@session.expects(:flunk)
@session.unchecks "remember_me"
end
def test_should_uncheck_rails_style_checkboxes
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<input id="user_tos" name="user[tos]" type="checkbox" value="1" checked="checked" />
<input name="user[tos]" type="hidden" value="0" />
<label for="user_tos">TOS</label>
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect).with("/login", "user" => {"tos" => "0"})
@session.unchecks "TOS"
@session.clicks_button
end
def test_should_result_in_value_not_being_posted
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<input type="checkbox" name="remember_me" value="yes" checked="checked" />
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", {})
@session.unchecks "remember_me"
@session.clicks_button
end
end

218
test/clicks_button_test.rb Normal file
View File

@ -0,0 +1,218 @@
require File.dirname(__FILE__) + "/helper"
class ClicksButtonTest < Test::Unit::TestCase
def setup
@session = ActionController::Integration::Session.new
@session.stubs(:assert_response)
@session.stubs(:get_via_redirect)
@session.stubs(:response).returns(@response=mock)
end
def test_should_fail_if_no_buttons
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login"></form>
EOS
@session.expects(:flunk)
@session.clicks_button
end
def test_should_fail_if_input_is_not_a_submit_button
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<input type="reset" />
</form>
EOS
@session.expects(:flunk)
@session.clicks_button
end
def test_should_default_to_get_method
@response.stubs(:body).returns(<<-EOS)
<form action="/login">
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect)
@session.clicks_button
end
def test_should_assert_valid_response
@response.stubs(:body).returns(<<-EOS)
<form action="/login">
<input type="submit" />
</form>
EOS
@session.expects(:assert_response).with(:success)
@session.clicks_button
end
def test_should_default_to_current_url
@response.stubs(:body).returns(<<-EOS)
<form method="get">
<input type="submit" />
</form>
EOS
@session.expects(:current_url).returns("/current")
@session.expects(:get_via_redirect).with("/current", {})
@session.clicks_button
end
def test_should_submit_the_first_form_by_default
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/form1">
<input type="submit" />
</form>
<form method="get" action="/form2">
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect).with("/form1", {})
@session.clicks_button
end
def test_should_submit_the_form_with_the_specified_button
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/form1">
<input type="submit" />
</form>
<form method="get" action="/form2">
<input type="submit" value="Form2" />
</form>
EOS
@session.expects(:get_via_redirect).with("/form2", {})
@session.clicks_button "Form2"
end
def test_should_use_action_from_form
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect).with("/login", {})
@session.clicks_button
end
def test_should_use_method_from_form
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect)
@session.clicks_button
end
def test_should_send_button_as_param_if_it_has_a_name
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<input type="submit" name="cancel" value="Cancel" />
<input type="submit" name="login" value="Login" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", "login" => "Login")
@session.clicks_button("Login")
end
def test_should_not_send_button_as_param_if_it_has_no_name
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<input type="submit" name="cancel" value="Cancel" />
<input type="submit" value="Login" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", {})
@session.clicks_button("Login")
end
def test_should_send_default_hidden_field_values
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<input id="user_email" name="user[email]" value="test@example.com" type="hidden" />
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect).with("/login", "user" => {"email" => "test@example.com"})
@session.clicks_button
end
def test_should_send_default_text_field_values
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect).with("/login", "user" => {"email" => "test@example.com"})
@session.clicks_button
end
def test_should_send_default_checked_fields
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<input id="user_tos" name="user[tos]" value="1" type="checkbox" checked="checked" />
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect).with("/login", "user" => {"tos" => "1"})
@session.clicks_button
end
def test_should_send_correct_data_for_rails_style_unchecked_fields
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<input id="user_tos" name="user[tos]" type="checkbox" value="1" />
<input name="user[tos]" type="hidden" value="0" /> TOS
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect).with("/login", "user" => {"tos" => "0"})
@session.clicks_button
end
def test_should_send_correct_data_for_rails_style_checked_fields
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<input id="user_tos" name="user[tos]" type="checkbox" value="1" checked="checked" />
<input name="user[tos]" type="hidden" value="0" /> TOS
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect).with("/login", "user" => {"tos" => "1"})
@session.clicks_button
end
def test_should_not_send_default_unchecked_fields
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<input id="user_tos" name="user[tos]" value="1" type="checkbox" />
<input type="submit" />
</form>
EOS
@session.expects(:get_via_redirect).with("/login", {})
@session.clicks_button
end
def test_should_send_default_textarea_values
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/posts">
<textarea name="post[body]">Post body here!</textarea>
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect).with("/posts", "post" => {"body" => "Post body here!"})
@session.clicks_button
end
def test_should_handle_nested_properties
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<input type="text" id="contestant_scores_12" name="contestant[scores][1]" value="2"/>
<input type="text" id="contestant_scores_13" name="contestant[scores][3]" value="4"/>
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", "contestant" => {"scores" => {'1' => '2', '3' => '4'}})
@session.clicks_button
end
end

162
test/clicks_link_test.rb Normal file
View File

@ -0,0 +1,162 @@
require File.dirname(__FILE__) + "/helper"
class ClicksLinkTest < Test::Unit::TestCase
def setup
@session = ActionController::Integration::Session.new
@session.stubs(:assert_response)
@session.stubs(:get_via_redirect)
@session.stubs(:response).returns(@response=mock)
end
def test_should_use_get_by_default
@response.stubs(:body).returns(<<-EOS)
<a href="/page">Link text</a>
EOS
@session.expects(:get_via_redirect).with("/page", {})
@session.clicks_link "Link text"
end
def test_should_click_get_links
@response.stubs(:body).returns(<<-EOS)
<a href="/page">Link text</a>
EOS
@session.expects(:get_via_redirect).with("/page", {})
@session.clicks_get_link "Link text"
end
def test_should_click_delete_links
@response.stubs(:body).returns(<<-EOS)
<a href="/page">Link text</a>
EOS
@session.expects(:delete_via_redirect).with("/page", {})
@session.clicks_delete_link "Link text"
end
def test_should_click_post_links
@response.stubs(:body).returns(<<-EOS)
<a href="/page">Link text</a>
EOS
@session.expects(:post_via_redirect).with("/page", {})
@session.clicks_post_link "Link text"
end
def test_should_click_put_links
@response.stubs(:body).returns(<<-EOS)
<a href="/page">Link text</a>
EOS
@session.expects(:put_via_redirect).with("/page", {})
@session.clicks_put_link "Link text"
end
def test_should_click_rails_javascript_links_with_authenticity_tokens
@response.stubs(:body).returns(<<-EOS)
<a href="/posts" onclick="var f = document.createElement('form');
f.style.display = 'none';
this.parentNode.appendChild(f);
f.method = 'POST';
f.action = this.href;
var s = document.createElement('input');
s.setAttribute('type', 'hidden');
s.setAttribute('name', 'authenticity_token');
s.setAttribute('value', 'aa79cb354597a60a3786e7e291ed4f74d77d3a62');
f.appendChild(s);
f.submit();
return false;">Posts</a>
EOS
@session.expects(:post_via_redirect).with("/posts", "authenticity_token" => "aa79cb354597a60a3786e7e291ed4f74d77d3a62")
@session.clicks_link "Posts"
end
def test_should_click_rails_javascript_delete_links
@response.stubs(:body).returns(<<-EOS)
<a href="/posts/1" onclick="var f = document.createElement('form');
f.style.display = 'none';
this.parentNode.appendChild(f);
f.method = 'POST';
f.action = this.href;
var m = document.createElement('input');
m.setAttribute('type', 'hidden');
m.setAttribute('name', '_method');
m.setAttribute('value', 'delete');
f.appendChild(m);
f.submit();
return false;">Delete</a>
EOS
@session.expects(:delete_via_redirect).with("/posts/1", {})
@session.clicks_link "Delete"
end
def test_should_click_rails_javascript_post_links
@response.stubs(:body).returns(<<-EOS)
<a href="/posts" onclick="var f = document.createElement('form');
f.style.display = 'none';
this.parentNode.appendChild(f);
f.method = 'POST';
f.action = this.href;
f.submit();
return false;">Posts</a>
EOS
@session.expects(:post_via_redirect).with("/posts", {})
@session.clicks_link "Posts"
end
def test_should_click_rails_javascript_put_links
@response.stubs(:body).returns(<<-EOS)
<a href="/posts" onclick="var f = document.createElement('form');
f.style.display = 'none';
this.parentNode.appendChild(f);
f.method = 'POST';
f.action = this.href;
var m = document.createElement('input');
m.setAttribute('type', 'hidden');
m.setAttribute('name', '_method');
m.setAttribute('value', 'put');
f.appendChild(m);
f.submit();
return false;">Put</a></h2>
EOS
@session.expects(:put_via_redirect).with("/posts", {})
@session.clicks_link "Put"
end
def test_should_assert_valid_response
@response.stubs(:body).returns(<<-EOS)
<a href="/page">Link text</a>
EOS
@session.expects(:assert_response).with(:success)
@session.clicks_link "Link text"
end
def test_should_not_be_case_sensitive
@response.stubs(:body).returns(<<-EOS)
<a href="/page">Link text</a>
EOS
@session.expects(:get_via_redirect).with("/page", {})
@session.clicks_link "LINK TEXT"
end
def test_should_match_link_substrings
@response.stubs(:body).returns(<<-EOS)
<a href="/page">This is some cool link text, isn't it?</a>
EOS
@session.expects(:get_via_redirect).with("/page", {})
@session.clicks_link "Link text"
end
def test_should_work_with_elements_in_the_link
@response.stubs(:body).returns(<<-EOS)
<a href="/page"><span>Link text</span></a>
EOS
@session.expects(:get_via_redirect).with("/page", {})
@session.clicks_link "Link text"
end
def test_should_match_the_first_matching_link
@response.stubs(:body).returns(<<-EOS)
<a href="/page1">Link text</a>
<a href="/page2">Link text</a>
EOS
@session.expects(:get_via_redirect).with("/page1", {})
@session.clicks_link "Link text"
end
end

139
test/fills_in_test.rb Normal file
View File

@ -0,0 +1,139 @@
require File.dirname(__FILE__) + "/helper"
class FillsInTest < Test::Unit::TestCase
def setup
@session = ActionController::Integration::Session.new
@session.stubs(:assert_response)
@session.stubs(:get_via_redirect)
@session.stubs(:response).returns(@response=mock)
end
def test_should_work_with_textareas
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<label for="user_text">User Text</label>
<textarea id="user_text" name="user[text]"></textarea>
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", "user" => {"text" => "filling text area"})
@session.fills_in "User Text", :with => "filling text area"
@session.clicks_button
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
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" value="test@example.com" 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_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" => {"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"})
@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

17
test/helper.rb Normal file
View File

@ -0,0 +1,17 @@
require "rubygems"
require "test/unit"
# gem install redgreen for colored test output
begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end
require "mocha"
require "active_support"
require "action_controller"
require "action_controller/integration"
require File.expand_path(File.dirname(__FILE__) + "/../lib/webrat")
class ActionController::Integration::Session
def flunk(message)
raise message
end
end

93
test/selects_test.rb Normal file
View File

@ -0,0 +1,93 @@
require File.dirname(__FILE__) + "/helper"
class SelectsTest < Test::Unit::TestCase
def setup
@session = ActionController::Integration::Session.new
@session.stubs(:assert_response)
@session.stubs(:get_via_redirect)
@session.stubs(:response).returns(@response=mock)
end
def test_should_fail_if_option_not_found
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<select name="month"><option value="1">January</option></select>
</form>
EOS
@session.expects(:flunk)
@session.selects "February"
end
def test_should_fail_if_option_not_found_in_list_specified_by_element_name
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<select name="month"><option value="1">January</option></select>
<select name="year"><option value="2008">2008</option></select>
</form>
EOS
@session.expects(:flunk)
@session.selects "February", :from => "year"
end
def test_should_fail_if_specified_list_not_found
@response.stubs(:body).returns(<<-EOS)
<form method="get" action="/login">
<select name="month"><option value="1">January</option></select>
</form>
EOS
@session.expects(:flunk)
@session.selects "February", :from => "year"
end
def test_should_send_value_from_option
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<select name="month"><option value="1">January</option></select>
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", "month" => "1")
@session.selects "January"
@session.clicks_button
end
def test_should_send_value_from_option_in_list_specified_by_name
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<select name="start_month"><option value="s1">January</option></select>
<select name="end_month"><option value="e1">January</option></select>
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", "end_month" => "e1")
@session.selects "January", :from => "end_month"
@session.clicks_button
end
def test_should_send_value_from_option_in_list_specified_by_label
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<label for="start_month">Start Month</label>
<select id="start_month" name="start_month"><option value="s1">January</option></select>
<label for="end_month">End Month</label>
<select id="end_month" name="end_month"><option value="e1">January</option></select>
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", "end_month" => "e1")
@session.selects "January", :from => "End Month"
@session.clicks_button
end
def test_should_use_option_text_if_no_value
@response.stubs(:body).returns(<<-EOS)
<form method="post" action="/login">
<select name="month"><option>January</option></select>
<input type="submit" />
</form>
EOS
@session.expects(:post_via_redirect).with("/login", "month" => "January")
@session.selects "January"
@session.clicks_button
end
end

25
test/visits_test.rb Normal file
View File

@ -0,0 +1,25 @@
require File.dirname(__FILE__) + "/helper"
class VisitsTest < Test::Unit::TestCase
def setup
@session = ActionController::Integration::Session.new
@session.stubs(:assert_response)
@session.stubs(:get_via_redirect)
end
def test_should_use_get
@session.expects(:get_via_redirect).with("/", {})
@session.visits("/")
end
def test_should_assert_valid_response
@session.expects(:assert_response).with(:success)
@session.visits("/")
end
def test_should_require_a_visit_before_manipulating_page
assert_raise(RuntimeError) do
@session.fills_in "foo", :with => "blah"
end
end
end