Added Rspec and Webrat plugins and started porting Selenium on Rails tests to Rspec Plain Text Stories driving Webrat driving Selenium.

This commit is contained in:
Luke Melia 2008-06-18 02:57:57 -04:00 committed by Simon Rozet
parent 7b432a74ed
commit 2c09db45c5
602 changed files with 47788 additions and 29 deletions

5
vendor/plugins/webrat/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
coverage
pkg
doc
ri
email.txt

54
vendor/plugins/webrat/History.txt vendored Normal file
View file

@ -0,0 +1,54 @@
== Trunk
* Enhancements
* Support file fields using attaches_file (Patch from Kyle Hargraves)
* Support button elements (Patch from Nick Sieger)
* Support matching select options by regexp (Patch from Kyle Hargraves)
* Support relative links, including href="?foo=bar" (Patch from Kyle Hargraves)
* Support links to fully qualified URLs starting with http:// or https:// (Luke Melia)
* save_and_open_page rewrites css and image references to provide a friendlier debugging experience (Luke Melia)
* Bug fixes
* Fix bug with empty select list option (Patch from Kyle Hargraves)
* Fix regression of not sending default values in password fields
* Don't explode if encountering inputs with no type attribute (assume text)
== 0.2.0 / 2008-04-04
* 4 Major enhancements
* Add save_and_open_page to aid in debugging
* Add radio button support via #chooses method
* Add basic support for Rails-generated JavaScript link tags
* Add support for checkboxes (Patches from Kyle Hargraves and Jarkko Laine)
* Add support for textarea fields (Patch from Sacha Schlegel)
* 8 Minor enhancements
* Added reloads method to reload the page (Patch from Kamal Fariz Mahyuddi)
* Prevent making a request if clicking on local anchor link (Patch from Kamal Fariz Mahyuddi)
* Added clicks_link_within(selector, link_text), allowing restricting link search
to within a given css selector (Patch from Luke Melia)
* 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 support for alternate POST, PUT and DELETE link clicking (Patch from Kyle Hargraves)
* Change clicks_link to find the shortest matching link (Patch from Luke Melia)
* Improve matching for labels in potentially ambiguous cases
* 7 Bug fixes
* Fix incorrect serializing of collection inputs, i.e. name contains [] (Patch from Kamal Fariz Mahyuddi)
* Serialize empty text field values just like browsers (Patch from Kamal Fariz Mahyuddi)
* Quick fix to avoid @dom not initialized warnings (Patch from Kamal Fariz Mahyuddi)
* Docfix: bad reference to #select method in README (Patch from Luke Melia)
* Ensure Rails-style checkboxes work properly (checkboxes followed by a hidden input with the same name)
* 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
vendor/plugins/webrat/MIT-LICENSE.txt vendored 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.

41
vendor/plugins/webrat/Manifest.txt vendored Normal file
View file

@ -0,0 +1,41 @@
.gitignore
History.txt
MIT-LICENSE.txt
Manifest.txt
README.txt
Rakefile
TODO.txt
coverage/index.html
coverage/lib-webrat-field_rb.html
coverage/lib-webrat-form_rb.html
coverage/lib-webrat-label_rb.html
coverage/lib-webrat-link_rb.html
coverage/lib-webrat-logging_rb.html
coverage/lib-webrat-page_rb.html
coverage/lib-webrat-redirect_actions_rb.html
coverage/lib-webrat-select_option_rb.html
coverage/lib-webrat_rb.html
init.rb
install.rb
lib/webrat.rb
lib/webrat/field.rb
lib/webrat/form.rb
lib/webrat/label.rb
lib/webrat/link.rb
lib/webrat/logging.rb
lib/webrat/page.rb
lib/webrat/redirect_actions.rb
lib/webrat/select_option.rb
spec/attaches_file_spec.rb
spec/checks_spec.rb
spec/chooses_spec.rb
spec/clicks_button_spec.rb
spec/clicks_link_spec.rb
spec/fills_in_spec.rb
spec/rcov.opts
spec/reloads_spec.rb
spec/save_and_open_page_spec.rb
spec/selects_spec.rb
spec/spec.opts
spec/spec_helper.rb
spec/visits_spec.rb

97
vendor/plugins/webrat/README.txt vendored Normal file
View file

@ -0,0 +1,97 @@
Webrat
======
- [Code on GitHub](http://github.com/brynary/webrat)
- [Tickets on Lighthouse](http://webrat.lighthouseapp.com/)
Description
-----------
Webrat (_Ruby Acceptance Testing for Web applications_)
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.
Initial development was sponsored by [EastMedia](http://www.eastmedia.com).
Synopsis
--------
def test_sign_up
visits "/"
clicks_link "Sign up"
fills_in "Email", :with => "good@example.com"
selects "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 to these without any modifications.
Install
-------
To install the latest release:
sudo gem install webrat
In your stories/helper.rb:
require "webrat"
You could also unpack the gem into vendor/plugins.
Requirements
------------
- Rails >= 1.2.6
- Hpricot >= 0.6
- Rails integration tests in Test::Unit _or_
- RSpec stories (using an RSpec version >= revision 2997)
Authors
-------
- Maintained by [Bryan Helmkamp](mailto:bryan@brynary.com)
- Original code written by [Seth Fitzsimmons](mailto:seth@mojodna.net)
- Many other contributors. See attributions in History.txt
License
-------
Copyright (c) 2007 Bryan Helmkamp, Seth Fitzsimmons.
See MIT-LICENSE.txt in this directory.

65
vendor/plugins/webrat/Rakefile vendored Normal file
View file

@ -0,0 +1,65 @@
require 'rubygems'
require 'hoe'
require 'spec'
require 'spec/rake/spectask'
require './lib/webrat.rb'
Hoe.new('webrat', Webrat::VERSION) do |p|
p.rubyforge_name = 'webrat'
p.summary = 'Ruby Acceptance Testing for Web applications'
p.developer "Bryan Helmkamp", "bryan@brynary.com"
p.developer "Seth Fitzsimmons", "seth@mojodna.net"
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.changes = p.paragraphs_of('History.txt', 0..3).join("\n\n")
p.extra_deps << ["hpricot", ">= 0.6"]
p.remote_rdoc_dir = '' # Release to root
end
desc "Upload rdoc to brynary.com"
task :publish_rdoc => :docs do
sh "scp -r doc/ brynary.com:/apps/uploads/webrat"
end
Rake::TaskManager.class_eval do
def remove_task(task_name)
@tasks.delete(task_name.to_s)
end
end
def remove_task(task_name)
Rake.application.remove_task(task_name)
end
remove_task "test"
remove_task "test_deps"
desc "Run all specs in spec directory"
Spec::Rake::SpecTask.new do |t|
t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
t.spec_files = FileList['spec/**/*_spec.rb']
end
desc "Run all specs in spec directory with RCov"
Spec::Rake::SpecTask.new(:rcov) do |t|
t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
t.spec_files = FileList['spec/**/*_spec.rb']
t.rcov = true
t.rcov_opts = lambda do
IO.readlines(File.dirname(__FILE__) + "/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
end
end
require 'spec/rake/verify_rcov'
RCov::VerifyTask.new(:verify_rcov => :rcov) do |t|
t.threshold = 96.9 # Make sure you have rcov 0.7 or higher!
end
remove_task "default"
task :default do
Rake::Task["verify_rcov"].invoke
end

4
vendor/plugins/webrat/TODO.txt vendored Normal file
View file

@ -0,0 +1,4 @@
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
vendor/plugins/webrat/init.rb vendored Normal file
View file

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

1
vendor/plugins/webrat/install.rb vendored Normal file
View file

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

9
vendor/plugins/webrat/lib/webrat.rb vendored Normal file
View file

@ -0,0 +1,9 @@
module Webrat
VERSION = '0.2.1'
end
require "rubygems"
require "active_support"
require File.dirname(__FILE__) + "/webrat/core"
require File.dirname(__FILE__) + "/webrat/rails" if defined?(RAILS_ENV)

View file

@ -0,0 +1,3 @@
Dir[File.join(File.dirname(__FILE__), "core", "*.rb")].each do |file|
require File.expand_path(file)
end

View file

@ -0,0 +1,284 @@
module Webrat
class Field
def self.class_for_element(element)
if element.name == "input"
if %w[submit image].include?(element["type"])
field_class = "button"
else
field_class = element["type"] || "text"
end
else
field_class = element.name
end
Webrat.const_get("#{field_class.capitalize}Field")
rescue NameError
raise "Invalid field element: #{element.inspect}"
end
def initialize(form, element)
@form = form
@element = element
@value = default_value
end
def label_text
return nil unless label
label.text
end
def matches_id?(id)
@element["id"] == id.to_s
end
def matches_name?(name)
@element["name"] == name.to_s
end
def matches_label?(label_text)
return false unless label
label.matches_text?(label_text)
end
def to_param
param_parser.parse_query_parameters("#{name}=#{@value}")
end
def set(value)
@value = value
end
def unset
@value = default_value
end
protected
def id
@element["id"]
end
def name
@element["name"]
end
def label
return nil if label_element.nil?
@label ||= Label.new(self, label_element)
end
def label_element
@label_element ||= begin
parent = @element.parent
while parent.respond_to?(:parent)
return parent if parent.name == "label"
parent = parent.parent
end
if id.blank?
nil
else
@form.element.at("label[@for=#{id}]")
end
end
end
def default_value
@element["value"]
end
def param_parser
if defined?(CGIMethods)
CGIMethods
else
require "action_controller"
require "action_controller/integration"
ActionController::AbstractRequest
end
end
def replace_param_value(params, oval, nval)
output = Hash.new
params.each do |key, value|
case value
when Hash
value = replace_param_value(value, oval, nval)
when Array
value = value.map { |o| o == oval ? nval : oval }
when oval
value = nval
end
output[key] = value
end
output
end
end
class ButtonField < Field
def matches_text?(text)
@element.innerHTML =~ /#{Regexp.escape(text.to_s)}/i
end
def matches_value?(value)
@element["value"] =~ /^\W*#{Regexp.escape(value.to_s)}/i || matches_text?(value)
end
def to_param
return nil if @value.nil?
super
end
def default_value
nil
end
def click
set(@element["value"]) unless @element["name"].blank?
@form.submit
end
end
class HiddenField < Field
def to_param
if collection_name?
super
else
checkbox_with_same_name = @form.find_field(name, CheckboxField)
if checkbox_with_same_name.to_param.nil?
super
else
nil
end
end
end
protected
def collection_name?
name =~ /\[\]/
end
end
class CheckboxField < Field
def to_param
return nil if @value.nil?
super
end
def check
set(@element["value"] || "on")
end
def uncheck
set(nil)
end
protected
def default_value
if @element["checked"] == "checked"
@element["value"] || "on"
else
nil
end
end
end
class PasswordField < Field
end
class RadioField < Field
def to_param
return nil if @value.nil?
super
end
def choose
other_options.each do |option|
option.unset
end
set(@element["value"] || "on")
end
protected
def other_options
@form.fields.select { |f| f.name == name }
end
def default_value
if @element["checked"] == "checked"
@element["value"] || "on"
else
nil
end
end
end
class TextareaField < Field
protected
def default_value
@element.inner_html
end
end
class FileField < Field
def to_param
if @value.nil?
super
else
replace_param_value(super, @value, ActionController::TestUploadedFile.new(@value))
end
end
end
class TextField < Field
end
class ResetField < Field
end
class SelectField < Field
def find_option(text)
options.detect { |o| o.matches_text?(text) }
end
protected
def default_value
selected_options = @element / "option[@selected='selected']"
selected_options = @element / "option:first" if selected_options.empty?
selected_options.map do |option|
return "" if option.nil?
option["value"] || option.innerHTML
end
end
def options
option_elements.map { |oe| SelectOption.new(self, oe) }
end
def option_elements
(@element / "option")
end
end
end

View file

@ -0,0 +1,140 @@
module Webrat
class Form
attr_reader :element
def initialize(page, element)
@page = page
@element = element
@fields = nil
end
def find_field(id_or_name_or_label, *field_types)
possible_fields = fields_by_type(field_types)
find_field_by_id(possible_fields, id_or_name_or_label) ||
find_field_by_name(possible_fields, id_or_name_or_label) ||
find_field_by_label(possible_fields, id_or_name_or_label) ||
nil
end
def find_select_option(option_text)
select_fields = fields_by_type([SelectField])
select_fields.each do |select_field|
result = select_field.find_option(option_text)
return result if result
end
nil
end
def find_button(value = nil)
return fields_by_type([ButtonField]).first if value.nil?
possible_buttons = fields_by_type([ButtonField])
possible_buttons.each do |possible_button|
return possible_button if possible_button.matches_value?(value)
end
nil
end
def fields
return @fields if @fields
@fields = []
(@element / "button, input, textarea, select").each do |field_element|
@fields << Field.class_for_element(field_element).new(self, field_element)
end
@fields
end
def submit
Page.new(@page.session, form_action, form_method, params)
end
protected
def find_field_by_id(possible_fields, id)
possible_fields.each do |possible_field|
return possible_field if possible_field.matches_id?(id)
end
nil
end
def find_field_by_name(possible_fields, name)
possible_fields.each do |possible_field|
return possible_field if possible_field.matches_name?(name)
end
nil
end
def find_field_by_label(possible_fields, label)
matching_fields = []
possible_fields.each do |possible_field|
matching_fields << possible_field if possible_field.matches_label?(label)
end
matching_fields.sort_by { |f| f.label_text.length }.first
end
def fields_by_type(field_types)
fields.select { |f| field_types.include?(f.class) }
end
def params
all_params = {}
fields.each do |field|
next if field.to_param.nil?
merge(all_params, field.to_param)
end
all_params
end
def form_method
@element["method"].blank? ? :get : @element["method"].downcase
end
def form_action
@element["action"].blank? ? @page.url : @element["action"]
end
def merge(all_params, new_param)
new_param.each do |key, value|
case all_params[key]
when Hash, HashWithIndifferentAccess
merge_hash_values(all_params[key], value)
when Array
all_params[key] += value
else
all_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

View file

@ -0,0 +1,18 @@
module Webrat
class Label
def initialize(field, element)
@field = field
@element = element
end
def matches_text?(label_text)
text =~ /^\W*#{Regexp.escape(label_text.to_s)}\b/i
end
def text
@element.innerText
end
end
end

View file

@ -0,0 +1,83 @@
module Webrat
class Link
def initialize(page, element)
@page = page
@element = element
end
def click(method = nil)
method ||= http_method
return if href =~ /^#/ && method == :get
Page.new(@page.session, absolute_href, method, data)
end
def matches_text?(link_text)
text =~ /#{Regexp.escape(link_text.to_s)}/i
end
def text
@element.innerHTML
end
protected
def data
authenticity_token.blank? ? {} : {"authenticity_token" => authenticity_token}
end
def href
@element["href"]
end
def absolute_href
if href =~ %r{^https?://www.example.com(/.*)}
$LAST_MATCH_INFO.captures.first
elsif href =~ /^\?/
"#{@page.url}#{href}"
elsif href !~ /^\//
"#{@page.url}/#{href}"
else
href
end
end
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
@element["onclick"]
end
def http_method
if !onclick.blank? && onclick.include?("f.submit()")
http_method_from_js_form
else
:get
end
end
def http_method_from_js_form
if onclick.include?("m.setAttribute('name', '_method')")
http_method_from_fake_method_param
else
:post
end
end
def http_method_from_fake_method_param
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

View file

@ -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

View file

@ -0,0 +1,299 @@
require "rubygems"
require "hpricot"
require "English"
module Webrat
class Page
include Logging
attr_reader :session
attr_reader :url
def initialize(session, url = nil, method = :get, data = {})
@session = session
@url = url
@method = method
@data = data
reset_dom
reloads if @url
session.current_page = self
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(id_or_name_or_label, options = {})
field = find_field(id_or_name_or_label, TextField, TextareaField, PasswordField)
field.set(options[:with])
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(id_or_name_or_label)
field = find_field(id_or_name_or_label, CheckboxField)
field.check
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(id_or_name_or_label)
field = find_field(id_or_name_or_label, CheckboxField)
field.uncheck
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(label)
field = find_field(label, RadioField)
field.choose
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 = {})
id_or_name_or_label = options[:from]
if id_or_name_or_label
field = find_field(id_or_name_or_label, SelectField)
option = field.find_option(option_text)
else
option = find_select_option(option_text)
end
flunk("Could not find option #{option_text.inspect}") if option.nil?
option.choose
end
# Verifies that an input file field exists on the current page and sets
# its value to the given +file+, so that the file will be uploaded
# along with the form.
#
# Example:
# attaches_file "Photo", "/path/to/the/photo.jpg"
def attaches_file(id_or_name_or_label, path)
field = find_field(id_or_name_or_label, FileField)
field.set(path)
end
# Saves the 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?(session.saved_page_dir)
filename = "#{session.saved_page_dir}/webrat-#{Time.now.to_i}.html"
File.open(filename, "w") do |f|
f.write rewrite_css_and_image_references(session.response_body)
end
open_in_browser(filename)
end
def open_in_browser(path) # :nodoc
`open #{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 = find_link(link_text)
link.click
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)
link = find_link(link_text, selector)
link.click
end
# Works like clicks_link, but forces a GET request
#
# Example:
# clicks_get_link "Log out"
def clicks_get_link(link_text)
link = find_link(link_text)
link.click(: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)
link = find_link(link_text)
link.click(: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)
link = find_link(link_text)
link.click(: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)
link = find_link(link_text)
link.click(: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)
button = nil
forms.each do |form|
button = form.find_button(value)
break if button
end
flunk("Could not find button #{value.inspect}") if button.nil?
button.click
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 find_select_option(option_text)
forms.each do |form|
result = form.find_select_option(option_text)
return result if result
end
nil
end
def find_link(text, selector = nil)
matching_links = []
links_within(selector).each do |possible_link|
matching_links << possible_link if possible_link.matches_text?(text)
end
if matching_links.any?
matching_links.sort_by { |l| l.text.length }.first
else
flunk("Could not find link with text #{text.inspect}")
end
end
def find_field(id_or_name_or_label, *field_types)
forms.each do |form|
result = form.find_field(id_or_name_or_label, *field_types)
return result if result
end
flunk("Could not find #{field_types.inspect}: #{id_or_name_or_label.inspect}")
end
def request_page(url, method, data)
debug_log "REQUESTING PAGE: #{method.to_s.upcase} #{url} with #{data.inspect}"
session.send "#{method}", url, data || {}
if session.response_body =~ /Exception caught/ || session.response_body.blank?
save_and_open
end
flunk("Page load was not successful (Code: #{session.response_code.inspect})") unless (200..299).include?(session.response_code)
reset_dom
end
def reset_dom
@dom = nil
@forms = nil
end
def links_within(selector)
(dom / selector / "a[@href]").map do |link_element|
Link.new(self, link_element)
end
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_code
@dom = Hpricot(@session.response_body)
end
def flunk(message)
raise message
end
def rewrite_css_and_image_references(response_html) # :nodoc
return response_html unless session.doc_root
response_html.gsub(/"\/(stylesheets|images)/, session.doc_root + '/\1')
end
end
end

View file

@ -0,0 +1,28 @@
module Webrat
class SelectOption
def initialize(select, element)
@select = select
@element = element
end
def matches_text?(text)
if text.is_a?(Regexp)
@element.innerHTML =~ text
else
@element.innerHTML == text.to_s
end
end
def choose
@select.set(value)
end
protected
def value
@element["value"] || @element.innerHTML
end
end
end

View file

@ -0,0 +1,41 @@
module Webrat
class Session
def doc_root
nil
end
def saved_page_dir
File.expand_path(".")
end
def current_page
@current_page ||= Page.new(self)
end
def current_page=(new_page)
@current_page = new_page
end
def visits(*args)
Page.new(self, *args)
end
def respond_to?(name)
super || current_page.respond_to?(name)
end
def save_and_open_page
current_page.save_and_open
end
def method_missing(name, *args)
if current_page.respond_to?(name)
current_page.send(name, *args)
else
super
end
end
end
end

View file

@ -0,0 +1,5 @@
require "rubygems"
require "mechanize"
require File.dirname(__FILE__) + "/mechanize/mechanize_session"

View file

@ -0,0 +1,25 @@
module Webrat
class MechanizeSession < Session
def initialize(mechanize = WWW::Mechanize.new)
@mechanize = mechanize
end
def get(url, data)
@mechanize_page = @mechanize.get(url, data)
end
def post(url, data)
@mechanize_page = @mechanize.post(url, data)
end
def response_body
@mechanize_page.content
end
def response_code
@mechanize_page.code.to_i
end
end
end

View file

@ -0,0 +1,3 @@
require File.dirname(__FILE__) + "/rails/redirect_actions"
require File.dirname(__FILE__) + "/rails/rails_session"
require File.dirname(__FILE__) + "/rails/session"

View file

@ -0,0 +1,55 @@
module Webrat
class RailsSession < Session
def initialize(integration_session)
@integration_session = integration_session
end
def doc_root
File.expand_path(File.join(RAILS_ROOT, 'public'))
end
def saved_page_dir
File.expand_path(File.join(RAILS_ROOT, "tmp"))
end
def get(url, data)
@integration_session.get_via_redirect(url, data)
end
def post(url, data)
@integration_session.post_via_redirect(url, data)
end
def put(url, data)
@integration_session.put_via_redirect(url, data)
end
def delete(url, data)
@integration_session.delete_via_redirect(url, data)
end
def response_body
response.body
end
def response_code
response.code.to_i
end
protected
def update_protocol(href)
if href =~ /^https:/
@integration_session.https!(true)
elsif href =~ /^http:/
@integration_session.https!(false)
end
end
def response
@integration_session.response
end
end
end

View file

@ -0,0 +1,18 @@
# For Rails before http://dev.rubyonrails.org/ticket/10497 was committed
module Webrat
module RedirectActions
def put_via_redirect(path, parameters = {}, headers = {})
put path, parameters, headers
follow_redirect! while redirect?
status
end
def delete_via_redirect(path, parameters = {}, headers = {})
delete path, parameters, headers
follow_redirect! while redirect?
status
end
end
end

View file

@ -0,0 +1,37 @@
module ActionController
module Integration
class Session
unless instance_methods.include?("put_via_redirect")
include Webrat::RedirectActions
end
# Issues a GET request for a page, follows any redirects, and verifies the final page
# load was successful.
#
# Example:
# visits "/"
def visits(*args)
Webrat::Page.new(webrat_session, *args)
end
def respond_to?(name)
super || webrat_session.respond_to?(name)
end
def method_missing(name, *args)
if webrat_session.respond_to?(name)
webrat_session.send(name, *args)
else
super
end
end
protected
def webrat_session
@webrat_session ||= Webrat::RailsSession.new(self)
end
end
end
end

View file

@ -0,0 +1,5 @@
require "rubygems"
require "selenium"
require File.dirname(__FILE__) + "/selenium/selenium_session"

View file

@ -0,0 +1,115 @@
module Webrat
class SeleniumSession < Session
def initialize(selenium_driver)
@selenium = selenium_driver
define_location_strategies
end
def visits(url)
@selenium.open(url)
end
def fills_in(label_text, options)
@selenium.type("webrat=#{Regexp.escape(label_text)}", "#{options[:with]}")
end
def response_body
@selenium.get_html_source
end
def clicks_button(button_text = nil)
button_text ||= '*'
@selenium.click("button=#{button_text}")
@selenium.wait_for_page_to_load()
end
def clicks_link(link_text)
@selenium.click("webratlink=#{Regexp.escape(link_text)}")
@selenium.wait_for_page_to_load()
end
def selects(option_text, options = {})
id_or_name_or_label = options[:from]
if id_or_name_or_label
select_locator = "webrat=#{id_or_name_or_label}"
else
select_locator = "webratselectwithoption=#{option_text}"
end
@selenium.select(select_locator, option_text)
end
def chooses(label_text)
@selenium.click("webrat=#{label_text}")
end
def checks(label_text)
@selenium.check("webrat=#{label_text}")
end
protected
def define_location_strategies
@selenium.add_location_strategy('label', <<-JS)
var allLabels = inDocument.getElementsByTagName("label");
var candidateLabels = $A(allLabels).select(function(candidateLabel){
var regExp = new RegExp('^' + locator + '\\\\b', 'i');
var labelText = getText(candidateLabel).strip();
return (labelText.search(regExp) >= 0);
});
if (candidateLabels.length == 0) {
return null;
}
candidateLabels = candidateLabels.sortBy(function(s) { return s.length * -1; }); //reverse length sort
var locatedLabel = candidateLabels.first();
var labelFor = locatedLabel.getAttribute('for');
return selenium.browserbot.locationStrategies['id'].call(this, labelFor, inDocument, inWindow);
JS
@selenium.add_location_strategy('webrat', <<-JS)
var locationStrategies = selenium.browserbot.locationStrategies;
return locationStrategies['id'].call(this, locator, inDocument, inWindow)
|| locationStrategies['name'].call(this, locator, inDocument, inWindow)
|| locationStrategies['label'].call(this, locator, inDocument, inWindow)
|| null;
JS
@selenium.add_location_strategy('button', <<-JS)
if (locator == '*') {
return selenium.browserbot.locationStrategies['xpath'].call(this, "//input[@type='submit']", inDocument, inWindow)
}
var inputs = inDocument.getElementsByTagName('input');
return $A(inputs).find(function(candidate){
inputType = candidate.getAttribute('type');
if (inputType == 'submit' || inputType == 'image') {
var buttonText = $F(candidate);
return (PatternMatcher.matches(locator + '*', buttonText));
}
return false;
});
JS
@selenium.add_location_strategy('webratlink', <<-JS)
var links = inDocument.getElementsByTagName('a');
var candidateLinks = $A(links).select(function(candidateLink) {
return PatternMatcher.matches(locator, getText(candidateLink));
});
if (candidateLinks.length == 0) {
return null;
}
candidateLinks = candidateLinks.sortBy(function(s) { return s.length * -1; }); //reverse length sort
return candidateLinks.first();
JS
@selenium.add_location_strategy('webratselectwithoption', <<-JS)
var optionElements = inDocument.getElementsByTagName('option');
var locatedOption = $A(optionElements).find(function(candidate){
return (PatternMatcher.matches(locator, getText(candidate)));
});
return locatedOption ? locatedOption.parentNode : null;
JS
end
end
end

View file

@ -0,0 +1,10 @@
require "lib/webrat"
require "lib/webrat/mechanize"
include Webrat
sess = MechanizeSession.new
sess.visits "http://www.google.com/"
sess.fills_in "q", :with => "Webrat"
sess.clicks_button
sess.save_and_open_page

34
vendor/plugins/webrat/selenium_spike.rb vendored Normal file
View file

@ -0,0 +1,34 @@
require 'rubygems'
require "lib/webrat"
require "lib/webrat/selenium"
require 'selenium'
include Webrat
# To try it out:
#
# Install the required gem
# > sudo gem install Selenium
#
# Fire up the Selenium proxy server
# > selenium
#
# Run this script
# > ruby selenium_spike.rb
@sel = Selenium::SeleniumDriver.new("localhost", 4444, "*chrome", "http://localhost", 15000)
@sel.start
sess = SeleniumSession.new(@sel)
sess.visits "http://www.google.com/"
sess.fills_in "q", :with => "Webrat"
sess.clicks_link 'Images'
sess.clicks_button 'Search'
sess.selects 'Small images', :from => 'imagesize'
sess.clicks_link 'Preferences'
sess.chooses 'Do not filter'
sess.checks 'Open search results in a new browser window'
sess.clicks_button
sess.save_and_open_page
@sel.stop

View file

@ -0,0 +1,59 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "attaches_file" do
before do
@session = Webrat::TestSession.new
@filename = __FILE__
@uploaded_file = mock
ActionController::TestUploadedFile.stubs(:new).returns(@uploaded_file)
end
it "should fail if no file field found" do
@session.response_body = <<-EOS
<form method="post" action="/widgets">
</form>
EOS
lambda { @session.attaches_file("Doc", "/some/path") }.should raise_error
end
it "should submit empty strings for blank file fields" do
@session.response_body = <<-EOS
<form method="post" action="/widgets">
<input type="file" id="widget_file" name="widget[file]" />
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/widgets", { "widget" => { "file" => "" } })
@session.clicks_button
end
it "should submit the attached file" do
@session.response_body = <<-EOS
<form method="post" action="/widgets">
<label for="widget_file">Document</label>
<input type="file" id="widget_file" name="widget[file]" />
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/widgets", { "widget" => { "file" => @uploaded_file } })
@session.attaches_file "Document", @filename
@session.clicks_button
end
it "should support collections" do
@session.response_body = <<-EOS
<form method="post" action="/widgets">
<label for="widget_file1">Document</label>
<input type="file" id="widget_file1" name="widget[files][]" />
<label for="widget_file2">Spreadsheet</label>
<input type="file" id="widget_file2" name="widget[files][]" />
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/widgets", { "widget" => { "files" => [@uploaded_file, @uploaded_file] } })
@session.attaches_file "Document", @filename
@session.attaches_file "Spreadsheet", @filename
@session.clicks_button
end
end

View file

@ -0,0 +1,116 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "checks" do
before do
@session = Webrat::TestSession.new
end
it "should fail if no checkbox found" do
@session.response_body = <<-EOS
<form method="post" action="/login">
</form>
EOS
lambda { @session.checks "remember_me" }.should raise_error
end
it "should fail if input is not a checkbox" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="text" name="remember_me" />
</form>
EOS
lambda { @session.checks "remember_me" }.should raise_error
end
it "should check rails style checkboxes" do
@session.response_body = <<-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).with("/login", "user" => {"tos" => "1"})
@session.checks "TOS"
@session.clicks_button
end
it "should result in the value on being posted if not specified" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="checkbox" name="remember_me" />
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", "remember_me" => "on")
@session.checks "remember_me"
@session.clicks_button
end
it "should result in a custom value being posted" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="checkbox" name="remember_me" value="yes" />
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", "remember_me" => "yes")
@session.checks "remember_me"
@session.clicks_button
end
end
describe "unchecks" do
before do
@session = Webrat::TestSession.new
end
it "should fail if no checkbox found" do
@session.response_body = <<-EOS
<form method="post" action="/login">
</form>
EOS
lambda { @session.unchecks "remember_me" }.should raise_error
end
it "should fail if input is not a checkbox" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="text" name="remember_me" />
</form>
EOS
lambda { @session.unchecks "remember_me" }.should raise_error
end
it "should uncheck rails style checkboxes" do
@session.response_body = <<-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).with("/login", "user" => {"tos" => "0"})
@session.checks "TOS"
@session.unchecks "TOS"
@session.clicks_button
end
it "should result in value not being posted" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="checkbox" name="remember_me" value="yes" checked="checked" />
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", {})
@session.unchecks "remember_me"
@session.clicks_button
end
end

View file

@ -0,0 +1,80 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "chooses" do
before do
@session = Webrat::TestSession.new
end
it "should fail if no radio buttons found" do
@session.response_body = <<-EOS
<form method="post" action="/login">
</form>
EOS
lambda { @session.chooses "first option" }.should raise_error
end
it "should fail if input is not a radio button" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="text" name="first_option" />
</form>
EOS
lambda { @session.chooses "first_option" }.should raise_error
end
it "should check rails style radio buttons" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input id="user_gender_male" name="user[gender]" type="radio" value="M" />
<label for="user_gender_male">Male</label>
<input id="user_gender_female" name="user[gender]" type="radio" value="F" />
<label for="user_gender_female">Female</label>
<input type="submit" />
</form>
EOS
@session.expects(:get).with("/login", "user" => {"gender" => "M"})
@session.chooses "Male"
@session.clicks_button
end
it "should only submit last chosen value" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input id="user_gender_male" name="user[gender]" type="radio" value="M" />
<label for="user_gender_male">Male</label>
<input id="user_gender_female" name="user[gender]" type="radio" value="F" />
<label for="user_gender_female">Female</label>
<input type="submit" />
</form>
EOS
@session.expects(:get).with("/login", "user" => {"gender" => "M"})
@session.chooses "Female"
@session.chooses "Male"
@session.clicks_button
end
it "should result in the value on being posted if not specified" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="radio" name="first_option" />
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", "first_option" => "on")
@session.chooses "first_option"
@session.clicks_button
end
it "should result in the value on being posted if not specified and checked by default" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="radio" name="first_option" checked="checked"/>
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", "first_option" => "on")
@session.clicks_button
end
end

View file

@ -0,0 +1,336 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "clicks_button" do
before do
@session = Webrat::TestSession.new
end
it "should fail if no buttons" do
@session.response_body = <<-EOS
<form method="get" action="/login"></form>
EOS
lambda { @session.clicks_button }.should raise_error
end
it "should fail if input is not a submit button" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input type="reset" />
</form>
EOS
lambda { @session.clicks_button }.should raise_error
end
it "should default to get method" do
@session.response_body = <<-EOS
<form action="/login">
<input type="submit" />
</form>
EOS
@session.expects(:get)
@session.clicks_button
end
it "should assert valid response" do
@session.response_body = <<-EOS
<form action="/login">
<input type="submit" />
</form>
EOS
@session.response_code = 404
lambda { @session.clicks_button }.should raise_error
end
it "should submit the first form by default" do
@session.response_body = <<-EOS
<form method="get" action="/form1">
<input type="submit" />
</form>
<form method="get" action="/form2">
<input type="submit" />
</form>
EOS
@session.expects(:get).with("/form1", {})
@session.clicks_button
end
it "should not explode on file fields" do
@session.response_body = <<-EOS
<form method="get" action="/form1">
<input type="file" />
<input type="submit" />
</form>
EOS
@session.clicks_button
end
it "should submit the form with the specified button" do
@session.response_body = <<-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).with("/form2", {})
@session.clicks_button "Form2"
end
it "should use action from form" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input type="submit" />
</form>
EOS
@session.expects(:get).with("/login", {})
@session.clicks_button
end
it "should use method from form" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="submit" />
</form>
EOS
@session.expects(:post)
@session.clicks_button
end
it "should send button as param if it has a name" do
@session.response_body = <<-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).with("/login", "login" => "Login")
@session.clicks_button("Login")
end
it "should not send button as param if it has no name" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="submit" name="cancel" value="Cancel" />
<input type="submit" value="Login" />
</form>
EOS
@session.expects(:post).with("/login", {})
@session.clicks_button("Login")
end
it "should send default password field values" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input id="user_password" name="user[password]" value="mypass" type="password" />
<input type="submit" />
</form>
EOS
@session.expects(:get).with("/login", "user" => {"password" => "mypass"})
@session.clicks_button
end
it "should send default hidden field values" do
@session.response_body = <<-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).with("/login", "user" => {"email" => "test@example.com"})
@session.clicks_button
end
it "should send default text field values" do
@session.response_body = <<-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).with("/login", "user" => {"email" => "test@example.com"})
@session.clicks_button
end
it "should send default checked fields" do
@session.response_body = <<-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).with("/login", "user" => {"tos" => "1"})
@session.clicks_button
end
it "should send default radio options" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input id="user_gender_male" name="user[gender]" type="radio" value="M" />
<label for="user_gender_male">Male</label>
<input id="user_gender_female" name="user[gender]" type="radio" value="F" checked="checked" />
<label for="user_gender_female">Female</label>
<input type="submit" />
</form>
EOS
@session.expects(:get).with("/login", "user" => {"gender" => "F"})
@session.clicks_button
end
it "should send correct data for rails style unchecked fields" do
@session.response_body = <<-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).with("/login", "user" => {"tos" => "0"})
@session.clicks_button
end
it "should send correct data for rails style checked fields" do
@session.response_body = <<-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).with("/login", "user" => {"tos" => "1"})
@session.clicks_button
end
it "should send default collection fields" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="checkbox" name="options[]" value="burger" checked="checked" />
<input type="radio" name="options[]" value="fries" checked="checked" />
<input type="text" name="options[]" value="soda" />
<!-- Same value appearing twice -->
<input type="text" name="options[]" value="soda" />
<input type="hidden" name="options[]" value="dessert" />
<input type="hidden" name="response[choices][][selected]" value="one" />
<input type="hidden" name="response[choices][][selected]" value="two" />
<!-- Same value appearing twice -->
<input type="hidden" name="response[choices][][selected]" value="two" />
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login",
"options" => ["burger", "fries", "soda", "soda", "dessert"],
"response" => { "choices" => [{"selected" => "one"}, {"selected" => "two"}, {"selected" => "two"}]})
@session.clicks_button
end
it "should not send default unchecked fields" do
@session.response_body = <<-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).with("/login", {})
@session.clicks_button
end
it "should send default textarea values" do
@session.response_body = <<-EOS
<form method="post" action="/posts">
<textarea name="post[body]">Post body here!</textarea>
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/posts", "post" => {"body" => "Post body here!"})
@session.clicks_button
end
it "should send default selected option value from select" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<select name="month">
<option value="1">January</option>
<option value="2" selected="selected">February</option>
</select>
<input type="submit" />
</form>
EOS
@session.expects(:get).with("/login", "month" => "2")
@session.clicks_button
end
it "should send default selected option inner html from select when no value attribute" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<select name="month">
<option>January</option>
<option selected="selected">February</option>
</select>
<input type="submit" />
</form>
EOS
@session.expects(:get).with("/login", "month" => "February")
@session.clicks_button
end
it "should send first select option value when no option selected" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<select name="month">
<option value="1">January</option>
<option value="2">February</option>
</select>
<input type="submit" />
</form>
EOS
@session.expects(:get).with("/login", "month" => "1")
@session.clicks_button
end
it "should handle nested properties" do
@session.response_body = <<-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).with("/login", "contestant" => {"scores" => {'1' => '2', '3' => '4'}})
@session.clicks_button
end
it "should send default empty text field values" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input id="user_email" name="user[email]" value="" type="text" />
<input type="submit" />
</form>
EOS
@session.expects(:get).with("/login", "user" => {"email" => ""})
@session.clicks_button
end
it "should recognize button tags" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input id="user_email" name="user[email]" value="" type="text" />
<button type="submit" />
</form>
EOS
@session.expects(:get).with("/login", "user" => {"email" => ""})
@session.clicks_button
end
it "should recognize button tags by content" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input id="user_email" name="user[email]" value="" type="text" />
<button type="submit">Login</button>
</form>
EOS
@session.expects(:get).with("/login", "user" => {"email" => ""})
@session.clicks_button "Login"
end
end

View file

@ -0,0 +1,216 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "clicks_link" do
before do
@session = Webrat::TestSession.new
end
it "should use get by default" do
@session.response_body = <<-EOS
<a href="/page">Link text</a>
EOS
@session.expects(:get).with("/page", {})
@session.clicks_link "Link text"
end
it "should click get links" do
@session.response_body = <<-EOS
<a href="/page">Link text</a>
EOS
@session.expects(:get).with("/page", {})
@session.clicks_get_link "Link text"
end
it "should click delete links" do
@session.response_body = <<-EOS
<a href="/page">Link text</a>
EOS
@session.expects(:delete).with("/page", {})
@session.clicks_delete_link "Link text"
end
it "should click post links" do
@session.response_body = <<-EOS
<a href="/page">Link text</a>
EOS
@session.expects(:post).with("/page", {})
@session.clicks_post_link "Link text"
end
it "should click put links" do
@session.response_body = <<-EOS
<a href="/page">Link text</a>
EOS
@session.expects(:put).with("/page", {})
@session.clicks_put_link "Link text"
end
it "should click rails javascript links with authenticity tokens" do
@session.response_body = <<-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).with("/posts", "authenticity_token" => "aa79cb354597a60a3786e7e291ed4f74d77d3a62")
@session.clicks_link "Posts"
end
it "should click rails javascript delete links" do
@session.response_body = <<-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).with("/posts/1", {})
@session.clicks_link "Delete"
end
it "should click rails javascript post links" do
@session.response_body = <<-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).with("/posts", {})
@session.clicks_link "Posts"
end
it "should click rails javascript put links" do
@session.response_body = <<-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).with("/posts", {})
@session.clicks_link "Put"
end
it "should assert valid response" do
@session.response_body = <<-EOS
<a href="/page">Link text</a>
EOS
@session.response_code = 404
lambda { @session.clicks_link "Link text" }.should raise_error
end
it "should not be case sensitive" do
@session.response_body = <<-EOS
<a href="/page">Link text</a>
EOS
@session.expects(:get).with("/page", {})
@session.clicks_link "LINK TEXT"
end
it "should match link substrings" do
@session.response_body = <<-EOS
<a href="/page">This is some cool link text, isn't it?</a>
EOS
@session.expects(:get).with("/page", {})
@session.clicks_link "Link text"
end
it "should work with elements in the link" do
@session.response_body = <<-EOS
<a href="/page"><span>Link text</span></a>
EOS
@session.expects(:get).with("/page", {})
@session.clicks_link "Link text"
end
it "should match the first matching link" do
@session.response_body = <<-EOS
<a href="/page1">Link text</a>
<a href="/page2">Link text</a>
EOS
@session.expects(:get).with("/page1", {})
@session.clicks_link "Link text"
end
it "should choose the shortest link text match" do
@session.response_body = <<-EOS
<a href="/page1">Linkerama</a>
<a href="/page2">Link</a>
EOS
@session.expects(:get).with("/page2", {})
@session.clicks_link "Link"
end
it "should click link within a selector" do
@session.response_body = <<-EOS
<a href="/page1">Link</a>
<div id="container">
<a href="/page2">Link</a>
</div>
EOS
@session.expects(:get).with("/page2", {})
@session.clicks_link_within "#container", "Link"
end
it "should not make request when link is local anchor" do
@session.response_body = <<-EOS
<a href="#section-1">Jump to Section 1</a>
EOS
# Don't know why @session.expects(:get).never doesn't work here
@session.expects(:send).with('get_via_redirect', '#section-1', {}).never
@session.clicks_link "Jump to Section 1"
end
it "should follow relative links" do
@session.current_page.stubs(:url).returns("/page")
@session.response_body = <<-EOS
<a href="sub">Jump to sub page</a>
EOS
@session.expects(:get).with("/page/sub", {})
@session.clicks_link "Jump to sub page"
end
it "should follow fully qualified local links" do
@session.response_body = <<-EOS
<a href="http://www.example.com/page/sub">Jump to sub page</a>
EOS
@session.expects(:get).with("/page/sub", {})
@session.clicks_link "Jump to sub page"
end
it "should follow query parameters" do
@session.current_page.stubs(:url).returns("/page")
@session.response_body = <<-EOS
<a href="?foo=bar">Jump to foo bar</a>
EOS
@session.expects(:get).with("/page?foo=bar", {})
@session.clicks_link "Jump to foo bar"
end
end

View file

@ -0,0 +1,148 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "fills_in" do
before do
@session = Webrat::TestSession.new
end
it "should work with textareas" do
@session.response_body = <<-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).with("/login", "user" => {"text" => "filling text area"})
@session.fills_in "User Text", :with => "filling text area"
@session.clicks_button
end
it "should work with password fields" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input id="user_text" name="user[text]" type="password" />
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", "user" => {"text" => "pass"})
@session.fills_in "user_text", :with => "pass"
@session.clicks_button
end
it "should fail if input not found" do
@session.response_body = <<-EOS
<form method="get" action="/login">
</form>
EOS
lambda { @session.fills_in "Email", :with => "foo@example.com" }.should raise_error
end
it "should allow overriding default form values" do
@session.response_body = <<-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).with("/login", "user" => {"email" => "foo@example.com"})
@session.fills_in "user[email]", :with => "foo@example.com"
@session.clicks_button
end
it "should choose the shortest label match" do
@session.response_body = <<-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).with("/login", "user" => {"mail1" => "", "mail2" => "value"})
@session.fills_in "Some", :with => "value"
@session.clicks_button
end
it "should choose the first label match if closest is a tie" do
@session.response_body = <<-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).with("/login", "user" => {"mail1" => "value", "mail2" => ""})
@session.fills_in "Some mail", :with => "value"
@session.clicks_button
end
it "should anchor label matches to start of label" do
@session.response_body = <<-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
lambda { @session.fills_in "mail", :with => "value" }.should raise_error
end
it "should anchor label matches to word boundaries" do
@session.response_body = <<-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
lambda { @session.fills_in "Email", :with => "value" }.should raise_error
end
it "should work with inputs nested in labels" do
@session.response_body = <<-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).with("/login", "user" => {"email" => "foo@example.com"})
@session.fills_in "Email", :with => "foo@example.com"
@session.clicks_button
end
it "should work with full input names" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input id="user_email" name="user[email]" type="text" />
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", "user" => {"email" => "foo@example.com"})
@session.fills_in "user[email]", :with => "foo@example.com"
@session.clicks_button
end
it "should work with symbols" do
@session.response_body = <<-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).with("/login", "user" => {"email" => "foo@example.com"})
@session.fills_in :email, :with => "foo@example.com"
@session.clicks_button
end
end

View file

@ -0,0 +1,14 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "reloads" do
before do
@session = Webrat::TestSession.new
@session.response_body = "Hello world"
end
it "should reload the page" do
@session.expects(:get).with("/", {}).times(2)
@session.visits("/")
@session.reloads
end
end

View file

@ -0,0 +1,53 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "save_and_open_page" do
before do
@session = Webrat::TestSession.new
@session.response_body = <<-HTML
<html>
<head>
<link href="/stylesheets/foo.css" media="screen" rel="stylesheet" type="text/css" />
</head>
<body>
<h1>Hello world</h1>
<img src="/images/bar.png" />
</body>
</html>
HTML
File.stubs(:exist?).returns(true)
Time.stubs(:now).returns(1234)
Webrat::Page.any_instance.stubs(:open_in_browser)
@file_handle = mock()
File.stubs(:open).with(filename, 'w').yields(@file_handle)
@file_handle.stubs(:write)
end
it "should rewrite css rules" do
@file_handle.expects(:write).with do |html|
html =~ %r|#{@session.doc_root}/stylesheets/foo.css|s
end
@session.save_and_open_page
end
it "should rewrite image paths" do
@file_handle.expects(:write).with do |html|
html =~ %r|#{@session.doc_root}/images/bar.png|s
end
@session.save_and_open_page
end
it "should open the temp file in a browser" do
Webrat::Page.any_instance.expects(:open_in_browser).with(filename)
@session.save_and_open_page
end
def filename
File.expand_path("./webrat-#{Time.now}.html")
end
end

View file

@ -0,0 +1,140 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "selects" do
before do
@session = Webrat::TestSession.new
end
it "should fail if option not found" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<select name="month"><option value="1">January</option></select>
</form>
EOS
lambda { @session.selects "February", :from => "month" }.should raise_error
end
it "should fail if option not found in list specified by element name" do
@session.response_body = <<-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
lambda { @session.selects "February", :from => "year" }.should raise_error
end
it "should fail if specified list not found" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<select name="month"><option value="1">January</option></select>
</form>
EOS
lambda { @session.selects "February", :from => "year" }.should raise_error
end
it "should send value from option" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<select name="month"><option value="1">January</option></select>
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", "month" => "1")
@session.selects "January", :from => "month"
@session.clicks_button
end
it "should work with empty select lists" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<select name="month"></select>
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", 'month' => '')
@session.clicks_button
end
it "should work without specifying the field name or label" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<select name="month"><option value="1">January</option></select>
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", "month" => "1")
@session.selects "January"
@session.clicks_button
end
it "should send value from option in list specified by name" do
@session.response_body = <<-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).with("/login", "start_month" => "s1", "end_month" => "e1")
@session.selects "January", :from => "end_month"
@session.clicks_button
end
it "should send value from option in list specified by label" do
@session.response_body = <<-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).with("/login", "start_month" => "s1", "end_month" => "e1")
@session.selects "January", :from => "End Month"
@session.clicks_button
end
it "should use option text if no value" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<select name="month"><option>January</option></select>
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", "month" => "January")
@session.selects "January", :from => "month"
@session.clicks_button
end
it "should find option by regexp" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<select name="month"><option>January</option></select>
<input type="submit" />
</form>
EOS
@session.expects(:post).with("/login", "month" => "January")
@session.selects(/jan/i)
@session.clicks_button
end
it "should find option by regexp in list specified by label" do
@session.response_body = <<-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).with("/login", "start_month" => "s1", "end_month" => "e1")
@session.selects(/jan/i, :from => "End Month")
@session.clicks_button
end
end

View file

@ -0,0 +1,22 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "visits" do
before do
@session = Webrat::TestSession.new
@session.response_body = "Hello world"
end
it "should use get" do
@session.expects(:get).with("/", {})
@session.visits("/")
end
it "should assert valid response" do
@session.response_code = 404
lambda { @session.visits("/") }.should raise_error
end
it "should require a visit before manipulating page" do
lambda { @session.fills_in "foo", :with => "blah" }.should raise_error
end
end

View file

@ -0,0 +1,26 @@
module Webrat
class TestSession < Session
attr_accessor :response_body
attr_writer :response_code
def doc_root
File.expand_path(File.join(".", "public"))
end
def response_code
@response_code || 200
end
def get(url, data)
end
def post(url, data)
end
def put(url, data)
end
def delete(url, data)
end
end
end

View file

@ -0,0 +1,20 @@
# it "should default to current url" do
# # @session.current_page.stubs(:url).returns("/page")
# @session.response_body = <<-EOS
# <form method="get">
# <input type="submit" />
# </form>
# EOS
# @page.stubs(:url).returns("/current")
# @session.expects(:get).with("/current", {})
# @session.clicks_button
# end
#
# it "should follow fully qualified secure local links" do
# @session.response_body = <<-EOS
# <a href="https://www.example.com/page/sub">Jump to sub page</a>
# EOS
# @session.expects(:https!).with(true)
# @session.expects(:get).with("/page/sub", {})
# @session.clicks_link "Jump to sub page"
# end

1
vendor/plugins/webrat/spec/rcov.opts vendored Normal file
View file

@ -0,0 +1 @@
-x gems,spec

0
vendor/plugins/webrat/spec/spec.opts vendored Normal file
View file

View file

@ -0,0 +1,19 @@
require "rubygems"
require "spec"
# gem install redgreen for colored test output
begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end
require "mocha"
require "active_support"
silence_warnings do
require "action_controller"
require "action_controller/integration"
end
require File.expand_path(File.dirname(__FILE__) + "/../lib/webrat")
require File.dirname(__FILE__) + "/fakes/test_session"
Spec::Runner.configure do |config|
config.mock_with :mocha
end