Merge branch 'brynary/master'

This commit is contained in:
Ben Mabey 2008-11-13 15:05:56 -07:00
commit b8a87e3143
82 changed files with 2677 additions and 862 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
coverage coverage
.DS_Store
pkg pkg
doc doc
ri ri

View File

@ -1,38 +1,82 @@
== Trunk == Trunk
* Major enhancements
* Added #within for manipulating the current page within a selector scope
* Add support for simulating SSL requests (Luke Melia)
* Add support for file fields via #attaches_file method (Patch from Kyle Hargraves)
* Support relative links, including href="?foo=bar" (Patch from Kyle Hargraves)
* Separated Rails-specific code from the Webrat core to make it easier to use Webrat with other environments
* Alias visits as visit, clicks_link as click_link, etc. for better readability
* Minor enhancements * Minor enhancements
* Add support for redirect_to :back by sending HTTP_REFERER headers (Patch from Hendrik Volkmer) * Raise Webrat::PageLoadError when a failure occurs so that application exceptions can be more accurately tested (Ryan Briones)
== 0.3.2 / 2008-11-08
* Minor enhancements
* Fixes behavior or have_tag when a block is passed. It passes the matched node(s) to the block for further specs again. (Carl Lerche)
== 0.3.1 / 2008-11-07
* Minor enhancements
* Use @_webrat_session instance variable instead of @session for Merb integration to avoid collisions
== 0.3.0 / 2008-11-07
* Major enhancements
* Added Merb support (Gwyn Morfey, Jeremy Burks, Rob Kaufman, Yehuda Katz)
* Added experimental Selenium support (Luke Melia)
* Add have_selector, have_xpath, have_tag and contain matchers from Merb
* Switch from Hpricot to Nokogiri for XML parsing (thanks, Aaron Patterson)
* Minor enhancements
* Added #within for manipulating the current page within a selector scope
* Add support for file fields via #attaches_file method (Rails only at the moment) (Kyle Hargraves)
* Add support for simulating SSL requests (Luke Melia)
* Added #basic_auth(user, pass) to support HTTP Basic Auth (Aslak Hellesøy)
* Added support for Sinatra and Rack (Aslak Hellesøy)
* Rename visits to visit, fills_in to fill_in, etc.
* Add #field_labeled for looking up form fields by label (David Chelimsky)
* Add #field_named and #field_with_id locators
* Don't depend on hoe anymore
* Return responses after sending requests
* Allow clicking links and buttons by a regular expression in Selenium (Luke Melia)
* Allow clicking links by a regular expression
* Add #http_accept for including MIME type HTTP "Accept" headers (Ryan Briones)
* Add #header to support inclusion of custom HTTP headers (Ryan Briones)
* Consider response codes 200-499 as successful enough to not raise a Webrat error (David Leal)
* Add Webrat.root method for cross-framework support (Krzysztof Zylawy)
* Add support for clicking areas of an image map (Alex Lang)
* Support relative links, including href="?foo=bar" (Kyle Hargraves)
* Separated Rails-specific code from the Webrat core to make it easier to use Webrat with other environments
* Alias visits as visit, clicks_link as click_link, etc. for better readability
* Raise error when trying to interact with a disabled form element (Luke Melia)
* Don't send disabled form elements to the server (Nicholas A. Evans)
* Display response body when the page load is not successful (David Leal)
* CGI escape form field values (Miha Filej)
* Add support for redirect_to :back by sending HTTP_REFERER headers (Hendrik Volkmer)
* Expose current DOM (as an Hpricot object) as #current_dom * Expose current DOM (as an Hpricot object) as #current_dom
* Add support for disabling JavaScript when clicking a link to enable testing of both JS * Add support for disabling JavaScript when clicking a link to enable testing of both JS
and non-JS implementations (Luke Melia and Bryan Helmkamp) and non-JS implementations (Luke Melia and Bryan Helmkamp)
* Support &nbsp's as spaces in matching link text (Patch from Luke Melia) * Support &nbsp's as spaces in matching link text (Luke Melia)
* Support button elements (Patch from Nick Sieger) * Support button elements (Nick Sieger)
* Support matching select options by regexp (Patch from Kyle Hargraves) * Support matching select options by regexp (Kyle Hargraves)
* save_and_open_page rewrites css and image references to provide a friendlier debugging experience (Luke Melia) * save_and_open_page rewrites css and image references to provide a friendlier debugging experience (Luke Melia)
* Added support for matching alt attributes in fields (primarly for clicks_button) (Patch from Aaron Quint) * Added support for matching alt attributes in fields (primarly for clicks_button) (Aaron Quint)
* Support '&' in submitted values (Patch from Kyle Hargraves) * Support '&' in submitted values (Kyle Hargraves)
* Support clicking links by title (Patch from Dan Barry) * Support clicking links by title (Dan Barry)
* Added missing spec for clicking image buttons (Patch from Tim Harper) * Added missing spec for clicking image buttons (Tim Harper)
* Switched tests to specs, and from Mocha to RSpec's mocking library * Switched tests to specs, and from Mocha to RSpec's mocking library
* Add support to click_button for IDs (Gwyn Morfey)
* Miscellaneous core refactorings (Jan Suchal)
* Bug fixes * Bug fixes
* Don't open blank pages in the browser (Patch from Kyle Hargraves) * Fix initialization of WWW::Mechanize (Derek Kastner)
* Support radio buttons with multiple labels (Patch from Dan Barry) * Don't open blank pages in the browser (Kyle Hargraves)
* Fix load order bug on some platforms (Patch from Ismael Celis) * Support radio buttons with multiple labels (Dan Barry)
* Fix bug with empty select list option (Patch from Kyle Hargraves) * Fix load order bug on some platforms (Ismael Celis)
* Fix bug with empty select list option (Kyle Hargraves)
* Fix regression of not sending default values in password fields * Fix regression of not sending default values in password fields
* Don't explode if encountering inputs with no type attribute (assume text) * Don't explode if encountering inputs with no type attribute (assume text)
* Fix bug where choosing a radio button in a series with a default submitted the incorrect field value (Luke Melia)
== 0.2.0 / 2008-04-04 == 0.2.0 / 2008-04-04
@ -42,29 +86,29 @@
* Add radio button support via #chooses method * Add radio button support via #chooses method
* Add basic support for Rails-generated JavaScript link tags * Add basic support for Rails-generated JavaScript link tags
* Add support for checkboxes (Patches from Kyle Hargraves and Jarkko Laine) * Add support for checkboxes (Patches from Kyle Hargraves and Jarkko Laine)
* Add support for textarea fields (Patch from Sacha Schlegel) * Add support for textarea fields (Sacha Schlegel)
* 8 Minor enhancements * 8 Minor enhancements
* Added reloads method to reload the page (Patch from Kamal Fariz Mahyuddi) * Added reloads method to reload the page (Kamal Fariz Mahyuddi)
* Prevent making a request if clicking on local anchor link (Patch from Kamal Fariz Mahyuddi) * Prevent making a request if clicking on local anchor link (Kamal Fariz Mahyuddi)
* Added clicks_link_within(selector, link_text), allowing restricting link search * Added clicks_link_within(selector, link_text), allowing restricting link search
to within a given css selector (Patch from Luke Melia) to within a given css selector (Luke Melia)
* Allow specifying the input name/label when doing a select (Patch from David Chelimsky) * Allow specifying the input name/label when doing a select (David Chelimsky)
* Raise a specific exception if the developer tries to manipulate form elements before loading a page (Patch from James Deville) * Raise a specific exception if the developer tries to manipulate form elements before loading a page (James Deville)
* Add support for alternate POST, PUT and DELETE link clicking (Patch from Kyle Hargraves) * Add support for alternate POST, PUT and DELETE link clicking (Kyle Hargraves)
* Change clicks_link to find the shortest matching link (Patch from Luke Melia) * Change clicks_link to find the shortest matching link (Luke Melia)
* Improve matching for labels in potentially ambiguous cases * Improve matching for labels in potentially ambiguous cases
* 7 Bug fixes * 7 Bug fixes
* Fix incorrect serializing of collection inputs, i.e. name contains [] (Patch from Kamal Fariz Mahyuddi) * Fix incorrect serializing of collection inputs, i.e. name contains [] (Kamal Fariz Mahyuddi)
* Serialize empty text field values just like browsers (Patch from Kamal Fariz Mahyuddi) * Serialize empty text field values just like browsers (Kamal Fariz Mahyuddi)
* Quick fix to avoid @dom not initialized warnings (Patch from Kamal Fariz Mahyuddi) * Quick fix to avoid @dom not initialized warnings (Kamal Fariz Mahyuddi)
* Docfix: bad reference to #select method in README (Patch from Luke Melia) * Docfix: bad reference to #select method in README (Luke Melia)
* Ensure Rails-style checkboxes work properly (checkboxes followed by a hidden input with the same name) * 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) * Fix Edge Rails (a.k.a. 2.0 RC) compatibility (David Chelimsky)
* Support param hashes nested more than one level (Patch from David Chelimsky) * Support param hashes nested more than one level (David Chelimsky)
== 0.1.0 / 2007-11-28 == 0.1.0 / 2007-11-28

View File

@ -1,41 +0,0 @@
.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

View File

@ -1,11 +1,9 @@
Webrat === Webrat
======
- [Code on GitHub](http://github.com/brynary/webrat) - [Code on GitHub](http://github.com/brynary/webrat)
- [Tickets on Lighthouse](http://webrat.lighthouseapp.com/) - [Tickets on Lighthouse](http://webrat.lighthouseapp.com/)
Description === Description
-----------
Webrat (_Ruby Acceptance Testing for Web applications_) Webrat (_Ruby Acceptance Testing for Web applications_)
lets you quickly write robust and thorough acceptance tests for a Ruby lets you quickly write robust and thorough acceptance tests for a Ruby
@ -23,15 +21,14 @@ run your tests much faster and more frequently.
Initial development was sponsored by [EastMedia](http://www.eastmedia.com). Initial development was sponsored by [EastMedia](http://www.eastmedia.com).
Synopsis === Synopsis
--------
def test_sign_up def test_sign_up
visits "/" visit "/"
clicks_link "Sign up" click_link "Sign up"
fills_in "Email", :with => "good@example.com" fill_in "Email", :with => "good@example.com"
selects "Free account" select "Free account"
clicks_button "Register" click_button "Register"
... ...
end end
@ -62,8 +59,14 @@ tests to break unnecessarily as your application evolves:
A test written with Webrat can handle these changes to these without any modifications. A test written with Webrat can handle these changes to these without any modifications.
Install === Merb
------- To avoid losing sessions, you need this in environments/test.rb:
Merb::Config.use do |c|
c[:session_store] = 'memory'
end
=== Install
To install the latest release: To install the latest release:
@ -75,23 +78,13 @@ In your stories/helper.rb:
You could also unpack the gem into vendor/plugins. You could also unpack the gem into vendor/plugins.
Requirements === Authors
------------
- 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) - Maintained by [Bryan Helmkamp](mailto:bryan@brynary.com)
- Original code written by [Seth Fitzsimmons](mailto:seth@mojodna.net) - Original code written by [Seth Fitzsimmons](mailto:seth@mojodna.net)
- Many other contributors. See attributions in History.txt - Many other contributors. See attributions in History.txt
License === License
-------
Copyright (c) 2007 Bryan Helmkamp, Seth Fitzsimmons. Copyright (c) 2007 Bryan Helmkamp, Seth Fitzsimmons.
See MIT-LICENSE.txt in this directory. See MIT-LICENSE.txt in this directory.

View File

@ -1,44 +1,53 @@
require 'rubygems' require 'rubygems'
require 'hoe' require "rake/gempackagetask"
require 'rake/rdoctask'
require "rake/clean"
require 'spec' require 'spec'
require 'spec/rake/spectask' require 'spec/rake/spectask'
require 'spec/rake/verify_rcov'
require './lib/webrat.rb' require './lib/webrat.rb'
Hoe.new('webrat', Webrat::VERSION) do |p| ##############################################################################
p.rubyforge_name = 'webrat' # Package && release
p.summary = 'Ruby Acceptance Testing for Web applications' ##############################################################################
spec = Gem::Specification.new do |s|
s.name = "webrat"
s.version = Webrat::VERSION
s.platform = Gem::Platform::RUBY
s.author = "Bryan Helmkamp"
s.email = "bryan" + "@" + "brynary.com"
s.homepage = "http://github.com/brynary/webrat"
s.summary = "Webrat. Ruby Acceptance Testing for Web applications"
s.bindir = "bin"
s.description = s.summary
s.require_path = "lib"
s.files = %w(History.txt init.rb install.rb MIT-LICENSE.txt README.txt Rakefile TODO.txt) + Dir["lib/**/*"]
p.developer "Bryan Helmkamp", "bryan@brynary.com" # rdoc
p.developer "Seth Fitzsimmons", "seth@mojodna.net" s.has_rdoc = true
s.extra_rdoc_files = %w(README.txt MIT-LICENSE.txt)
p.description = p.paragraphs_of('README.txt', 4..6).join("\n\n") # Dependencies
p.url = p.paragraphs_of('README.txt', 1).first.split("\n").first.strip s.add_dependency "nokogiri", ">= 1.0.3"
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 end
Rake::GemPackageTask.new(spec) do |package|
package.gem_spec = spec
end
desc 'Show information about the gem.'
task :debug_gem do
puts spec.to_ruby
end
CLEAN.include ["pkg", "*.gem", "doc", "ri", "coverage"]
desc "Upload rdoc to brynary.com" desc "Upload rdoc to brynary.com"
task :publish_rdoc => :docs do task :publish_rdoc => :docs do
sh "scp -r doc/ brynary.com:/apps/uploads/webrat" sh "scp -r doc/ brynary.com:/apps/uploads/webrat"
end end
Rake::TaskManager.class_eval do desc "Run API and Core specs"
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| Spec::Rake::SpecTask.new do |t|
t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
t.spec_files = FileList['spec/**/*_spec.rb'] t.spec_files = FileList['spec/**/*_spec.rb']
@ -54,12 +63,27 @@ Spec::Rake::SpecTask.new(:rcov) do |t|
end end
end end
require 'spec/rake/verify_rcov'
RCov::VerifyTask.new(:verify_rcov => :rcov) do |t| RCov::VerifyTask.new(:verify_rcov => :rcov) do |t|
t.threshold = 97.1 # Make sure you have rcov 0.7 or higher! t.threshold = 96.2 # Make sure you have rcov 0.7 or higher!
end end
remove_task "default"
task :default do task :default do
Rake::Task["verify_rcov"].invoke Rake::Task["verify_rcov"].invoke
end end
desc 'Install the package as a gem.'
task :install_gem => [:clean, :package] do
gem = Dir['pkg/*.gem'].first
sh "sudo gem install --local #{gem}"
end
Rake::RDocTask.new(:docs) do |rd|
rd.main = "README.txt"
rd.rdoc_dir = 'doc'
files = spec.files.grep(/^(lib|bin|ext)|txt$/)
files -= ["TODO.txt"]
files -= files.grep(/\.js$/)
rd.rdoc_files = files.uniq
title = "webrat-#{Webrat::VERSION} Documentation"
rd.options << "-t #{title}"
end

View File

@ -1,5 +1,10 @@
Restore SSL support for Rails (See 73d3b72108254c0f1ad00e63f8e712115cc8ca7c) Run tests in separate processes to eliminate constant-level dependencies
Full support for multiple forms on a page Add rake tasks for selenium runs
Track the current form based on the location of the last manipulated input, use this as a default for clicks_button Add tests for selenium
Add tests for locator strategies
Use Webrat::Methods for Rails integration
Get file uploads workign with merb
Fix #within scoping for forms that exist outside the scope
Make current_url work with redirections Make current_url work with redirections
Support for a hash mapping page names to page URLs Track the current form based on the location of the last manipulated input, use this as a default for click_button
Verify SSL support in Rails and Merb

View File

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

View File

@ -1,9 +1,34 @@
require "rubygems"
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
module Webrat module Webrat
VERSION = '0.2.1' VERSION = '0.3.2'
def self.root #:nodoc:
defined?(RAILS_ROOT) ? RAILS_ROOT : Merb.root
end
class WebratError < StandardError
end
end end
require "rubygems" # We need Nokogiri's CSS to XPath support, even if using REXML
require "active_support" require "nokogiri/css"
require File.dirname(__FILE__) + "/webrat/core" # Require nokogiri and fall back on rexml
require File.dirname(__FILE__) + "/webrat/rails" if defined?(RAILS_ENV) begin
require "nokogiri"
require "webrat/core/nokogiri"
rescue LoadError => e
require "rexml/document"
warn("Standard REXML library is slow. Please consider installing nokogiri.\nUse \"sudo gem install nokogiri\"")
end
require "webrat/core"
# TODO: This is probably not a good idea.
# Probably better for webrat users to require "webrat/rails" etc. directly
if defined?(RAILS_ENV)
require "webrat/rails"
end

View File

@ -1,3 +1,12 @@
Dir[File.join(File.dirname(__FILE__), "core", "*.rb")].sort.each do |file| require "webrat/core/nokogiri"
require File.expand_path(file) require "webrat/core/logging"
end require "webrat/core/flunk"
require "webrat/core/form"
require "webrat/core/scope"
require "webrat/core/link"
require "webrat/core/area"
require "webrat/core/label"
require "webrat/core/select_option"
require "webrat/core/session"
require "webrat/core/methods"
require "webrat/core/matchers"

44
lib/webrat/core/area.rb Normal file
View File

@ -0,0 +1,44 @@
module Webrat
class Area #:nodoc:
def initialize(session, element)
@session = session
@element = element
end
def click(method = nil, options = {})
@session.request_page(absolute_href, :get, {})
end
def matches_text?(id_or_title)
matcher = /#{Regexp.escape(id_or_title.to_s)}/i
title =~ matcher || id =~ matcher
end
protected
def href
@element["href"]
end
def title
@element["title"]
end
def id
@element["id"]
end
def absolute_href
if href =~ /^\?/
"#{@session.current_url}#{href}"
elsif href !~ %r{^https?://[\w|.]+(/.*)} && (href !~ /^\//)
"#{@session.current_url}/#{href}"
else
href
end
end
end
end

View File

@ -1,17 +1,20 @@
require "cgi"
require "webrat/core_extensions/blank"
require "webrat/core_extensions/nil_to_param"
module Webrat module Webrat
class Field class Field #:nodoc:
def self.class_for_element(element) def self.class_for_element(element)
if element.name == "input" if element.name == "input"
if %w[submit image].include?(element["type"]) if %w[submit image].include?(element["type"])
field_class = "button" field_class = "button"
else else
field_class = element["type"] || "text" field_class = element["type"] || "text" #default type; 'type' attribute is not mandatory
end end
else else
field_class = element.name field_class = element.name
end end
Webrat.const_get("#{field_class.capitalize}Field") Webrat.const_get("#{field_class.capitalize}Field")
rescue NameError rescue NameError
raise "Invalid field element: #{element.inspect}" raise "Invalid field element: #{element.inspect}"
@ -46,9 +49,26 @@ module Webrat
@element["alt"] =~ /^\W*#{Regexp.escape(alt.to_s)}/i @element["alt"] =~ /^\W*#{Regexp.escape(alt.to_s)}/i
end end
def disabled?
@element.attributes.has_key?("disabled") && @element["disabled"] != 'false'
end
def raise_error_if_disabled
raise "Cannot interact with disabled form element (#{self})" if disabled?
end
def to_param def to_param
value = @value.to_s.gsub('&', '%26') return nil if disabled?
param_parser.parse_query_parameters("#{name}=#{value}")
key_and_value = "#{name}=#{escaped_value}"
if defined?(CGIMethods)
CGIMethods.parse_query_parameters(key_and_value)
elsif defined?(ActionController::AbstractRequest)
ActionController::AbstractRequest.parse_query_parameters(key_and_value)
else
::Merb::Parse.query(key_and_value)
end
end end
def set(value) def set(value)
@ -69,6 +89,10 @@ module Webrat
@element["name"] @element["name"]
end end
def escaped_value
CGI.escape(@value.to_s)
end
def labels def labels
@labels ||= label_elements.map { |element| Label.new(self, element) } @labels ||= label_elements.map { |element| Label.new(self, element) }
end end
@ -87,7 +111,7 @@ module Webrat
end end
unless id.blank? unless id.blank?
@label_elements += @form.element / "label[@for=#{id}]" @label_elements += @form.element.search("label[@for='#{id}']")
end end
@label_elements @label_elements
@ -97,16 +121,6 @@ module Webrat
@element["value"] @element["value"]
end 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) def replace_param_value(params, oval, nval)
output = Hash.new output = Hash.new
params.each do |key, value| params.each do |key, value|
@ -124,10 +138,10 @@ module Webrat
end end
end end
class ButtonField < Field class ButtonField < Field #:nodoc:
def matches_text?(text) def matches_text?(text)
@element.innerHTML =~ /#{Regexp.escape(text.to_s)}/i @element.inner_html =~ /#{Regexp.escape(text.to_s)}/i
end end
def matches_value?(value) def matches_value?(value)
@ -144,21 +158,22 @@ module Webrat
end end
def click def click
raise_error_if_disabled
set(@element["value"]) unless @element["name"].blank? set(@element["value"]) unless @element["name"].blank?
@form.submit @form.submit
end end
end end
class HiddenField < Field class HiddenField < Field #:nodoc:
def to_param def to_param
if collection_name? if collection_name?
super super
else else
checkbox_with_same_name = @form.find_field(name, CheckboxField) checkbox_with_same_name = @form.field(name, CheckboxField)
if checkbox_with_same_name.to_param.nil? if checkbox_with_same_name.to_param.blank?
super super
else else
nil nil
@ -174,7 +189,7 @@ module Webrat
end end
class CheckboxField < Field class CheckboxField < Field #:nodoc:
def to_param def to_param
return nil if @value.nil? return nil if @value.nil?
@ -182,10 +197,16 @@ module Webrat
end end
def check def check
raise_error_if_disabled
set(@element["value"] || "on") set(@element["value"] || "on")
end end
def checked?
@element["checked"] == "checked"
end
def uncheck def uncheck
raise_error_if_disabled
set(nil) set(nil)
end end
@ -201,10 +222,10 @@ module Webrat
end end
class PasswordField < Field class PasswordField < Field #:nodoc:
end end
class RadioField < Field class RadioField < Field #:nodoc:
def to_param def to_param
return nil if @value.nil? return nil if @value.nil?
@ -212,6 +233,7 @@ module Webrat
end end
def choose def choose
raise_error_if_disabled
other_options.each do |option| other_options.each do |option|
option.set(nil) option.set(nil)
end end
@ -235,7 +257,7 @@ module Webrat
end end
class TextareaField < Field class TextareaField < Field #:nodoc:
protected protected
@ -245,7 +267,7 @@ module Webrat
end end
class FileField < Field class FileField < Field #:nodoc:
attr_accessor :content_type attr_accessor :content_type
@ -274,13 +296,13 @@ module Webrat
end end
class TextField < Field class TextField < Field #:nodoc:
end end
class ResetField < Field class ResetField < Field #:nodoc:
end end
class SelectField < Field class SelectField < Field #:nodoc:
def find_option(text) def find_option(text)
options.detect { |o| o.matches_text?(text) } options.detect { |o| o.matches_text?(text) }
@ -289,11 +311,12 @@ module Webrat
protected protected
def default_value def default_value
selected_options = @element / "option[@selected='selected']" selected_options = @element.search(".//option[@selected='selected']")
selected_options = @element / "option:first" if selected_options.empty? selected_options = @element.search(".//option[position() = 1]") if selected_options.empty?
selected_options.map do |option| selected_options.map do |option|
return "" if option.nil? return "" if option.nil?
option["value"] || option.innerHTML option["value"] || option.inner_html
end end
end end
@ -302,7 +325,7 @@ module Webrat
end end
def option_elements def option_elements
(@element / "option") @element.search(".//option")
end end
end end

View File

@ -1,6 +1,6 @@
module Flunk module Flunk
def flunk(message) def flunk(message) #:nodoc:
raise message raise message
end end

View File

@ -1,5 +1,8 @@
require "webrat/core/field"
require "webrat/core_extensions/blank"
module Webrat module Webrat
class Form class Form #:nodoc:
attr_reader :element attr_reader :element
def initialize(session, element) def initialize(session, element)
@ -8,12 +11,10 @@ module Webrat
@fields = nil @fields = nil
end end
def find_field(id_or_name_or_label, *field_types) def field(locator, *field_types)
possible_fields = fields_by_type(field_types) field_with_id(locator, *field_types) ||
field_named(locator, *field_types) ||
find_field_by_id(possible_fields, id_or_name_or_label) || field_labeled(locator, *field_types) ||
find_field_by_name(possible_fields, id_or_name_or_label) ||
find_field_by_label(possible_fields, id_or_name_or_label) ||
nil nil
end end
@ -30,62 +31,49 @@ module Webrat
def find_button(value = nil) def find_button(value = nil)
return fields_by_type([ButtonField]).first if value.nil? return fields_by_type([ButtonField]).first if value.nil?
possible_buttons = fields_by_type([ButtonField]) possible_buttons = fields_by_type([ButtonField])
possible_buttons.detect { |possible_button| possible_button.matches_id?(value) } ||
possible_buttons.each do |possible_button| possible_buttons.detect { |possible_button| possible_button.matches_value?(value) }
return possible_button if possible_button.matches_value?(value)
end
nil
end end
def fields def fields
return @fields if @fields return @fields if @fields
@fields = [] @fields = (@element.search(".//button", ".//input", ".//textarea", ".//select")).collect do |field_element|
Field.class_for_element(field_element).new(self, field_element)
(@element / "button, input, textarea, select").each do |field_element|
@fields << Field.class_for_element(field_element).new(self, field_element)
end end
@fields
end end
def submit def submit
@session.request_page(form_action, form_method, params) @session.request_page(form_action, form_method, params)
end end
def field_with_id(id, *field_types)
possible_fields = fields_by_type(field_types)
possible_fields.detect { |possible_field| possible_field.matches_id?(id) }
end
def field_named(name, *field_types)
possible_fields = fields_by_type(field_types)
possible_fields.detect { |possible_field| possible_field.matches_name?(name) }
end
def field_labeled(label, *field_types)
possible_fields = fields_by_type(field_types)
matching_fields = possible_fields.select do |possible_field|
possible_field.matches_label?(label)
end
matching_fields.min { |a, b| a.label_text.length <=> b.label_text.length }
end
protected 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) def fields_by_type(field_types)
if field_types.any?
fields.select { |f| field_types.include?(f.class) } fields.select { |f| field_types.include?(f.class) }
else
fields
end
end end
def params def params
@ -107,10 +95,12 @@ module Webrat
@element["action"].blank? ? @session.current_url : @element["action"] @element["action"].blank? ? @session.current_url : @element["action"]
end end
HASH = [Hash, HashWithIndifferentAccess] rescue [Hash]
def merge(all_params, new_param) def merge(all_params, new_param)
new_param.each do |key, value| new_param.each do |key, value|
case all_params[key] case all_params[key]
when Hash, HashWithIndifferentAccess when *HASH
merge_hash_values(all_params[key], value) merge_hash_values(all_params[key], value)
when Array when Array
all_params[key] += value all_params[key] += value
@ -123,7 +113,7 @@ module Webrat
def merge_hash_values(a, b) # :nodoc: def merge_hash_values(a, b) # :nodoc:
a.keys.each do |k| a.keys.each do |k|
if b.has_key?(k) if b.has_key?(k)
case [a[k], b[k]].map(&:class) case [a[k], b[k]].map{|value| value.class}
when [Hash, Hash] when [Hash, Hash]
a[k] = merge_hash_values(a[k], b[k]) a[k] = merge_hash_values(a[k], b[k])
b.delete(k) b.delete(k)

View File

@ -1,5 +1,5 @@
module Webrat module Webrat
class Label class Label #:nodoc:
def initialize(field, element) def initialize(field, element)
@field = field @field = field
@ -11,7 +11,7 @@ module Webrat
end end
def text def text
@element.innerText @element.inner_text
end end
end end

View File

@ -1,13 +1,15 @@
require "webrat/core_extensions/blank"
module Webrat module Webrat
class Link class Link #:nodoc:
def initialize(session, element) def initialize(session, element)
@session = session @session = session
@element = element @element = element
end end
def click(method = nil, options = {}) def click(options = {})
method ||= http_method method = options[:method] || http_method
return if href =~ /^#/ && method == :get return if href =~ /^#/ && method == :get
options[:javascript] = true if options[:javascript].nil? options[:javascript] = true if options[:javascript].nil?
@ -20,13 +22,19 @@ module Webrat
end end
def matches_text?(link_text) def matches_text?(link_text)
html = text.gsub('&nbsp;',' ') html = text.gsub('&#xA0;',' ')
if link_text.is_a?(Regexp)
matcher = link_text
else
matcher = /#{Regexp.escape(link_text.to_s)}/i matcher = /#{Regexp.escape(link_text.to_s)}/i
end
html =~ matcher || title =~ matcher html =~ matcher || title =~ matcher
end end
def text def text
@element.innerHTML @element.inner_html
end end
protected protected

View File

@ -0,0 +1,92 @@
require "webrat/core_extensions/detect_mapped"
module Webrat
module Locators
def field(*args)
# This is the default locator strategy
find_field_with_id(*args) ||
find_field_named(*args) ||
field_labeled(*args) ||
flunk("Could not find field: #{args.inspect}")
end
def field_labeled(label, *field_types)
find_field_labeled(label, *field_types) ||
flunk("Could not find field labeled #{label.inspect}")
end
def field_named(name, *field_types)
find_field_named(name, *field_types) ||
flunk("Could not find field named #{name.inspect}")
end
def field_with_id(id, *field_types)
find_field_with_id(id, *field_types) ||
flunk("Could not find field with id #{id.inspect}")
end
def find_field_labeled(label, *field_types) #:nodoc:
forms.detect_mapped do |form|
form.field_labeled(label, *field_types)
end
end
def find_field_named(name, *field_types) #:nodoc:
forms.detect_mapped do |form|
form.field_named(name, *field_types)
end
end
def find_field_with_id(id, *field_types) #:nodoc:
forms.detect_mapped do |form|
form.field_with_id(id, *field_types)
end
end
def find_select_option(option_text, id_or_name_or_label) #:nodoc:
if id_or_name_or_label
field = field(id_or_name_or_label, SelectField)
return field.find_option(option_text)
else
select_option = forms.detect_mapped do |form|
form.find_select_option(option_text)
end
return select_option if select_option
end
flunk("Could not find option #{option_text.inspect}")
end
def find_button(value) #:nodoc:
button = forms.detect_mapped do |form|
form.find_button(value)
end
if button
return button
else
flunk("Could not find button #{value.inspect}")
end
end
def find_area(area_name) #:nodoc:
areas.detect { |area| area.matches_text?(area_name) } ||
flunk("Could not find area with name #{area_name}")
end
def find_link(text) #:nodoc:
matching_links = links.select do |possible_link|
possible_link.matches_text?(text)
end
if matching_links.any?
matching_links.min { |a, b| a.text.length <=> b.text.length }
else
flunk("Could not find link with text #{text.inspect}")
end
end
end
end

View File

@ -1,14 +1,21 @@
module Webrat module Webrat
module Logging module Logging #:nodoc:
def warn_log(message) # :nodoc:
return unless logger
logger.warn message
end
def debug_log(message) # :nodoc: def debug_log(message) # :nodoc:
return unless logger return unless logger
logger.debug(message) logger.debug message
end end
def logger # :nodoc: def logger # :nodoc:
if defined? RAILS_DEFAULT_LOGGER if defined? RAILS_DEFAULT_LOGGER
RAILS_DEFAULT_LOGGER RAILS_DEFAULT_LOGGER
elsif defined? Merb
Merb.logger
else else
nil nil
end end

View File

@ -0,0 +1,4 @@
require "webrat/core/matchers/have_xpath"
require "webrat/core/matchers/have_selector"
require "webrat/core/matchers/have_tag"
require "webrat/core/matchers/have_content"

View File

@ -0,0 +1,94 @@
module Webrat
module Matchers
class HasContent #:nodoc:
def initialize(content)
@content = content
end
def matches?(stringlike)
if defined?(Nokogiri::XML)
matches_nokogiri?(stringlike)
else
matches_rexml?(stringlike)
end
end
def matches_rexml?(stringlike)
@document = rexml_document(stringlike)
@element = @document.inner_text
case @content
when String
@element.include?(@content)
when Regexp
@element.match(@content)
end
end
def matches_nokogiri?(stringlike)
@document = Webrat.nokogiri_document(stringlike)
@element = @document.inner_text
case @content
when String
@element.include?(@content)
when Regexp
@element.match(@content)
end
end
def rexml_document(stringlike)
stringlike = stringlike.body.to_s if stringlike.respond_to?(:body)
case stringlike
when REXML::Document
stringlike.root
when REXML::Node
stringlike
when StringIO, String
begin
REXML::Document.new(stringlike.to_s).root
rescue REXML::ParseException => e
if e.message.include?("second root element")
REXML::Document.new("<fake-root-element>#{stringlike}</fake-root-element>").root
else
raise e
end
end
end
end
# ==== Returns
# String:: The failure message.
def failure_message
"expected the following element's content to #{content_message}:\n#{@element}"
end
# ==== Returns
# String:: The failure message to be displayed in negative matches.
def negative_failure_message
"expected the following element's content to not #{content_message}:\n#{@element}"
end
def content_message
case @content
when String
"include \"#{@content}\""
when Regexp
"match #{@content.inspect}"
end
end
end
# Matches the contents of an HTML document with
# whatever string is supplied
#
# ---
# @api public
def contain(content)
HasContent.new(content)
end
end
end

View File

@ -0,0 +1,39 @@
module Webrat
module Matchers
class HaveSelector < HaveXpath #:nodoc:
# ==== Returns
# String:: The failure message.
def failure_message
"expected following text to match selector #{@expected}:\n#{@document}"
end
# ==== Returns
# String:: The failure message to be displayed in negative matches.
def negative_failure_message
"expected following text to not match selector #{@expected}:\n#{@document}"
end
def query
Nokogiri::CSS::Parser.parse(*super).map { |ast| ast.to_xpath }
end
end
# Matches HTML content against a CSS 3 selector.
#
# ==== Parameters
# expected<String>:: The CSS selector to look for.
#
# ==== Returns
# HaveSelector:: A new have selector matcher.
# ---
# @api public
def have_selector(expected, &block)
HaveSelector.new(expected, &block)
end
alias_method :match_selector, :have_selector
end
end

View File

@ -0,0 +1,58 @@
module Webrat
module HaveTagMatcher
class HaveTag < ::Webrat::Matchers::HaveSelector #:nodoc:
# ==== Returns
# String:: The failure message.
def failure_message
"expected following output to contain a #{tag_inspect} tag:\n#{@document}"
end
# ==== Returns
# String:: The failure message to be displayed in negative matches.
def negative_failure_message
"expected following output to omit a #{tag_inspect}:\n#{@document}"
end
def tag_inspect
options = @expected.last.dup
content = options.delete(:content)
html = "<#{@expected.first}"
options.each do |k,v|
html << " #{k}='#{v}'"
end
if content
html << ">#{content}</#{@expected.first}>"
else
html << "/>"
end
html
end
def query
options = @expected.last.dup
selector = @expected.first.to_s
selector << ":contains('#{options.delete(:content)}')" if options[:content]
options.each do |key, value|
selector << "[#{key}='#{value}']"
end
Nokogiri::CSS::Parser.parse(selector).map { |ast| ast.to_xpath }
end
end
def have_tag(name, attributes = {}, &block)
HaveTag.new([name, attributes], &block)
end
alias_method :match_tag, :have_tag
end
end

View File

@ -0,0 +1,85 @@
require "webrat/core/nokogiri"
require "webrat/core/rexml"
module Webrat
module Matchers
class HaveXpath #:nodoc:
def initialize(expected, &block)
@expected = expected
@block = block
end
def matches?(stringlike)
if defined?(Nokogiri::XML)
matches_nokogiri?(stringlike)
else
matches_rexml?(stringlike)
end
end
def matches_rexml?(stringlike)
if REXML::Node === stringlike || Array === stringlike
@query = query.map { |q| q.gsub(%r'//', './') }
else
@query = query
end
@document = Webrat.rexml_document(stringlike)
matched = @query.map do |q|
if @document.is_a?(Array)
@document.map { |d| REXML::XPath.match(d, q) }
else
REXML::XPath.match(@document, q)
end
end.flatten.compact
matched.any? && (!@block || @block.call(matched))
end
def matches_nokogiri?(stringlike)
if Nokogiri::XML::NodeSet === stringlike
@query = query.map { |q| q.gsub(%r'//', './') }
else
@query = query
end
@document = Webrat.nokogiri_document(stringlike)
matched = @document.xpath(*@query)
matched.any? && (!@block || @block.call(matched))
end
def query
[@expected].flatten.compact
end
# ==== Returns
# String:: The failure message.
def failure_message
"expected following text to match xpath #{@expected}:\n#{@document}"
end
# ==== Returns
# String:: The failure message to be displayed in negative matches.
def negative_failure_message
"expected following text to not match xpath #{@expected}:\n#{@document}"
end
end
# Matches HTML content against an XPath query
#
# ==== Parameters
# expected<String>:: The XPath query to look for.
#
# ==== Returns
# HaveXpath:: A new have xpath matcher.
# ---
# @api public
def have_xpath(expected, &block)
HaveXpath.new(expected, &block)
end
alias_method :match_xpath, :have_xpath
end
end

View File

@ -0,0 +1,44 @@
module Webrat
module Methods #:nodoc:
def self.delegate_to_session(*meths)
meths.each do |meth|
self.class_eval <<-RUBY
def #{meth}(*args, &blk)
@_webrat_session ||= ::Webrat::MerbSession.new
@_webrat_session.#{meth}(*args, &blk)
end
RUBY
end
end
# all of these methods delegate to the @session, which should
# be created transparently.
#
# Note that when using Webrat, #request also uses @session, so
# that #request and webrat native functions behave interchangably
delegate_to_session \
:visits, :visit,
:within,
:header, :http_accept, :basic_auth,
:save_and_open_page,
:fill_in,
:check,
:uncheck,
:choose,
:select,
:attach_file,
:cookies,
:response,
:current_page,
:current_url,
:click_link,
:click_area,
:click_button,
:reload, :reloads,
:clicks_link_within,
:field_labeled
end
end

29
lib/webrat/core/mime.rb Normal file
View File

@ -0,0 +1,29 @@
module Webrat
module MIME
def self.mime_type(string_or_symbol)
if string_or_symbol.is_a?(String)
string_or_symbol
else
case string_or_symbol
when :text then "text/plain"
when :html then "text/html"
when :js then "text/javascript"
when :css then "text/css"
when :ics then "text/calendar"
when :csv then "text/csv"
when :xml then "application/xml"
when :rss then "application/rss+xml"
when :atom then "application/atom+xml"
when :yaml then "application/x-yaml"
when :multipart_form then "multipart/form-data"
when :url_encoded_form then "application/x-www-form-urlencoded"
when :json then "application/json"
else
raise ArgumentError.new("Invalid Mime type: #{string_or_symbol.inspect}")
end
end
end
end
end

View File

@ -0,0 +1,44 @@
require "webrat/core_extensions/meta_class"
module Webrat
def self.nokogiri_document(stringlike) #:nodoc:
return stringlike.dom if stringlike.respond_to?(:dom)
if Nokogiri::HTML::Document === stringlike
stringlike
elsif Nokogiri::XML::NodeSet === stringlike
stringlike
elsif StringIO === stringlike
Nokogiri::HTML(stringlike.string)
elsif stringlike.respond_to?(:body)
Nokogiri::HTML(stringlike.body.to_s)
else
Nokogiri::HTML(stringlike.to_s)
end
end
def self.define_dom_method(object, dom) #:nodoc:
object.meta_class.send(:define_method, :dom) do
dom
end
end
end
module Nokogiri
module CSS
class XPathVisitor
def visit_pseudo_class_text(node) #:nodoc:
"@type='text'"
end
def visit_pseudo_class_password(node) #:nodoc:
"@type='password'"
end
end
end
end

24
lib/webrat/core/rexml.rb Normal file
View File

@ -0,0 +1,24 @@
module Webrat
def self.rexml_document(stringlike)
stringlike = stringlike.body.to_s if stringlike.respond_to?(:body)
case stringlike
when REXML::Document
stringlike.root
when REXML::Node, Array
stringlike
else
begin
REXML::Document.new(stringlike.to_s).root
rescue REXML::ParseException => e
if e.message.include?("second root element")
REXML::Document.new("<fake-root-element>#{stringlike}</fake-root-element>").root
else
raise e
end
end
end
end
end

View File

@ -1,64 +1,81 @@
require "hpricot" require "webrat/core/form"
require "webrat/core/locators"
module Webrat module Webrat
class Scope class Scope
include Logging include Logging
include Flunk include Flunk
include Locators
def initialize(session, html, selector = nil) def self.from_page(session, response, response_body) #:nodoc:
@session = session new(session) do
@html = html @response = response
@response_body = response_body
end
end
def self.from_scope(session, scope, selector) #:nodoc:
new(session) do
@scope = scope
@selector = selector @selector = selector
end end
end
def initialize(session, &block) #:nodoc:
@session = session
instance_eval(&block) if block_given?
end
# Verifies an input field or textarea exists on the current page, and stores a value for # 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. # it which will be sent when the form is submitted.
# #
# Examples: # Examples:
# fills_in "Email", :with => "user@example.com" # fill_in "Email", :with => "user@example.com"
# fills_in "user[email]", :with => "user@example.com" # fill_in "user[email]", :with => "user@example.com"
# #
# The field value is required, and must be specified in <tt>options[:with]</tt>. # 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>) # <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. # 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 = {}) def fill_in(field_locator, options = {})
find_field(id_or_name_or_label, TextField, TextareaField, PasswordField).set(options[:with]) field = locate_field(field_locator, TextField, TextareaField, PasswordField)
field.raise_error_if_disabled
field.set(options[:with])
end end
alias_method :fill_in, :fills_in alias_method :fills_in, :fill_in
# Verifies that an input checkbox exists on the current page and marks it # 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. # as checked, so that the value will be submitted with the form.
# #
# Example: # Example:
# checks 'Remember Me' # check 'Remember Me'
def checks(id_or_name_or_label) def check(field_locator)
find_field(id_or_name_or_label, CheckboxField).check locate_field(field_locator, CheckboxField).check
end end
alias_method :check, :checks alias_method :checks, :check
# Verifies that an input checkbox exists on the current page and marks it # 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. # as unchecked, so that the value will not be submitted with the form.
# #
# Example: # Example:
# unchecks 'Remember Me' # uncheck 'Remember Me'
def unchecks(id_or_name_or_label) def uncheck(field_locator)
find_field(id_or_name_or_label, CheckboxField).uncheck locate_field(field_locator, CheckboxField).uncheck
end end
alias_method :uncheck, :unchecks alias_method :unchecks, :uncheck
# Verifies that an input radio button exists on the current page and marks it # 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. # as checked, so that the value will be submitted with the form.
# #
# Example: # Example:
# chooses 'First Option' # choose 'First Option'
def chooses(label) def choose(field_locator)
find_field(label, RadioField).choose locate_field(field_locator, RadioField).choose
end end
alias_method :choose, :chooses alias_method :chooses, :choose
# Verifies that a an option element exists on the current page with the specified # 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 # text. You can optionally restrict the search to a specific select list by
@ -82,93 +99,64 @@ module Webrat
# Example: # Example:
# attaches_file "Resume", "/path/to/the/resume.txt" # attaches_file "Resume", "/path/to/the/resume.txt"
# attaches_file "Photo", "/path/to/the/image.png", "image/png" # attaches_file "Photo", "/path/to/the/image.png", "image/png"
def attaches_file(id_or_name_or_label, path, content_type = nil) def attach_file(field_locator, path, content_type = nil)
find_field(id_or_name_or_label, FileField).set(path, content_type) locate_field(field_locator, FileField).set(path, content_type)
end end
alias_method :attach_file, :attaches_file alias_method :attaches_file, :attach_file
def click_area(area_name)
find_area(area_name).click
end
alias_method :clicks_area, :click_area
# Issues a request for the URL pointed to by a link on the current page, # 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. # follows any redirects, and verifies the final page load was successful.
# #
# clicks_link has very basic support for detecting Rails-generated # click_link has very basic support for detecting Rails-generated
# JavaScript onclick handlers for PUT, POST and DELETE links, as well as # JavaScript onclick handlers for PUT, POST and DELETE links, as well as
# CSRF authenticity tokens if they are present. # CSRF authenticity tokens if they are present.
# #
# Javascript imitation can be disabled by passing the option :javascript => false # Javascript imitation can be disabled by passing the option :javascript => false
# #
# Example: # Passing a :method in the options hash overrides the HTTP method used
# clicks_link "Sign up" # for making the link request
#
# clicks_link "Sign up", :javascript => false
def clicks_link(link_text, options = {})
find_link(link_text).click(nil, options)
end
alias_method :click_link, :clicks_link
# Works like clicks_link, but forces a GET request
# #
# Example: # Example:
# clicks_get_link "Log out" # click_link "Sign up"
def clicks_get_link(link_text)
find_link(link_text).click(:get)
end
alias_method :click_get_link, :clicks_get_link
# Works like clicks_link, but issues a DELETE request instead of a GET
# #
# Example: # click_link "Sign up", :javascript => false
# clicks_delete_link "Log out"
def clicks_delete_link(link_text)
find_link(link_text).click(:delete)
end
alias_method :click_delete_link, :clicks_delete_link
# Works like clicks_link, but issues a POST request instead of a GET
# #
# Example: # click_link "Sign up", :method => :put
# clicks_post_link "Vote" def click_link(link_text, options = {})
def clicks_post_link(link_text) find_link(link_text).click(options)
find_link(link_text).click(:post)
end end
alias_method :click_post_link, :clicks_post_link alias_method :clicks_link, :click_link
# 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)
find_link(link_text).click(:put)
end
alias_method :click_put_link, :clicks_put_link
# Verifies that a submit button exists for the form, then submits the form, follows # Verifies that a submit button exists for the form, then submits the form, follows
# any redirects, and verifies the final page was successful. # any redirects, and verifies the final page was successful.
# #
# Example: # Example:
# clicks_button "Login" # click_button "Login"
# clicks_button # click_button
# #
# The URL and HTTP method for the form submission are automatically read from the # 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. # <tt>action</tt> and <tt>method</tt> attributes of the <tt><form></tt> element.
def clicks_button(value = nil) def click_button(value = nil)
find_button(value).click find_button(value).click
end end
alias_method :click_button, :clicks_button alias_method :clicks_button, :click_button
def dom # :nodoc: def dom # :nodoc:
return @dom if defined?(@dom) && @dom return @dom if @dom
@dom = Hpricot(@html)
if @selector if @selector
html = (@dom / @selector).first.to_html @dom = scoped_dom
@dom = Hpricot(html) else
@dom = page_dom
end end
return @dom return @dom
@ -176,62 +164,41 @@ module Webrat
protected protected
def find_select_option(option_text, id_or_name_or_label) def page_dom #:nodoc:
if id_or_name_or_label return @response.dom if @response.respond_to?(:dom)
field = find_field(id_or_name_or_label, SelectField) dom = Webrat.nokogiri_document(@response_body)
return field.find_option(option_text) Webrat.define_dom_method(@response, dom)
return dom
end
def scoped_dom #:nodoc:
Webrat.nokogiri_document(@scope.dom.search(@selector).first.to_html)
end
def locate_field(field_locator, *field_types) #:nodoc:
if field_locator.is_a?(Field)
field_locator
else else
forms.each do |form| field(field_locator, *field_types)
result = form.find_select_option(option_text)
return result if result
end end
end end
flunk("Could not find option #{option_text.inspect}") def areas #:nodoc:
end dom.search("area").map do |element|
Area.new(@session, element)
def find_button(value)
forms.each do |form|
button = form.find_button(value)
return button if button
end
flunk("Could not find button #{value.inspect}")
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
end end
def find_field(id_or_name_or_label, *field_types) def links #:nodoc:
forms.each do |form| dom.search("a[@href]").map do |link_element|
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 links_within(selector)
(dom / selector / "a[@href]").map do |link_element|
Link.new(@session, link_element) Link.new(@session, link_element)
end end
end end
def forms def forms #:nodoc:
return @forms if @forms return @forms if @forms
@forms = (dom / "form").map do |form_element| @forms = dom.search("form").map do |form_element|
Form.new(@session, form_element) Form.new(@session, form_element)
end end
end end

View File

@ -1,5 +1,5 @@
module Webrat module Webrat
class SelectOption class SelectOption #:nodoc:
def initialize(select, element) def initialize(select, element)
@select = select @select = select
@ -8,20 +8,21 @@ module Webrat
def matches_text?(text) def matches_text?(text)
if text.is_a?(Regexp) if text.is_a?(Regexp)
@element.innerHTML =~ text @element.inner_html =~ text
else else
@element.innerHTML == text.to_s @element.inner_html == text.to_s
end end
end end
def choose def choose
@select.raise_error_if_disabled
@select.set(value) @select.set(value)
end end
protected protected
def value def value
@element["value"] || @element.innerHTML @element["value"] || @element.inner_html
end end
end end

View File

@ -1,17 +1,23 @@
require "forwardable" require "forwardable"
require "ostruct" require "ostruct"
require "webrat/core/mime"
module Webrat module Webrat
class PageLoadError < WebratError
end
class Session class Session
extend Forwardable extend Forwardable
include Logging include Logging
include Flunk
attr_reader :current_url attr_reader :current_url
def initialize def initialize #:nodoc:
@http_method = :get @http_method = :get
@data = {} @data = {}
@default_headers = {}
@custom_headers = {}
end end
# Saves the page out to RAILS_ROOT/tmp/ and opens it in the default # Saves the page out to RAILS_ROOT/tmp/ and opens it in the default
@ -31,12 +37,12 @@ module Webrat
open_in_browser(filename) open_in_browser(filename)
end end
def current_dom def current_dom #:nodoc:
current_scope.dom current_scope.dom
end end
# For backwards compatibility -- removing in 1.0 # For backwards compatibility -- removing in 1.0
def current_page def current_page #:nodoc:
page = OpenStruct.new page = OpenStruct.new
page.url = @current_url page.url = @current_url
page.http_method = @http_method page.http_method = @http_method
@ -44,41 +50,64 @@ module Webrat
page page
end end
def doc_root def doc_root #:nodoc:
nil nil
end end
def saved_page_dir def saved_page_dir #:nodoc:
File.expand_path(".") File.expand_path(".")
end end
def request_page(url, http_method, data) def header(key, value)
debug_log "REQUESTING PAGE: #{http_method.to_s.upcase} #{url} with #{data.inspect}" @custom_headers[key] = value
if @current_url end
send "#{http_method}", url, data || {}, {"HTTP_REFERER" => @current_url}
else def http_accept(mime_type)
header('Accept', Webrat::MIME.mime_type(mime_type))
end
def basic_auth(user, pass)
encoded_login = ["#{user}:#{pass}"].pack("m*")
header('HTTP_AUTHORIZATION', "Basic #{encoded_login}")
end
def headers #:nodoc:
@default_headers.dup.merge(@custom_headers.dup)
end
def request_page(url, http_method, data) #:nodoc:
h = headers
h['HTTP_REFERER'] = @current_url if @current_url
debug_log "REQUESTING PAGE: #{http_method.to_s.upcase} #{url} with #{data.inspect} and HTTP headers #{h.inspect}"
if h.empty?
send "#{http_method}", url, data || {} send "#{http_method}", url, data || {}
else
send "#{http_method}", url, data || {}, h
end end
save_and_open_page if exception_caught? save_and_open_page if exception_caught?
flunk("Page load was not successful (Code: #{response_code.inspect})") unless success_code? raise PageLoadError.new("Page load was not successful (Code: #{response_code.inspect}):\n#{formatted_error}") unless success_code?
@scope = nil @_scopes = nil
@_page_scope = nil
@current_url = url @current_url = url
@http_method = http_method @http_method = http_method
@data = data @data = data
return response
end end
def success_code? def success_code? #:nodoc:
(200..299).include?(response_code) (200..499).include?(response_code)
end end
def exception_caught? def exception_caught? #:nodoc:
response_body =~ /Exception caught/ response_body =~ /Exception caught/
end end
def current_scope def current_scope #:nodoc:
@scope ||= Scope.new(self, response_body) scopes.last || page_scope
end end
# Reloads the last page requested. Note that this will resubmit forms # Reloads the last page requested. Note that this will resubmit forms
@ -93,49 +122,69 @@ module Webrat
alias_method :reload, :reloads alias_method :reload, :reloads
# Works like clicks_link, but only looks for the link text within a given selector # Works like click_link, but only looks for the link text within a given selector
# #
# Example: # Example:
# clicks_link_within "#user_12", "Vote" # click_link_within "#user_12", "Vote"
def clicks_link_within(selector, link_text) def click_link_within(selector, link_text)
within(selector) do |scope| within(selector) do
scope.clicks_link(link_text) click_link(link_text)
end end
end end
alias_method :click_link_within, :clicks_link_within alias_method :clicks_link_within, :click_link_within
def within(selector) def within(selector)
yield Scope.new(self, response_body, selector) scopes.push(Scope.from_scope(self, current_scope, selector))
ret = yield(current_scope)
scopes.pop
return ret
end end
def visits(url = nil, http_method = :get, data = {}) # Issues a GET request for a page, follows any redirects, and verifies the final page
# load was successful.
#
# Example:
# visit "/"
def visit(url = nil, http_method = :get, data = {})
request_page(url, http_method, data) request_page(url, http_method, data)
end end
alias_method :visit, :visits alias_method :visits, :visit
def open_in_browser(path) # :nodoc def open_in_browser(path) #:nodoc
`open #{path}` `open #{path}`
end end
def rewrite_css_and_image_references(response_html) # :nodoc def rewrite_css_and_image_references(response_html) #:nodoc
return response_html unless doc_root return response_html unless doc_root
response_html.gsub(/"\/(stylesheets|images)/, doc_root + '/\1') response_html.gsub(/"\/(stylesheets|images)/, doc_root + '/\1')
end end
# Subclasses can override this to show error messages without html
def formatted_error #:nodoc:
response_body
end
def scopes #:nodoc:
@_scopes ||= []
end
def page_scope #:nodoc:
@_page_scope ||= Scope.from_page(self, response, response_body)
end
def_delegators :current_scope, :fill_in, :fills_in def_delegators :current_scope, :fill_in, :fills_in
def_delegators :current_scope, :check, :checks def_delegators :current_scope, :check, :checks
def_delegators :current_scope, :uncheck, :unchecks def_delegators :current_scope, :uncheck, :unchecks
def_delegators :current_scope, :choose, :chooses def_delegators :current_scope, :choose, :chooses
def_delegators :current_scope, :select, :selects def_delegators :current_scope, :select, :selects
def_delegators :current_scope, :attach_file, :attaches_file def_delegators :current_scope, :attach_file, :attaches_file
def_delegators :current_scope, :click_area, :clicks_area
def_delegators :current_scope, :click_link, :clicks_link def_delegators :current_scope, :click_link, :clicks_link
def_delegators :current_scope, :click_get_link, :clicks_get_link
def_delegators :current_scope, :click_delete_link, :clicks_delete_link
def_delegators :current_scope, :click_post_link, :clicks_post_link
def_delegators :current_scope, :click_put_link, :clicks_put_link
def_delegators :current_scope, :click_button, :clicks_button def_delegators :current_scope, :click_button, :clicks_button
def_delegators :current_scope, :should_see
def_delegators :current_scope, :should_not_see
def_delegators :current_scope, :field_labeled
end end
end end

View File

@ -0,0 +1,58 @@
class Object #:nodoc:
# An object is blank if it's false, empty, or a whitespace string.
# For example, "", " ", +nil+, [], and {} are blank.
#
# This simplifies
#
# if !address.nil? && !address.empty?
#
# to
#
# if !address.blank?
def blank?
respond_to?(:empty?) ? empty? : !self
end
# An object is present if it's not blank.
def present?
!blank?
end
end
class NilClass #:nodoc:
def blank?
true
end
end
class FalseClass #:nodoc:
def blank?
true
end
end
class TrueClass #:nodoc:
def blank?
false
end
end
class Array #:nodoc:
alias_method :blank?, :empty?
end
class Hash #:nodoc:
alias_method :blank?, :empty?
end
class String #:nodoc:
def blank?
self !~ /\S/
end
end
class Numeric #:nodoc:
def blank?
false
end
end

View File

@ -0,0 +1,8 @@
class Module #:nodoc:
def deprecate(old_method_name, new_method_name)
define_method old_method_name do |*args|
warn "#{old_method_name} is deprecated. Use #{new_method_name} instead."
__send__(new_method_name, *args)
end
end
end

View File

@ -0,0 +1,12 @@
class Array #:nodoc:
def detect_mapped
each do |element|
result = yield element
return result if result
end
return nil
end
end

View File

@ -0,0 +1,131 @@
# This class has dubious semantics and we only have it so that
# people can write params[:key] instead of params['key']
# and they get the same value for both keys.
class HashWithIndifferentAccess < Hash #:nodoc:
def initialize(constructor = {})
if constructor.is_a?(Hash)
super()
update(constructor)
else
super(constructor)
end
end
def default(key = nil)
if key.is_a?(Symbol) && include?(key = key.to_s)
self[key]
else
super
end
end
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
alias_method :regular_update, :update unless method_defined?(:regular_update)
#
# Assigns a new value to the hash.
#
# Example:
#
# hash = HashWithIndifferentAccess.new
# hash[:key] = "value"
#
def []=(key, value)
regular_writer(convert_key(key), convert_value(value))
end
#
# Updates the instantized hash with values from the second.
#
# Example:
#
# >> hash_1 = HashWithIndifferentAccess.new
# => {}
#
# >> hash_1[:key] = "value"
# => "value"
#
# >> hash_2 = HashWithIndifferentAccess.new
# => {}
#
# >> hash_2[:key] = "New Value!"
# => "New Value!"
#
# >> hash_1.update(hash_2)
# => {"key"=>"New Value!"}
#
def update(other_hash)
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
self
end
alias_method :merge!, :update
# Checks the hash for a key matching the argument passed in
def key?(key)
super(convert_key(key))
end
alias_method :include?, :key?
alias_method :has_key?, :key?
alias_method :member?, :key?
# Fetches the value for the specified key, same as doing hash[key]
def fetch(key, *extras)
super(convert_key(key), *extras)
end
# Returns an array of the values at the specified indicies.
def values_at(*indices)
indices.collect {|key| self[convert_key(key)]}
end
# Returns an exact copy of the hash.
def dup
HashWithIndifferentAccess.new(self)
end
# Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
# Does not overwrite the existing hash.
def merge(hash)
self.dup.update(hash)
end
# Removes a specified key from the hash.
def delete(key)
super(convert_key(key))
end
def stringify_keys!; self end
def symbolize_keys!; self end
def to_options!; self end
# Convert to a Hash with String keys.
def to_hash
Hash.new(default).merge(self)
end
protected
def convert_key(key)
key.kind_of?(Symbol) ? key.to_s : key
end
def convert_value(value)
case value
when Hash
value.with_indifferent_access
when Array
value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
else
value
end
end
end
class Hash #:nodoc:
def with_indifferent_access
hash = HashWithIndifferentAccess.new(self)
hash.default = self.default
hash
end
end

View File

@ -0,0 +1,6 @@
class ::Object #:nodoc:
def meta_class
class << self; self end
end
end

View File

@ -0,0 +1,5 @@
class NilClass #:nodoc:
def to_param
nil
end
end

View File

@ -1,5 +1,28 @@
require "rubygems"
require "mechanize" require "mechanize"
require File.dirname(__FILE__) + "/mechanize/mechanize_session" module Webrat
class MechanizeSession < Session #:nodoc:
def initialize(mechanize = WWW::Mechanize.new)
super()
@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

@ -1,25 +0,0 @@
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

75
lib/webrat/merb.rb Normal file
View File

@ -0,0 +1,75 @@
require "webrat/core"
require "cgi"
gem "extlib"
require "extlib"
require "merb-core"
HashWithIndifferentAccess = Mash
module Webrat
class MerbSession < Session #:nodoc:
include Merb::Test::MakeRequest
attr_accessor :response
def get(url, data, headers = nil)
do_request(url, data, headers, "GET")
end
def post(url, data, headers = nil)
do_request(url, data, headers, "POST")
end
def put(url, data, headers = nil)
do_request(url, data, headers, "PUT")
end
def delete(url, data, headers = nil)
do_request(url, data, headers, "DELETE")
end
def response_body
@response.body.to_s
end
def response_code
@response.status
end
def do_request(url, data, headers, method)
@response = request(url,
:params => (data && data.any?) ? data : nil,
:headers => headers,
:method => method)
follow_redirect
end
def follow_redirect
self.get(@response.headers['Location'], nil, @response.headers) if @response.status == 302
end
end
end
module Merb
module Test
module RequestHelper #:nodoc:
def request(uri, env = {})
@_webrat_session ||= Webrat::MerbSession.new
@_webrat_session.response = @_webrat_session.request(uri, env)
end
def follow_redirect
@_webrat_session.follow_redirect
end
end
end
end
class Merb::Test::RspecStory #:nodoc:
def browser
@browser ||= Webrat::MerbSession.new
end
end

24
lib/webrat/rack.rb Normal file
View File

@ -0,0 +1,24 @@
require 'webrat'
class CGIMethods #:nodoc:
def self.parse_query_parameters(params)
hash = {}
params.split('&').each do |p|
pair = p.split('=')
hash[pair[0]] = pair[1]
end
hash
end
end
module Webrat
class RackSession < Session #:nodoc:
def response_body
@response.body
end
def response_code
@response.status
end
end
end

View File

@ -1,3 +1,102 @@
require File.dirname(__FILE__) + "/rails/redirect_actions" require "webrat"
require File.dirname(__FILE__) + "/rails/rails_session"
require File.dirname(__FILE__) + "/rails/session" module Webrat
class RailsSession < Session #:nodoc:
def initialize(integration_session)
super()
@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, headers = nil)
do_request(:get, url, data, headers)
end
def post(url, data, headers = nil)
do_request(:post, url, data, headers)
end
def put(url, data, headers = nil)
do_request(:put, url, data, headers)
end
def delete(url, data, headers = nil)
do_request(:delete, url, data, headers)
end
def response_body
response.body
end
def response_code
response.code.to_i
end
protected
def do_request(http_method, url, data, headers) #:nodoc:
update_protocol(url)
@integration_session.request_via_redirect(http_method, remove_protocol(url), data, headers)
end
def remove_protocol(href) #:nodoc:
if href =~ %r{^https?://www.example.com(/.*)}
$LAST_MATCH_INFO.captures.first
else
href
end
end
def update_protocol(href) #:nodoc:
if href =~ /^https:/
@integration_session.https!(true)
elsif href =~ /^http:/
@integration_session.https!(false)
end
end
def response #:nodoc:
@integration_session.response
end
end
end
module ActionController
module Integration
class Session #:nodoc:
unless instance_methods.include?("put_via_redirect")
require "webrat/rails/redirect_actions"
include Webrat::RedirectActions
end
def respond_to?(name)
super || webrat_session.respond_to?(name)
end
def method_missing(name, *args, &block)
if webrat_session.respond_to?(name)
webrat_session.send(name, *args, &block)
else
super
end
end
protected
def webrat_session
@webrat_session ||= Webrat::RailsSession.new(self)
end
end
end
end

View File

@ -1,68 +0,0 @@
module Webrat
class RailsSession < Session
def initialize(integration_session)
super()
@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, headers = nil)
update_protocol(url)
@integration_session.get_via_redirect(remove_protocol(url), data, headers)
end
def post(url, data, headers = nil)
update_protocol(url)
@integration_session.post_via_redirect(remove_protocol(url), data, headers)
end
def put(url, data, headers = nil)
update_protocol(url)
@integration_session.put_via_redirect(remove_protocol(url), data, headers)
end
def delete(url, data, headers = nil)
update_protocol(url)
@integration_session.delete_via_redirect(remove_protocol(url), data, headers)
end
def response_body
response.body
end
def response_code
response.code.to_i
end
protected
def remove_protocol(href)
if href =~ %r{^https?://www.example.com(/.*)}
$LAST_MATCH_INFO.captures.first
else
href
end
end
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

@ -1,6 +1,6 @@
# For Rails before http://dev.rubyonrails.org/ticket/10497 was committed # For Rails before http://dev.rubyonrails.org/ticket/10497 was committed
module Webrat module Webrat
module RedirectActions module RedirectActions #:nodoc:
def put_via_redirect(path, parameters = {}, headers = {}) def put_via_redirect(path, parameters = {}, headers = {})
put path, parameters, headers put path, parameters, headers

View File

@ -1,37 +0,0 @@
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_session.visits(*args)
end
def respond_to?(name)
super || webrat_session.respond_to?(name)
end
def method_missing(name, *args, &block)
if webrat_session.respond_to?(name)
webrat_session.send(name, *args, &block)
else
super
end
end
protected
def webrat_session
@webrat_session ||= Webrat::RailsSession.new(self)
end
end
end
end

View File

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

View File

@ -0,0 +1,12 @@
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;
});

View File

@ -0,0 +1,16 @@
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');
if ((labelFor == null) && (locatedLabel.hasChildNodes())) {
return locatedLabel.firstChild; //TODO: should find the first form field, not just any node
}
return selenium.browserbot.locationStrategies['id'].call(this, labelFor, inDocument, inWindow);

View File

@ -0,0 +1,5 @@
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;

View File

@ -0,0 +1,9 @@
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();

View File

@ -0,0 +1,15 @@
var locatorParts = locator.split('|');
var cssAncestor = locatorParts[0];
var linkText = locatorParts[1];
var matchingElements = cssQuery(cssAncestor, inDocument);
var candidateLinks = matchingElements.collect(function(ancestor){
var links = ancestor.getElementsByTagName('a');
return $A(links).select(function(candidateLink) {
return PatternMatcher.matches(linkText, getText(candidateLink));
});
}).flatten().compact();
if (candidateLinks.length == 0) {
return null;
}
candidateLinks = candidateLinks.sortBy(function(s) { return s.length * -1; }); //reverse length sort
return candidateLinks.first();

View File

@ -0,0 +1,5 @@
var optionElements = inDocument.getElementsByTagName('option');
var locatedOption = $A(optionElements).find(function(candidate){
return (PatternMatcher.matches(locator, getText(candidate)));
});
return locatedOption ? locatedOption.parentNode : null;

View File

@ -0,0 +1,6 @@
PatternMatcher.strategies['evalregex'] = function(regexpString) {
this.regexp = eval(regexpString);
this.matches = function(actual) {
return this.regexp.test(actual);
};
};

View File

@ -1,42 +1,57 @@
module Webrat module Webrat
class SeleniumSession < Session class SeleniumSession
def initialize(selenium_driver) def initialize(selenium_driver) #:nodoc:
super
@selenium = selenium_driver @selenium = selenium_driver
extend_selenium
define_location_strategies define_location_strategies
end end
def visits(url) def visit(url)
@selenium.open(url) @selenium.open(url)
end end
def fills_in(field_identifier, options) alias_method :visits, :visit
def fill_in(field_identifier, options)
locator = "webrat=#{Regexp.escape(field_identifier)}" locator = "webrat=#{Regexp.escape(field_identifier)}"
@selenium.type(locator, "#{options[:with]}") @selenium.type(locator, "#{options[:with]}")
end end
def response_body alias_method :fills_in, :fill_in
def response_body #:nodoc:
@selenium.get_html_source @selenium.get_html_source
end end
def clicks_button(button_text = nil, options = {}) def click_button(button_text_or_regexp = nil, options = {})
button_text, options = nil, button_text if button_text.is_a?(Hash) && options == {} if button_text_or_regexp.is_a?(Hash) && options == {}
button_text ||= '*' pattern, options = nil, button_text_or_regexp
@selenium.click("button=#{button_text}") else
pattern = adjust_if_regexp(button_text_or_regexp)
end
pattern ||= '*'
@selenium.click("button=#{pattern}")
wait_for_result(options[:wait]) wait_for_result(options[:wait])
end end
def clicks_link(link_text, options = {}) alias_method :clicks_button, :click_button
@selenium.click("webratlink=#{link_text}")
def click_link(link_text_or_regexp, options = {})
pattern = adjust_if_regexp(link_text_or_regexp)
@selenium.click("webratlink=#{pattern}")
wait_for_result(options[:wait]) wait_for_result(options[:wait])
end end
def clicks_link_within(selector, link_text, options = {}) alias_method :clicks_link, :click_link
def click_link_within(selector, link_text, options = {})
@selenium.click("webratlinkwithin=#{selector}|#{link_text}") @selenium.click("webratlinkwithin=#{selector}|#{link_text}")
wait_for_result(options[:wait]) wait_for_result(options[:wait])
end end
alias_method :clicks_link_within, :click_link_within
def wait_for_result(wait_type) def wait_for_result(wait_type)
if wait_type == :ajax if wait_type == :ajax
wait_for_ajax wait_for_ajax
@ -52,7 +67,7 @@ module Webrat
end end
def wait_for_ajax(timeout = 15000) def wait_for_ajax(timeout = 15000)
@selenium.wait_for_condition "window.Ajax.activeRequestCount == 0", timeout @selenium.wait_for_condition "Ajax.activeRequestCount == 0", timeout
end end
def wait_for_effects(timeout = 15000) def wait_for_effects(timeout = 15000)
@ -75,94 +90,48 @@ module Webrat
@selenium.select(select_locator, option_text) @selenium.select(select_locator, option_text)
end end
def chooses(label_text) def choose(label_text)
@selenium.click("webrat=#{label_text}") @selenium.click("webrat=#{label_text}")
end end
def checks(label_text) alias_method :chooses, :choose
def check(label_text)
@selenium.check("webrat=#{label_text}") @selenium.check("webrat=#{label_text}")
end end
alias_method :checks, :check
def is_ordered(*args) #:nodoc:
@selenium.is_ordered(*args)
end
def dragdrop(*args) #:nodoc:
@selenium.dragdrop(*args)
end
protected protected
def define_location_strategies def adjust_if_regexp(text_or_regexp) #:nodoc:
@selenium.add_location_strategy('label', <<-JS) if text_or_regexp.is_a?(Regexp)
var allLabels = inDocument.getElementsByTagName("label"); "evalregex:#{text_or_regexp.inspect}"
var candidateLabels = $A(allLabels).select(function(candidateLabel){ else
var regExp = new RegExp('^' + locator + '\\\\b', 'i'); text_or_regexp
var labelText = getText(candidateLabel).strip(); end
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('webratlinkwithin', <<-JS)
var locatorParts = locator.split('|');
var cssAncestor = locatorParts[0];
var linkText = locatorParts[1];
var matchingElements = cssQuery(cssAncestor, inDocument);
var candidateLinks = matchingElements.collect(function(ancestor){
var links = ancestor.getElementsByTagName('a');
return $A(links).select(function(candidateLink) {
return PatternMatcher.matches(linkText, getText(candidateLink));
});
}).flatten().compact();
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
def extend_selenium #:nodoc:
extensions_file = File.join(File.dirname(__FILE__), "selenium_extensions.js")
extenions_js = File.read(extensions_file)
@selenium.get_eval(extenions_js)
end
def define_location_strategies #:nodoc:
Dir[File.join(File.dirname(__FILE__), "location_strategy_javascript", "*.js")].sort.each do |file|
strategy_js = File.read(file)
strategy_name = File.basename(file, '.js')
@selenium.add_location_strategy(strategy_name, strategy_js)
end
end
end end
end end

19
lib/webrat/sinatra.rb Normal file
View File

@ -0,0 +1,19 @@
require 'webrat/rack'
require 'sinatra'
require 'sinatra/test/methods'
module Webrat
class SinatraSession < RackSession #:nodoc:
include Sinatra::Test::Methods
%w(get head post put delete).each do |verb|
define_method(verb) do |*args| # (path, data, headers = nil)
path, data, headers = *args
params = data.merge({:env => headers || {}})
self.__send__("#{verb}_it", path, params)
follow! while @response.redirect?
end
end
end
end

View File

@ -1,10 +0,0 @@
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

View File

@ -1,34 +0,0 @@
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,23 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "Basic Auth HTTP headers" do
before do
@session = Webrat::TestSession.new
@session.basic_auth('user', 'secret')
end
it "should be present in visit" do
@session.should_receive(:get).with("/", {}, {'HTTP_AUTHORIZATION' => "Basic dXNlcjpzZWNyZXQ=\n"})
@session.visit("/")
end
it "should be present in form submits" do
@session.response_body = <<-EOS
<form method="post" action="/form1">
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/form1", {}, {'HTTP_AUTHORIZATION' => "Basic dXNlcjpzZWNyZXQ=\n"})
@session.click_button
end
end

View File

@ -1,6 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "checks" do describe "check" do
before do before do
@session = Webrat::TestSession.new @session = Webrat::TestSession.new
end end
@ -11,7 +11,7 @@ describe "checks" do
</form> </form>
EOS EOS
lambda { @session.checks "remember_me" }.should raise_error lambda { @session.check "remember_me" }.should raise_error
end end
it "should fail if input is not a checkbox" do it "should fail if input is not a checkbox" do
@ -21,7 +21,7 @@ describe "checks" do
</form> </form>
EOS EOS
lambda { @session.checks "remember_me" }.should raise_error lambda { @session.check "remember_me" }.should raise_error
end end
it "should check rails style checkboxes" do it "should check rails style checkboxes" do
@ -34,8 +34,8 @@ describe "checks" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"tos" => "1"}) @session.should_receive(:get).with("/login", "user" => {"tos" => "1"})
@session.checks "TOS" @session.check "TOS"
@session.clicks_button @session.click_button
end end
it "should result in the value on being posted if not specified" do it "should result in the value on being posted if not specified" do
@ -46,8 +46,18 @@ describe "checks" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "remember_me" => "on") @session.should_receive(:post).with("/login", "remember_me" => "on")
@session.checks "remember_me" @session.check "remember_me"
@session.clicks_button @session.click_button
end
it "should fail if the checkbox is disabled" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="checkbox" name="remember_me" disabled="disabled" />
<input type="submit" />
</form>
EOS
lambda { @session.check "remember_me" }.should raise_error
end end
it "should result in a custom value being posted" do it "should result in a custom value being posted" do
@ -58,12 +68,12 @@ describe "checks" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "remember_me" => "yes") @session.should_receive(:post).with("/login", "remember_me" => "yes")
@session.checks "remember_me" @session.check "remember_me"
@session.clicks_button @session.click_button
end end
end end
describe "unchecks" do describe "uncheck" do
before do before do
@session = Webrat::TestSession.new @session = Webrat::TestSession.new
end end
@ -74,7 +84,7 @@ describe "unchecks" do
</form> </form>
EOS EOS
lambda { @session.unchecks "remember_me" }.should raise_error lambda { @session.uncheck "remember_me" }.should raise_error
end end
it "should fail if input is not a checkbox" do it "should fail if input is not a checkbox" do
@ -84,7 +94,17 @@ describe "unchecks" do
</form> </form>
EOS EOS
lambda { @session.unchecks "remember_me" }.should raise_error lambda { @session.uncheck "remember_me" }.should raise_error
end
it "should fail if the checkbox is disabled" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="checkbox" name="remember_me" checked="checked" disabled="disabled" />
<input type="submit" />
</form>
EOS
lambda { @session.uncheck "remember_me" }.should raise_error
end end
it "should uncheck rails style checkboxes" do it "should uncheck rails style checkboxes" do
@ -97,9 +117,9 @@ describe "unchecks" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"tos" => "0"}) @session.should_receive(:get).with("/login", "user" => {"tos" => "0"})
@session.checks "TOS" @session.check "TOS"
@session.unchecks "TOS" @session.uncheck "TOS"
@session.clicks_button @session.click_button
end end
it "should result in value not being posted" do it "should result in value not being posted" do
@ -110,7 +130,7 @@ describe "unchecks" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", {}) @session.should_receive(:post).with("/login", {})
@session.unchecks "remember_me" @session.uncheck "remember_me"
@session.clicks_button @session.click_button
end end
end end

View File

@ -1,6 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "chooses" do describe "choose" do
before do before do
@session = Webrat::TestSession.new @session = Webrat::TestSession.new
end end
@ -11,7 +11,7 @@ describe "chooses" do
</form> </form>
EOS EOS
lambda { @session.chooses "first option" }.should raise_error lambda { @session.choose "first option" }.should raise_error
end end
it "should fail if input is not a radio button" do it "should fail if input is not a radio button" do
@ -21,7 +21,7 @@ describe "chooses" do
</form> </form>
EOS EOS
lambda { @session.chooses "first_option" }.should raise_error lambda { @session.choose "first_option" }.should raise_error
end end
it "should check rails style radio buttons" do it "should check rails style radio buttons" do
@ -35,8 +35,8 @@ describe "chooses" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"gender" => "M"}) @session.should_receive(:get).with("/login", "user" => {"gender" => "M"})
@session.chooses "Male" @session.choose "Male"
@session.clicks_button @session.click_button
end end
it "should only submit last chosen value" do it "should only submit last chosen value" do
@ -50,9 +50,20 @@ describe "chooses" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"gender" => "M"}) @session.should_receive(:get).with("/login", "user" => {"gender" => "M"})
@session.chooses "Female" @session.choose "Female"
@session.chooses "Male" @session.choose "Male"
@session.clicks_button @session.click_button
end
it "should fail if the radio button is disabled" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input type="radio" name="first_option" disabled="disabled" />
<input type="submit" />
</form>
EOS
lambda { @session.choose "first_option" }.should raise_error
end end
it "should result in the value on being posted if not specified" do it "should result in the value on being posted if not specified" do
@ -63,8 +74,8 @@ describe "chooses" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "first_option" => "on") @session.should_receive(:post).with("/login", "first_option" => "on")
@session.chooses "first_option" @session.choose "first_option"
@session.clicks_button @session.click_button
end end
it "should result in the value on being posted if not specified and checked by default" do it "should result in the value on being posted if not specified and checked by default" do
@ -75,7 +86,7 @@ describe "chooses" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "first_option" => "on") @session.should_receive(:post).with("/login", "first_option" => "on")
@session.clicks_button @session.click_button
end end
it "should result in the value of the selected radio button being posted when a subsequent one is checked by default" do it "should result in the value of the selected radio button being posted when a subsequent one is checked by default" do
@ -89,7 +100,7 @@ describe "chooses" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "user" => {"gender" => "M"}) @session.should_receive(:post).with("/login", "user" => {"gender" => "M"})
@session.chooses "Male" @session.choose "Male"
@session.clicks_button @session.click_button
end end
end end

View File

@ -0,0 +1,93 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "click_area" do
before do
@session = Webrat::TestSession.new
end
it "should use get by default" do
@session.response_body = <<-EOS
<map name="map_de" id="map_de">
<area href="/page" title="Berlin" id="berlin" shape="poly" alt="Berlin" coords="180,89,180" />
</map>
EOS
@session.should_receive(:get).with("/page", {})
@session.click_area "Berlin"
end
it "should assert valid response" do
@session.response_body = <<-EOS
<map name="map_de" id="map_de">
<area href="/page" title="Berlin" id="berlin" shape="poly" alt="Berlin" coords="180,89,180" />
</map>
EOS
@session.response_code = 501
lambda { @session.click_area "Berlin" }.should raise_error
end
[200, 300, 400, 499].each do |status|
it "should consider the #{status} status code as success" do
@session.response_body = <<-EOS
<map name="map_de" id="map_de">
<area href="/page" title="Berlin" id="berlin" shape="poly" alt="Berlin" coords="180,89,180" />
</map>
EOS
@session.response_code = status
lambda { @session.click_area "Berlin" }.should_not raise_error
end
end
it "should fail if the area doesn't exist" do
@session.response_body = <<-EOS
<map name="map_de" id="map_de">
<area href="/page" title="Berlin" id="berlin" shape="poly" alt="Berlin" coords="180,89,180" />
</map>
EOS
lambda {
@session.click_area "Missing area"
}.should raise_error
end
it "should not be case sensitive" do
@session.response_body = <<-EOS
<map name="map_de" id="map_de">
<area href="/page" title="Berlin" id="berlin" shape="poly" alt="Berlin" coords="180,89,180" />
</map>
EOS
@session.should_receive(:get).with("/page", {})
@session.click_area "berlin"
end
it "should follow relative links" do
@session.stub!(:current_url).and_return("/page")
@session.response_body = <<-EOS
<map name="map_de" id="map_de">
<area href="sub" title="Berlin" id="berlin" shape="poly" alt="Berlin" coords="180,89,180" />
</map>
EOS
@session.should_receive(:get).with("/page/sub", {})
@session.click_area "Berlin"
end
it "should follow fully qualified local links" do
@session.response_body = <<-EOS
<map name="map_de" id="map_de">
<area href="http://www.example.com/page" title="Berlin" id="berlin" shape="poly" alt="Berlin" coords="180,89,180" />
</map>
EOS
@session.should_receive(:get).with("http://www.example.com/page", {})
@session.click_area "Berlin"
end
it "should follow query parameters" do
@session.response_body = <<-EOS
<map name="map_de" id="map_de">
<area href="/page?foo=bar" title="Berlin" id="berlin" shape="poly" alt="Berlin" coords="180,89,180" />
</map>
EOS
@session.should_receive(:get).with("/page?foo=bar", {})
@session.click_area "Berlin"
end
end

View File

@ -1,6 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "clicks_button" do describe "click_button" do
before do before do
@session = Webrat::TestSession.new @session = Webrat::TestSession.new
end end
@ -10,7 +10,7 @@ describe "clicks_button" do
<form method="get" action="/login"></form> <form method="get" action="/login"></form>
EOS EOS
lambda { @session.clicks_button }.should raise_error lambda { @session.click_button }.should raise_error
end end
it "should fail if input is not a submit button" do it "should fail if input is not a submit button" do
@ -20,7 +20,18 @@ describe "clicks_button" do
</form> </form>
EOS EOS
lambda { @session.clicks_button }.should raise_error lambda { @session.click_button }.should raise_error
end
it "should fail if button is disabled" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input type="submit" disabled="disabled" />
</form>
EOS
lambda { @session.click_button }.should raise_error
end end
it "should default to get method" do it "should default to get method" do
@ -30,7 +41,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get) @session.should_receive(:get)
@session.clicks_button @session.click_button
end end
it "should assert valid response" do it "should assert valid response" do
@ -39,8 +50,20 @@ describe "clicks_button" do
<input type="submit" /> <input type="submit" />
</form> </form>
EOS EOS
@session.response_code = 404 @session.response_code = 501
lambda { @session.clicks_button }.should raise_error lambda { @session.click_button }.should raise_error
end
[200, 300, 400, 499].each do |status|
it "should consider the #{status} status code as success" do
@session.response_body = <<-EOS
<form action="/login">
<input type="submit" />
</form>
EOS
@session.response_code = status
lambda { @session.click_button }.should_not raise_error
end
end end
it "should submit the first form by default" do it "should submit the first form by default" do
@ -53,7 +76,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/form1", {}) @session.should_receive(:get).with("/form1", {})
@session.clicks_button @session.click_button
end end
it "should not explode on file fields" do it "should not explode on file fields" do
@ -63,7 +86,7 @@ describe "clicks_button" do
<input type="submit" /> <input type="submit" />
</form> </form>
EOS EOS
@session.clicks_button @session.click_button
end end
it "should submit the form with the specified button" do it "should submit the form with the specified button" do
@ -76,7 +99,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/form2", {}) @session.should_receive(:get).with("/form2", {})
@session.clicks_button "Form2" @session.click_button "Form2"
end end
it "should use action from form" do it "should use action from form" do
@ -86,7 +109,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", {}) @session.should_receive(:get).with("/login", {})
@session.clicks_button @session.click_button
end end
it "should use method from form" do it "should use method from form" do
@ -96,7 +119,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:post) @session.should_receive(:post)
@session.clicks_button @session.click_button
end end
it "should send button as param if it has a name" do it "should send button as param if it has a name" do
@ -107,7 +130,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "login" => "Login") @session.should_receive(:post).with("/login", "login" => "Login")
@session.clicks_button("Login") @session.click_button("Login")
end end
it "should not send button as param if it has no name" do it "should not send button as param if it has no name" do
@ -118,7 +141,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", {}) @session.should_receive(:post).with("/login", {})
@session.clicks_button("Login") @session.click_button("Login")
end end
it "should send default password field values" do it "should send default password field values" do
@ -129,7 +152,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"password" => "mypass"}) @session.should_receive(:get).with("/login", "user" => {"password" => "mypass"})
@session.clicks_button @session.click_button
end end
it "should send default hidden field values" do it "should send default hidden field values" do
@ -140,7 +163,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"email" => "test@example.com"}) @session.should_receive(:get).with("/login", "user" => {"email" => "test@example.com"})
@session.clicks_button @session.click_button
end end
it "should send default text field values" do it "should send default text field values" do
@ -151,7 +174,22 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"email" => "test@example.com"}) @session.should_receive(:get).with("/login", "user" => {"email" => "test@example.com"})
@session.clicks_button @session.click_button
end
it "should not send disabled field values" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<input disabled id="user_email" name="user[email]" value="test@example.com" type="text" />
<input disabled id="user_gender_male" name="user[gender]" type="radio" value="M" />
<label for="user_gender_male">Male</label>
<input disabled 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.should_receive(:get).with("/login", {})
@session.click_button
end end
it "should send default checked fields" do it "should send default checked fields" do
@ -162,7 +200,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"tos" => "1"}) @session.should_receive(:get).with("/login", "user" => {"tos" => "1"})
@session.clicks_button @session.click_button
end end
it "should send default radio options" do it "should send default radio options" do
@ -176,7 +214,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"gender" => "F"}) @session.should_receive(:get).with("/login", "user" => {"gender" => "F"})
@session.clicks_button @session.click_button
end end
it "should send correct data for rails style unchecked fields" do it "should send correct data for rails style unchecked fields" do
@ -188,7 +226,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"tos" => "0"}) @session.should_receive(:get).with("/login", "user" => {"tos" => "0"})
@session.clicks_button @session.click_button
end end
it "should send correct data for rails style checked fields" do it "should send correct data for rails style checked fields" do
@ -200,7 +238,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"tos" => "1"}) @session.should_receive(:get).with("/login", "user" => {"tos" => "1"})
@session.clicks_button @session.click_button
end end
it "should send default collection fields" do it "should send default collection fields" do
@ -222,7 +260,7 @@ describe "clicks_button" do
@session.should_receive(:post).with("/login", @session.should_receive(:post).with("/login",
"options" => ["burger", "fries", "soda", "soda", "dessert"], "options" => ["burger", "fries", "soda", "soda", "dessert"],
"response" => { "choices" => [{"selected" => "one"}, {"selected" => "two"}, {"selected" => "two"}]}) "response" => { "choices" => [{"selected" => "one"}, {"selected" => "two"}, {"selected" => "two"}]})
@session.clicks_button @session.click_button
end end
it "should not send default unchecked fields" do it "should not send default unchecked fields" do
@ -233,7 +271,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", {}) @session.should_receive(:get).with("/login", {})
@session.clicks_button @session.click_button
end end
it "should send default textarea values" do it "should send default textarea values" do
@ -244,7 +282,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/posts", "post" => {"body" => "Post body here!"}) @session.should_receive(:post).with("/posts", "post" => {"body" => "Post body here!"})
@session.clicks_button @session.click_button
end end
it "should send default selected option value from select" do it "should send default selected option value from select" do
@ -258,7 +296,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "month" => "2") @session.should_receive(:get).with("/login", "month" => "2")
@session.clicks_button @session.click_button
end end
it "should send default selected option inner html from select when no value attribute" do it "should send default selected option inner html from select when no value attribute" do
@ -272,7 +310,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "month" => "February") @session.should_receive(:get).with("/login", "month" => "February")
@session.clicks_button @session.click_button
end end
it "should send first select option value when no option selected" do it "should send first select option value when no option selected" do
@ -286,7 +324,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "month" => "1") @session.should_receive(:get).with("/login", "month" => "1")
@session.clicks_button @session.click_button
end end
it "should handle nested properties" do it "should handle nested properties" do
@ -298,7 +336,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "contestant" => {"scores" => {'1' => '2', '3' => '4'}}) @session.should_receive(:post).with("/login", "contestant" => {"scores" => {'1' => '2', '3' => '4'}})
@session.clicks_button @session.click_button
end end
it "should send default empty text field values" do it "should send default empty text field values" do
@ -309,7 +347,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"email" => ""}) @session.should_receive(:get).with("/login", "user" => {"email" => ""})
@session.clicks_button @session.click_button
end end
it "should recognize button tags" do it "should recognize button tags" do
@ -320,7 +358,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"email" => ""}) @session.should_receive(:get).with("/login", "user" => {"email" => ""})
@session.clicks_button @session.click_button
end end
it "should recognize image button tags" do it "should recognize image button tags" do
@ -330,7 +368,17 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get) @session.should_receive(:get)
@session.clicks_button @session.click_button
end
it "should find buttons by their IDs" do
@session.response_body = <<-EOS
<form action="/">
<input type="submit" id="my_button" />
</form>
EOS
@session.should_receive(:get)
@session.click_button "my_button"
end end
it "should find image buttons by their alt text" do it "should find image buttons by their alt text" do
@ -340,7 +388,7 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get) @session.should_receive(:get)
@session.clicks_button "Go" @session.click_button "Go"
end end
it "should recognize button tags by content" do it "should recognize button tags by content" do
@ -351,6 +399,6 @@ describe "clicks_button" do
</form> </form>
EOS EOS
@session.should_receive(:get).with("/login", "user" => {"email" => ""}) @session.should_receive(:get).with("/login", "user" => {"email" => ""})
@session.clicks_button "Login" @session.click_button "Login"
end end
end end

View File

@ -1,6 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "clicks_link" do describe "click_link" do
before do before do
@session = Webrat::TestSession.new @session = Webrat::TestSession.new
end end
@ -10,7 +10,7 @@ describe "clicks_link" do
<a href="/page">Link text</a> <a href="/page">Link text</a>
EOS EOS
@session.should_receive(:get).with("/page", {}) @session.should_receive(:get).with("/page", {})
@session.clicks_link "Link text" @session.click_link "Link text"
end end
it "should click get links" do it "should click get links" do
@ -18,7 +18,7 @@ describe "clicks_link" do
<a href="/page">Link text</a> <a href="/page">Link text</a>
EOS EOS
@session.should_receive(:get).with("/page", {}) @session.should_receive(:get).with("/page", {})
@session.clicks_get_link "Link text" @session.click_link "Link text", :method => :get
end end
it "should click delete links" do it "should click delete links" do
@ -26,7 +26,7 @@ describe "clicks_link" do
<a href="/page">Link text</a> <a href="/page">Link text</a>
EOS EOS
@session.should_receive(:delete).with("/page", {}) @session.should_receive(:delete).with("/page", {})
@session.clicks_delete_link "Link text" @session.click_link "Link text", :method => :delete
end end
@ -35,7 +35,7 @@ describe "clicks_link" do
<a href="/page">Link text</a> <a href="/page">Link text</a>
EOS EOS
@session.should_receive(:post).with("/page", {}) @session.should_receive(:post).with("/page", {})
@session.clicks_post_link "Link text" @session.click_link "Link text", :method => :post
end end
it "should click put links" do it "should click put links" do
@ -43,7 +43,15 @@ describe "clicks_link" do
<a href="/page">Link text</a> <a href="/page">Link text</a>
EOS EOS
@session.should_receive(:put).with("/page", {}) @session.should_receive(:put).with("/page", {})
@session.clicks_put_link "Link text" @session.click_link "Link text", :method => :put
end
it "should click links by regexp" do
@session.response_body = <<-EOS
<a href="/page">Link text</a>
EOS
@session.should_receive(:get).with("/page", {})
@session.click_link /link [a-z]/i
end end
it "should click rails javascript links with authenticity tokens" do it "should click rails javascript links with authenticity tokens" do
@ -62,7 +70,7 @@ describe "clicks_link" do
return false;">Posts</a> return false;">Posts</a>
EOS EOS
@session.should_receive(:post).with("/posts", "authenticity_token" => "aa79cb354597a60a3786e7e291ed4f74d77d3a62") @session.should_receive(:post).with("/posts", "authenticity_token" => "aa79cb354597a60a3786e7e291ed4f74d77d3a62")
@session.clicks_link "Posts" @session.click_link "Posts"
end end
it "should click rails javascript delete links" do it "should click rails javascript delete links" do
@ -81,7 +89,7 @@ describe "clicks_link" do
return false;">Delete</a> return false;">Delete</a>
EOS EOS
@session.should_receive(:delete).with("/posts/1", {}) @session.should_receive(:delete).with("/posts/1", {})
@session.clicks_link "Delete" @session.click_link "Delete"
end end
it "should click rails javascript post links" do it "should click rails javascript post links" do
@ -95,7 +103,7 @@ describe "clicks_link" do
return false;">Posts</a> return false;">Posts</a>
EOS EOS
@session.should_receive(:post).with("/posts", {}) @session.should_receive(:post).with("/posts", {})
@session.clicks_link "Posts" @session.click_link "Posts"
end end
it "should click rails javascript post links without javascript" do it "should click rails javascript post links without javascript" do
@ -109,7 +117,7 @@ describe "clicks_link" do
return false;">Posts</a> return false;">Posts</a>
EOS EOS
@session.should_receive(:get).with("/posts", {}) @session.should_receive(:get).with("/posts", {})
@session.clicks_link "Posts", :javascript => false @session.click_link "Posts", :javascript => false
end end
it "should click rails javascript put links" do it "should click rails javascript put links" do
@ -128,7 +136,7 @@ describe "clicks_link" do
return false;">Put</a></h2> return false;">Put</a></h2>
EOS EOS
@session.should_receive(:put).with("/posts", {}) @session.should_receive(:put).with("/posts", {})
@session.clicks_link "Put" @session.click_link "Put"
end end
it "should fail if the javascript link doesn't have a value for the _method input" do it "should fail if the javascript link doesn't have a value for the _method input" do
@ -147,7 +155,7 @@ describe "clicks_link" do
EOS EOS
lambda { lambda {
@session.clicks_link "Link" @session.click_link "Link"
}.should raise_error }.should raise_error
end end
@ -155,8 +163,18 @@ describe "clicks_link" do
@session.response_body = <<-EOS @session.response_body = <<-EOS
<a href="/page">Link text</a> <a href="/page">Link text</a>
EOS EOS
@session.response_code = 404 @session.response_code = 501
lambda { @session.clicks_link "Link text" }.should raise_error lambda { @session.click_link "Link text" }.should raise_error
end
[200, 300, 400, 499].each do |status|
it "should consider the #{status} status code as success" do
@session.response_body = <<-EOS
<a href="/page">Link text</a>
EOS
@session.response_code = status
lambda { @session.click_link "Link text" }.should_not raise_error
end
end end
it "should fail is the link doesn't exist" do it "should fail is the link doesn't exist" do
@ -165,7 +183,7 @@ describe "clicks_link" do
EOS EOS
lambda { lambda {
@session.clicks_link "Missing link" @session.click_link "Missing link"
}.should raise_error }.should raise_error
end end
@ -174,7 +192,7 @@ describe "clicks_link" do
<a href="/page">Link text</a> <a href="/page">Link text</a>
EOS EOS
@session.should_receive(:get).with("/page", {}) @session.should_receive(:get).with("/page", {})
@session.clicks_link "LINK TEXT" @session.click_link "LINK TEXT"
end end
it "should match link substrings" do it "should match link substrings" do
@ -182,7 +200,7 @@ describe "clicks_link" do
<a href="/page">This is some cool link text, isn't it?</a> <a href="/page">This is some cool link text, isn't it?</a>
EOS EOS
@session.should_receive(:get).with("/page", {}) @session.should_receive(:get).with("/page", {})
@session.clicks_link "Link text" @session.click_link "Link text"
end end
it "should work with elements in the link" do it "should work with elements in the link" do
@ -190,7 +208,7 @@ describe "clicks_link" do
<a href="/page"><span>Link text</span></a> <a href="/page"><span>Link text</span></a>
EOS EOS
@session.should_receive(:get).with("/page", {}) @session.should_receive(:get).with("/page", {})
@session.clicks_link "Link text" @session.click_link "Link text"
end end
it "should match the first matching link" do it "should match the first matching link" do
@ -199,7 +217,7 @@ describe "clicks_link" do
<a href="/page2">Link text</a> <a href="/page2">Link text</a>
EOS EOS
@session.should_receive(:get).with("/page1", {}) @session.should_receive(:get).with("/page1", {})
@session.clicks_link "Link text" @session.click_link "Link text"
end end
it "should choose the shortest link text match" do it "should choose the shortest link text match" do
@ -209,7 +227,7 @@ describe "clicks_link" do
EOS EOS
@session.should_receive(:get).with("/page2", {}) @session.should_receive(:get).with("/page2", {})
@session.clicks_link "Link" @session.click_link "Link"
end end
it "should treat non-breaking spaces as spaces" do it "should treat non-breaking spaces as spaces" do
@ -218,7 +236,7 @@ describe "clicks_link" do
EOS EOS
@session.should_receive(:get).with("/page1", {}) @session.should_receive(:get).with("/page1", {})
@session.clicks_link "This is a link" @session.click_link "This is a link"
end end
it "should click link within a selector" do it "should click link within a selector" do
@ -230,7 +248,7 @@ describe "clicks_link" do
EOS EOS
@session.should_receive(:get).with("/page2", {}) @session.should_receive(:get).with("/page2", {})
@session.clicks_link_within "#container", "Link" @session.click_link_within "#container", "Link"
end end
it "should not make request when link is local anchor" do it "should not make request when link is local anchor" do
@ -239,7 +257,7 @@ describe "clicks_link" do
EOS EOS
# Don't know why @session.should_receive(:get).never doesn't work here # Don't know why @session.should_receive(:get).never doesn't work here
@session.should_receive(:send).with('get_via_redirect', '#section-1', {}).never @session.should_receive(:send).with('get_via_redirect', '#section-1', {}).never
@session.clicks_link "Jump to Section 1" @session.click_link "Jump to Section 1"
end end
it "should follow relative links" do it "should follow relative links" do
@ -248,7 +266,7 @@ describe "clicks_link" do
<a href="sub">Jump to sub page</a> <a href="sub">Jump to sub page</a>
EOS EOS
@session.should_receive(:get).with("/page/sub", {}) @session.should_receive(:get).with("/page/sub", {})
@session.clicks_link "Jump to sub page" @session.click_link "Jump to sub page"
end end
it "should follow fully qualified local links" do it "should follow fully qualified local links" do
@ -256,7 +274,7 @@ describe "clicks_link" do
<a href="http://www.example.com/page/sub">Jump to sub page</a> <a href="http://www.example.com/page/sub">Jump to sub page</a>
EOS EOS
@session.should_receive(:get).with("http://www.example.com/page/sub", {}) @session.should_receive(:get).with("http://www.example.com/page/sub", {})
@session.clicks_link "Jump to sub page" @session.click_link "Jump to sub page"
end end
it "should follow query parameters" do it "should follow query parameters" do
@ -265,6 +283,6 @@ describe "clicks_link" do
<a href="?foo=bar">Jump to foo bar</a> <a href="?foo=bar">Jump to foo bar</a>
EOS EOS
@session.should_receive(:get).with("/page?foo=bar", {}) @session.should_receive(:get).with("/page?foo=bar", {})
@session.clicks_link "Jump to foo bar" @session.click_link "Jump to foo bar"
end end
end end

View File

@ -0,0 +1,111 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "field_labeled" do
class << self
def using_this_html html
before(:each) do
@session = Webrat::TestSession.new
@session.response_body = html
end
end
def field_labeled label
@label = label
yield
end
def should_return_a type, opts
it "should return a textfield" do
@session.field_labeled(opts[:for]).should be_an_instance_of(type)
end
end
def with_an_id_of id, opts
it "should return an element with the correct id" do
@session.field_labeled(opts[:for]).should match_id(id)
end
end
def should_raise_error_matching regexp, opts
it "should raise with wrong label" do
lambda {
@session.field_labeled(opts[:for])
}.should raise_error(regexp)
end
end
end
def match_id(id)
simple_matcher "element with id #{id.inspect}" do |element, matcher|
element.matches_id? id
end
end
describe "finding a text field" do
using_this_html <<-HTML
<form>
<label for="element_42">The Label</label>
<input type="text" id="element_42">
</form>
HTML
should_return_a Webrat::TextField, :for => "The Label"
with_an_id_of "element_42", :for => "The Label"
should_raise_error_matching /Could not find .* "Other Label"/, :for => "Other Label"
end
describe "finding a hidden field" do
using_this_html <<-HTML
<form>
<label for="element_42">The Label</label>
<input type="hidden" id="element_42">
</form>
HTML
should_return_a Webrat::HiddenField, :for => "The Label"
with_an_id_of "element_42", :for => "The Label"
should_raise_error_matching /Could not find .* "Other Label"/, :for => "Other Label"
end
describe "finding a checkbox" do
using_this_html <<-HTML
<form>
<label for="element_42">The Label</label>
<input type="checkbox" id="element_42">
</form>
HTML
should_return_a Webrat::CheckboxField, :for => "The Label"
with_an_id_of "element_42", :for => "The Label"
should_raise_error_matching /Could not find .* "Other Label"/, :for => "Other Label"
end
describe "finding a radio button" do
using_this_html <<-HTML
<form>
<label for="element_42">The Label</label>
<input type="radio" id="element_42">
</form>
HTML
should_return_a Webrat::RadioField, :for => "The Label"
with_an_id_of "element_42", :for => "The Label"
should_raise_error_matching /Could not find .* "Other Label"/, :for => "Other Label"
end
describe "finding a text area" do
using_this_html <<-HTML
<form>
<label for="element_42">The Label</label>
<textarea id="element_42"></textarea>
</form>
HTML
should_return_a Webrat::TextareaField, :for => "The Label"
with_an_id_of "element_42", :for => "The Label"
should_raise_error_matching /Could not find .* "Other Label"/, :for => "Other Label"
end
end

View File

@ -1,6 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "fills_in" do describe "fill_in" do
before do before do
@session = Webrat::TestSession.new @session = Webrat::TestSession.new
end end
@ -14,8 +14,8 @@ describe "fills_in" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "user" => {"text" => "filling text area"}) @session.should_receive(:post).with("/login", "user" => {"text" => "filling text area"})
@session.fills_in "User Text", :with => "filling text area" @session.fill_in "User Text", :with => "filling text area"
@session.clicks_button @session.click_button
end end
it "should work with password fields" do it "should work with password fields" do
@ -26,8 +26,8 @@ describe "fills_in" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "user" => {"text" => "pass"}) @session.should_receive(:post).with("/login", "user" => {"text" => "pass"})
@session.fills_in "user_text", :with => "pass" @session.fill_in "user_text", :with => "pass"
@session.clicks_button @session.click_button
end end
it "should fail if input not found" do it "should fail if input not found" do
@ -36,7 +36,19 @@ describe "fills_in" do
</form> </form>
EOS EOS
lambda { @session.fills_in "Email", :with => "foo@example.com" }.should raise_error lambda { @session.fill_in "Email", :with => "foo@example.com" }.should raise_error
end
it "should fail if input is disabled" do
@session.response_body = <<-EOS
<form method="get" action="/login">
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" type="text" disabled="disabled" />
<input type="submit" />
</form>
EOS
lambda { @session.fill_in "Email", :with => "foo@example.com" }.should raise_error
end end
it "should allow overriding default form values" do it "should allow overriding default form values" do
@ -48,8 +60,8 @@ describe "fills_in" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"}) @session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
@session.fills_in "user[email]", :with => "foo@example.com" @session.fill_in "user[email]", :with => "foo@example.com"
@session.clicks_button @session.click_button
end end
it "should choose the shortest label match" do it "should choose the shortest label match" do
@ -64,8 +76,8 @@ describe "fills_in" do
EOS EOS
@session.should_receive(:post).with("/login", "user" => {"mail1" => "", "mail2" => "value"}) @session.should_receive(:post).with("/login", "user" => {"mail1" => "", "mail2" => "value"})
@session.fills_in "Some", :with => "value" @session.fill_in "Some", :with => "value"
@session.clicks_button @session.click_button
end end
it "should choose the first label match if closest is a tie" do it "should choose the first label match if closest is a tie" do
@ -80,8 +92,8 @@ describe "fills_in" do
EOS EOS
@session.should_receive(:post).with("/login", "user" => {"mail1" => "value", "mail2" => ""}) @session.should_receive(:post).with("/login", "user" => {"mail1" => "value", "mail2" => ""})
@session.fills_in "Some mail", :with => "value" @session.fill_in "Some mail", :with => "value"
@session.clicks_button @session.click_button
end end
it "should anchor label matches to start of label" do it "should anchor label matches to start of label" do
@ -92,7 +104,7 @@ describe "fills_in" do
</form> </form>
EOS EOS
lambda { @session.fills_in "mail", :with => "value" }.should raise_error lambda { @session.fill_in "mail", :with => "value" }.should raise_error
end end
it "should anchor label matches to word boundaries" do it "should anchor label matches to word boundaries" do
@ -103,7 +115,7 @@ describe "fills_in" do
</form> </form>
EOS EOS
lambda { @session.fills_in "Email", :with => "value" }.should raise_error lambda { @session.fill_in "Email", :with => "value" }.should raise_error
end end
it "should work with inputs nested in labels" do it "should work with inputs nested in labels" do
@ -117,8 +129,8 @@ describe "fills_in" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"}) @session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
@session.fills_in "Email", :with => "foo@example.com" @session.fill_in "Email", :with => "foo@example.com"
@session.clicks_button @session.click_button
end end
it "should work with full input names" do it "should work with full input names" do
@ -129,8 +141,20 @@ describe "fills_in" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"}) @session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
@session.fills_in "user[email]", :with => "foo@example.com" @session.fill_in "user[email]", :with => "foo@example.com"
@session.clicks_button @session.click_button
end
it "should work if the input type is not set" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<input id="user_email" name="user[email]" />
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
@session.fill_in "user[email]", :with => "foo@example.com"
@session.click_button
end end
it "should work with symbols" do it "should work with symbols" do
@ -142,7 +166,20 @@ describe "fills_in" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"}) @session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
@session.fills_in :email, :with => "foo@example.com" @session.fill_in :email, :with => "foo@example.com"
@session.clicks_button @session.click_button
end
it "should escape field values" do
@session.response_body = <<-EOS
<form method="post" action="/users">
<label for="user_phone">Phone</label>
<input id="user_phone" name="user[phone]" type="text" />
<input type="submit" />
</form>
EOS
@session.should_receive(:post).with("/users", "user" => {"phone" => "+1 22 33"})
@session.fill_in 'Phone', :with => "+1 22 33"
@session.click_button
end end
end end

178
spec/api/matchers_spec.rb Normal file
View File

@ -0,0 +1,178 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe Webrat::Matchers do
include Webrat::Matchers
include Webrat::HaveTagMatcher
before(:each) do
@body = <<-EOF
<div id='main'>
<div class='inner'>hello, world!</div>
<ul>
<li>First</li>
<li>Second</li>
</ul>
</div>
EOF
end
describe "#have_xpath" do
it "should be able to match an XPATH" do
@body.should have_xpath("//div")
end
it "should not match a XPATH that does not exist" do
@body.should_not have_xpath("//p")
end
it "should be able to loop over all the matched elements" do
@body.should have_xpath("//div") { |node| node.first.name.should == "div" }
end
it "should not match of any of the matchers in the block fail" do
lambda {
@body.should have_xpath("//div") { |node| node.first.name.should == "p" }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
it "should be able to use #have_xpath in the block" do
@body.should have_xpath("//div[@id='main']") { |node| node.should have_xpath("./div[@class='inner']") }
end
it "should convert absolute paths to relative in the block" do
@body.should have_xpath("//div[@id='main']") { |node| node.should have_xpath("//div[@class='inner']") }
end
it "should not match any parent tags in the block" do
lambda {
@body.should have_xpath("//div[@class='inner']") { |node| node.should have_xpath("//div[@id='main']") }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
end
describe "#have_selector" do
it "should be able to match a CSS selector" do
@body.should have_selector("div")
end
it "should not match a CSS selector that does not exist" do
@body.should_not have_selector("p")
end
it "should be able to loop over all the matched elements" do
@body.should have_selector("div") { |node| node.first.name.should == "div" }
end
it "should not match of any of the matchers in the block fail" do
lambda {
@body.should have_selector("div") { |node| node.first.name.should == "p" }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
it "should be able to use #have_selector in the block" do
@body.should have_selector("#main") { |node| node.should have_selector(".inner") }
end
it "should not match any parent tags in the block" do
lambda {
@body.should have_selector(".inner") { |node| node.should have_selector("#main") }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
end
describe "#have_tag" do
it "should be able to match a tag" do
@body.should have_tag("div")
end
it "should not match the tag when it should not match" do
@body.should_not have_tag("p")
end
it "should be able to specify the content of the tag" do
@body.should have_tag("div", :content => "hello, world!")
end
it "should be able to specify the attributes of the tag" do
@body.should have_tag("div", :class => "inner")
end
it "should be able to loop over all the matched elements" do
@body.should have_tag("div") { |node| node.first.name.should == "div" }
end
it "should not match of any of the matchers in the block fail" do
lambda {
@body.should have_tag("div") { |node| node.first.name.should == "p" }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
it "should be able to use #have_tag in the block" do
@body.should have_tag("div", :id => "main") { |node| node.should have_tag("div", :class => "inner") }
end
it "should not match any parent tags in the block" do
lambda {
@body.should have_tag("div", :class => "inner") { |node| node.should have_tag("div", :id => "main") }
}.should raise_error(Spec::Expectations::ExpectationNotMetError)
end
it "should work with items that have multiple child nodes" do
@body.should have_tag("ul") { |n|
n.should have_tag("li", :content => "First")
n.should have_tag("li", :content => "Second")
}
end
end
describe Webrat::Matchers::HasContent do
include Webrat::Matchers
before(:each) do
@body = <<-EOF
<div id='main'>
<div class='inner'>hello, world!</div>
</div>
EOF
end
describe "#matches?" do
it "should call element#contains? when the argument is a string" do
@body.should contain("hello, world!")
end
it "should call element#matches? when the argument is a regular expression" do
@body.should contain(/hello, world/)
end
end
describe "#failure_message" do
it "should include the content string" do
hc = Webrat::Matchers::HasContent.new("hello, world!")
hc.matches?(@body)
hc.failure_message.should include("\"hello, world!\"")
end
it "should include the content regular expresson" do
hc = Webrat::Matchers::HasContent.new(/hello,\sworld!/)
hc.matches?(@body)
hc.failure_message.should include("/hello,\\sworld!/")
end
it "should include the element's inner content" do
hc = Webrat::Matchers::HasContent.new(/hello,\sworld!/)
hc.matches?(@body)
hc.failure_message.should include("hello, world!")
end
end
end
end

View File

@ -9,7 +9,7 @@ describe "reloads" do
it "should reload the page with http referer" do it "should reload the page with http referer" do
@session.should_receive(:get).with("/", {}) @session.should_receive(:get).with("/", {})
@session.should_receive(:get).with("/", {}, {"HTTP_REFERER"=>"/"}) @session.should_receive(:get).with("/", {}, {"HTTP_REFERER"=>"/"})
@session.visits("/") @session.visit("/")
@session.reloads @session.reloads
end end
end end

View File

@ -36,6 +36,18 @@ describe "selects" do
lambda { @session.selects "February", :from => "year" }.should raise_error lambda { @session.selects "February", :from => "year" }.should raise_error
end end
it "should fail if the select is disabled" do
@session.response_body = <<-EOS
<form method="post" action="/login">
<select name="month" disabled="disabled"><option value="1">January</option></select>
<input type="submit" />
</form>
EOS
lambda { @session.selects "January", :from => "month" }.should raise_error
end
it "should send value from option" do it "should send value from option" do
@session.response_body = <<-EOS @session.response_body = <<-EOS
<form method="post" action="/login"> <form method="post" action="/login">
@ -45,7 +57,7 @@ describe "selects" do
EOS EOS
@session.should_receive(:post).with("/login", "month" => "1") @session.should_receive(:post).with("/login", "month" => "1")
@session.selects "January", :from => "month" @session.selects "January", :from => "month"
@session.clicks_button @session.click_button
end end
it "should send values with HTML encoded ampersands" do it "should send values with HTML encoded ampersands" do
@ -57,7 +69,7 @@ describe "selects" do
EOS EOS
@session.should_receive(:post).with("/login", "encoded" => "A & B") @session.should_receive(:post).with("/login", "encoded" => "A & B")
@session.selects "Encoded", :from => "encoded" @session.selects "Encoded", :from => "encoded"
@session.clicks_button @session.click_button
end end
it "should work with empty select lists" do it "should work with empty select lists" do
@ -68,7 +80,7 @@ describe "selects" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/login", 'month' => '') @session.should_receive(:post).with("/login", 'month' => '')
@session.clicks_button @session.click_button
end end
it "should work without specifying the field name or label" do it "should work without specifying the field name or label" do
@ -80,7 +92,7 @@ describe "selects" do
EOS EOS
@session.should_receive(:post).with("/login", "month" => "1") @session.should_receive(:post).with("/login", "month" => "1")
@session.selects "January" @session.selects "January"
@session.clicks_button @session.click_button
end end
it "should send value from option in list specified by name" do it "should send value from option in list specified by name" do
@ -93,7 +105,7 @@ describe "selects" do
EOS EOS
@session.should_receive(:post).with("/login", "start_month" => "s1", "end_month" => "e1") @session.should_receive(:post).with("/login", "start_month" => "s1", "end_month" => "e1")
@session.selects "January", :from => "end_month" @session.selects "January", :from => "end_month"
@session.clicks_button @session.click_button
end end
it "should send value from option in list specified by label" do it "should send value from option in list specified by label" do
@ -108,7 +120,7 @@ describe "selects" do
EOS EOS
@session.should_receive(:post).with("/login", "start_month" => "s1", "end_month" => "e1") @session.should_receive(:post).with("/login", "start_month" => "s1", "end_month" => "e1")
@session.selects "January", :from => "End Month" @session.selects "January", :from => "End Month"
@session.clicks_button @session.click_button
end end
it "should use option text if no value" do it "should use option text if no value" do
@ -120,7 +132,7 @@ describe "selects" do
EOS EOS
@session.should_receive(:post).with("/login", "month" => "January") @session.should_receive(:post).with("/login", "month" => "January")
@session.selects "January", :from => "month" @session.selects "January", :from => "month"
@session.clicks_button @session.click_button
end end
it "should find option by regexp" do it "should find option by regexp" do
@ -132,7 +144,7 @@ describe "selects" do
EOS EOS
@session.should_receive(:post).with("/login", "month" => "January") @session.should_receive(:post).with("/login", "month" => "January")
@session.selects(/jan/i) @session.selects(/jan/i)
@session.clicks_button @session.click_button
end end
it "should fail if no option matching the regexp exists" do it "should fail if no option matching the regexp exists" do
@ -160,6 +172,6 @@ describe "selects" do
EOS EOS
@session.should_receive(:post).with("/login", "start_month" => "s1", "end_month" => "e1") @session.should_receive(:post).with("/login", "start_month" => "s1", "end_month" => "e1")
@session.selects(/jan/i, :from => "End Month") @session.selects(/jan/i, :from => "End Month")
@session.clicks_button @session.click_button
end end
end end

View File

@ -1,6 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "visits" do describe "visit" do
before do before do
@session = Webrat::TestSession.new @session = Webrat::TestSession.new
@session.response_body = "Hello world" @session.response_body = "Hello world"
@ -8,20 +8,27 @@ describe "visits" do
it "should use get" do it "should use get" do
@session.should_receive(:get).with("/", {}) @session.should_receive(:get).with("/", {})
@session.visits("/") @session.visit("/")
end end
it "should assert valid response" do it "should assert valid response" do
@session.response_code = 404 @session.response_code = 501
lambda { @session.visits("/") }.should raise_error lambda { @session.visit("/") }.should raise_error
end
[200, 300, 400, 499].each do |status|
it "should consider the #{status} status code as success" do
@session.response_code = status
lambda { @session.visit("/") }.should_not raise_error
end
end end
it "should require a visit before manipulating page" do it "should require a visit before manipulating page" do
lambda { @session.fills_in "foo", :with => "blah" }.should raise_error lambda { @session.fill_in "foo", :with => "blah" }.should raise_error
end end
end end
describe "visits with referer" do describe "visit with referer" do
before do before do
@session = Webrat::TestSession.new @session = Webrat::TestSession.new
@session.instance_variable_set(:@current_url, "/old_url") @session.instance_variable_set(:@current_url, "/old_url")
@ -30,7 +37,7 @@ describe "visits with referer" do
it "should use get with referer header" do it "should use get with referer header" do
@session.should_receive(:get).with("/", {}, {"HTTP_REFERER" => "/old_url"}) @session.should_receive(:get).with("/", {}, {"HTTP_REFERER" => "/old_url"})
@session.visits("/") @session.visit("/")
end end
end end

View File

@ -5,6 +5,24 @@ describe "within" do
@session = Webrat::TestSession.new @session = Webrat::TestSession.new
end end
it "should work when nested" do
@session.response_body = <<-EOS
<div>
<a href="/page1">Link</a>
</div>
<div id="container">
<div><a href="/page2">Link</a></div>
</div>
EOS
@session.should_receive(:get).with("/page2", {})
@session.within "#container" do
@session.within "div" do
@session.click_link "Link"
end
end
end
it "should click links within a scope" do it "should click links within a scope" do
@session.response_body = <<-EOS @session.response_body = <<-EOS
<a href="/page1">Link</a> <a href="/page1">Link</a>
@ -14,8 +32,8 @@ describe "within" do
EOS EOS
@session.should_receive(:get).with("/page2", {}) @session.should_receive(:get).with("/page2", {})
@session.within "#container" do |scope| @session.within "#container" do
scope.clicks_link "Link" @session.click_link "Link"
end end
end end
@ -32,9 +50,9 @@ describe "within" do
EOS EOS
@session.should_receive(:get).with("/form2", "email" => "test@example.com") @session.should_receive(:get).with("/form2", "email" => "test@example.com")
@session.within "#form2" do |scope| @session.within "#form2" do
scope.fill_in "Email", :with => "test@example.com" @session.fill_in "Email", :with => "test@example.com"
scope.clicks_button @session.click_button
end end
end end
@ -47,9 +65,9 @@ describe "within" do
</form> </form>
EOS EOS
@session.within "#form2" do |scope| @session.within "#form2" do
lambda { lambda {
scope.clicks_button @session.click_button
}.should raise_error }.should raise_error
end end
end end

View File

@ -7,6 +7,10 @@ module Webrat
File.expand_path(File.join(".", "public")) File.expand_path(File.join(".", "public"))
end end
def response
@response ||= Object.new
end
def response_code def response_code
@response_code || 200 @response_code || 200
end end

View File

@ -4,16 +4,8 @@ require "spec"
# gem install redgreen for colored test output # gem install redgreen for colored test output
begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end
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.expand_path(File.dirname(__FILE__) + "/../lib/webrat")
require File.expand_path(File.dirname(__FILE__) + "/../lib/webrat/rails") require File.expand_path(File.dirname(__FILE__) + "/fakes/test_session")
require File.dirname(__FILE__) + "/fakes/test_session"
Spec::Runner.configure do |config| Spec::Runner.configure do |config|
# Nothing to configure yet # Nothing to configure yet

View File

@ -0,0 +1,15 @@
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
module Webrat
describe CheckboxField do
it "should say it is checked if it is" do
checkbox = CheckboxField.new(nil, (Webrat.nokogiri_document("<input type='checkbox' checked='checked'>")/'input').first)
checkbox.should be_checked
end
it "should say it is not checked if it is not" do
checkbox = CheckboxField.new(nil, (Webrat.nokogiri_document("<input type='checkbox'>")/'input').first)
checkbox.should_not be_checked
end
end
end

View File

@ -1,12 +1,10 @@
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
describe Webrat::Logging do describe Webrat::Logging do
include Webrat::Logging
it "should log to RAILS_DEFAULT_LOGGER" do it "should not log if there is no logger" do
logger = mock("logger") klass = Class.new
RAILS_DEFAULT_LOGGER = logger klass.send(:include, Webrat::Logging)
logger.should_receive(:debug).with("Testing") klass.new.debug_log "Testing"
debug_log "Testing"
end end
end end

View File

@ -10,11 +10,15 @@ describe Webrat::Session do
it "should expose the current_dom" do it "should expose the current_dom" do
session = Webrat::Session.new session = Webrat::Session.new
def session.response
Object.new
end
def session.response_body def session.response_body
"<html></html>" "<html></html>"
end end
session.current_dom.should be_an_instance_of(Hpricot::Doc) session.current_dom.should be_an_instance_of(Nokogiri::HTML::Document)
end end
it "should open the page in the browser" do it "should open the page in the browser" do
@ -30,4 +34,55 @@ describe Webrat::Session do
current_page.should respond_to(:url) current_page.should respond_to(:url)
end end
it "should allow custom headers to be set" do
session = Webrat::Session.new
session.header('Accept', 'application/xml')
session.instance_variable_get(:@custom_headers)['Accept'].should == 'application/xml'
end
it "should return a copy of the headers to be sent" do
session = Webrat::Session.new
session.instance_eval {
@default_headers = {'HTTP_X_FORWARDED_FOR' => '192.168.1.1'}
@custom_headers = {'Accept' => 'application/xml'}
}
session.headers.should == {'HTTP_X_FORWARDED_FOR' => '192.168.1.1', 'Accept' => 'application/xml'}
end
describe "#http_accept" do
before(:each) do
@session = Webrat::Session.new
end
it "should set the Accept header with the string Mime type" do
@session.http_accept('application/xml')
@session.headers['Accept'].should == 'application/xml'
end
it "should set the Accept head with the string value of the symbol Mime type" do
@session.http_accept(:xml)
@session.headers['Accept'].should == 'application/xml'
end
it "should raise an error if a symbol Mime type is passed that does not exist" do
lambda { @session.http_accept(:oogabooga) }.should raise_error(ArgumentError)
end
end
describe "#request_page" do
before(:each) do
@session = Webrat::Session.new
end
it "should raise an error if the request is not a success" do
@session.stub!(:get)
@session.stub!(:response_body).and_return("Exception caught")
@session.stub!(:response_code).and_return(500)
@session.stub!(:formatted_error).and_return("application error")
@session.stub!(:save_and_open_page)
lambda { @session.request_page('some url', :get, {}) }.should raise_error(Webrat::PageLoadError)
end
end
end end

View File

@ -0,0 +1,15 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require "mechanize"
require "webrat/mechanize"
describe Webrat::MechanizeSession do
before(:each) do
@mech = Webrat::MechanizeSession.new
end
describe "headers method" do
it "should return empty headers for a newly initialized session" do
@mech.headers.should == {}
end
end
end

View File

@ -0,0 +1,2 @@
require 'merb-core'
require File.expand_path(File.dirname(__FILE__) + "/../../../lib/webrat/merb")

View File

@ -0,0 +1,48 @@
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
require File.expand_path(File.dirname(__FILE__) + "/helper")
describe HashWithIndifferentAccess do
it "should not update constructor when not a hash" do
HashWithIndifferentAccess.should_receive(:update).never
HashWithIndifferentAccess.new('test')
end
it "should get the default for key" do
h = HashWithIndifferentAccess.new(:test => 'me')
h.should_receive(:super).never
h.default(:test).should == 'me'
end
context "a hash with a test value applied" do
setup do
@h = HashWithIndifferentAccess.new
@h[:test] = 'me'
end
it "should assign a new value" do
@h[:test].should == 'me'
end
it "should return true if asked for existing key" do
@h.key?(:test).should be_true
end
it "should return array of values for keys" do
@h.values_at(:test).should == ['me']
end
it "should merge with another hash" do
another = HashWithIndifferentAccess.new(:value => 'test')
@h.merge(another).values_at(:test, :value).should == ['me','test']
end
it "should delete the key" do
@h.delete(:test)
@h.any?.should be_false
@h[:test].should be_nil
end
end
end

View File

@ -0,0 +1,43 @@
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
require File.expand_path(File.dirname(__FILE__) + "/helper")
describe Webrat::Session do
it "should not pass empty params if data is and empty hash" do
session = Webrat::MerbSession.new
response = OpenStruct.new
response.status = 200
session.should_receive(:request).with('url', {:params=> nil, :method=>"GET", :headers=>nil}).and_return(response)
session.get('url', {}, nil)
end
%w{post put delete}.each do |request_method|
it "should call do request with method #{request_method.upcase} for a #{request_method} call" do
session = Webrat::MerbSession.new
response = OpenStruct.new
response.status = 200
session.should_receive(:request).with('url', {:params=>nil, :method=>request_method.upcase, :headers=>nil}).and_return(response)
session.send(request_method, 'url', {}, nil)
end
end
context "a session with a response" do
setup do
@session = Webrat::MerbSession.new
@response = OpenStruct.new
@response.status = 200
@response.body = 'test response'
@session.instance_variable_set(:@response, @response)
end
it "should return body of a request as a response_body" do
@session.response_body.should == @response.body
end
it "should return status of a request as a response_code" do
@session.response_code.should == @response.status
end
end
end

View File

@ -0,0 +1,75 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe "Nokogiri Extension" do
include Webrat::Matchers
def fail
raise_error(Spec::Expectations::ExpectationNotMetError)
end
before(:each) do
@text_and_password = <<-HTML
<div>
<input type="text"/>
<input type="password"/>
<span type="text"/>
</div>
HTML
@text_only = <<-HTML
<div>
<input type="text" disabled="disabled" />
</div>
HTML
@password_only = <<-HTML
<div>
<input type="password"/>
<div>
HTML
end
describe ":text" do
it "passes have_selector(:text) if a node with type=text exists" do
@text_and_password.should have_selector(":text")
end
it "passes not have_selector(:text) if no node with text=text exists" do
@password_only.should_not have_selector(":text")
end
it "fails have_selector(:text) if no node with type=text exists" do
lambda { @password_only.should have_selector(":text") }.should fail
end
it "fails not have_selector(:text) if a node with type=text exists" do
lambda { @text_only.should_not have_selector(":text") }.should fail
end
it "works together with other selectors" do
@text_and_password.should have_selector("input:text[type*='te']")
end
end
describe ":password" do
it "passes have_selector(:password) if a node with type=password exists" do
@text_and_password.should have_selector(":password")
end
it "passes not have_selector(:text) if no node with text=text exists" do
@text_only.should_not have_selector(":password")
end
it "fails have_selector(:password) if no node with type=password exists" do
lambda { @text_only.should have_selector(":password") }.should fail
end
it "fails not have_selector(:password) if a node with type=password exists" do
lambda { @password_only.should_not have_selector(":password") }.should fail
end
it "works together with other selectors" do
@text_and_password.should have_selector("input:password[type*='pa']")
end
end
end

View File

@ -1,6 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") require File.expand_path(File.dirname(__FILE__) + '/helper')
describe "attaches_file" do describe "attach_file" do
before do before do
@session = Webrat::TestSession.new @session = Webrat::TestSession.new
@ -14,7 +14,7 @@ describe "attaches_file" do
<form method="post" action="/widgets"> <form method="post" action="/widgets">
</form> </form>
EOS EOS
lambda { @session.attaches_file("Doc", "/some/path") }.should raise_error lambda { @session.attach_file("Doc", "/some/path") }.should raise_error
end end
it "should submit empty strings for blank file fields" do it "should submit empty strings for blank file fields" do
@ -25,7 +25,7 @@ describe "attaches_file" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/widgets", { "widget" => { "file" => "" } }) @session.should_receive(:post).with("/widgets", { "widget" => { "file" => "" } })
@session.clicks_button @session.click_button
end end
it "should submit the attached file" do it "should submit the attached file" do
@ -37,8 +37,8 @@ describe "attaches_file" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/widgets", { "widget" => { "file" => @uploaded_file } }) @session.should_receive(:post).with("/widgets", { "widget" => { "file" => @uploaded_file } })
@session.attaches_file "Document", @filename @session.attach_file "Document", @filename
@session.clicks_button @session.click_button
end end
it "should support collections" do it "should support collections" do
@ -52,9 +52,9 @@ describe "attaches_file" do
</form> </form>
EOS EOS
@session.should_receive(:post).with("/widgets", { "widget" => { "files" => [@uploaded_file, @uploaded_file] } }) @session.should_receive(:post).with("/widgets", { "widget" => { "files" => [@uploaded_file, @uploaded_file] } })
@session.attaches_file "Document", @filename @session.attach_file "Document", @filename
@session.attaches_file "Spreadsheet", @filename @session.attach_file "Spreadsheet", @filename
@session.clicks_button @session.click_button
end end
it "should allow the content type to be specified" do it "should allow the content type to be specified" do
@ -66,7 +66,7 @@ describe "attaches_file" do
</form> </form>
EOS EOS
ActionController::TestUploadedFile.should_receive(:new).with(@filename, "image/png").any_number_of_times ActionController::TestUploadedFile.should_receive(:new).with(@filename, "image/png").any_number_of_times
@session.attaches_file "Picture", @filename, "image/png" @session.attach_file "Picture", @filename, "image/png"
@session.clicks_button @session.click_button
end end
end end

View File

@ -0,0 +1,9 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require "active_support"
silence_warnings do
require "action_controller"
require "action_controller/integration"
end
require "webrat/rails"

View File

@ -1,4 +1,4 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require File.expand_path(File.dirname(__FILE__) + '/helper')
describe Webrat::RailsSession do describe Webrat::RailsSession do
it "should require a Rails Integration session to be initialized" do it "should require a Rails Integration session to be initialized" do
@ -19,31 +19,31 @@ describe Webrat::RailsSession do
Webrat::RailsSession.new(integration_session).response_code.should == 42 Webrat::RailsSession.new(integration_session).response_code.should == 42
end end
it "should delegate get to get_via_redirect on the integration session" do it "should delegate get to request_via_redirect on the integration session" do
integration_session = mock("integration session") integration_session = mock("integration session")
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(integration_session)
integration_session.should_receive(:get_via_redirect).with("url", "data", "headers") integration_session.should_receive(:request_via_redirect).with(:get, "url", "data", "headers")
rails_session.get("url", "data", "headers") rails_session.get("url", "data", "headers")
end end
it "should delegate post to post_via_redirect on the integration session" do it "should delegate post to request_via_redirect on the integration session" do
integration_session = mock("integration session") integration_session = mock("integration session")
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(integration_session)
integration_session.should_receive(:post_via_redirect).with("url", "data", "headers") integration_session.should_receive(:request_via_redirect).with(:post, "url", "data", "headers")
rails_session.post("url", "data", "headers") rails_session.post("url", "data", "headers")
end end
it "should delegate put to put_via_redirect on the integration session" do it "should delegate put to request_via_redirect on the integration session" do
integration_session = mock("integration session") integration_session = mock("integration session")
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(integration_session)
integration_session.should_receive(:put_via_redirect).with("url", "data", "headers") integration_session.should_receive(:request_via_redirect).with(:put, "url", "data", "headers")
rails_session.put("url", "data", "headers") rails_session.put("url", "data", "headers")
end end
it "should delegate delete to delete_via_redirect on the integration session" do it "should delegate delete to request_via_redirect on the integration session" do
integration_session = mock("integration session") integration_session = mock("integration session")
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(integration_session)
integration_session.should_receive(:delete_via_redirect).with("url", "data", "headers") integration_session.should_receive(:request_via_redirect).with(:delete, "url", "data", "headers")
rails_session.delete("url", "data", "headers") rails_session.delete("url", "data", "headers")
end end
@ -51,14 +51,14 @@ describe Webrat::RailsSession do
it "should just pass on the path" do it "should just pass on the path" do
integration_session = mock("integration session", :https! => nil) integration_session = mock("integration session", :https! => nil)
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(integration_session)
integration_session.should_receive(:get_via_redirect).with("/url", "data", "headers") integration_session.should_receive(:request_via_redirect).with(:get, "/url", "data", "headers")
rails_session.get("http://www.example.com/url", "data", "headers") rails_session.get("http://www.example.com/url", "data", "headers")
end end
end end
context "the URL is https://" do context "the URL is https://" do
it "should call #https! with true before the request" do it "should call #https! with true before the request" do
integration_session = mock("integration session", :get_via_redirect => nil) integration_session = mock("integration session", :request_via_redirect => nil)
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(integration_session)
integration_session.should_receive(:https!).with(true) integration_session.should_receive(:https!).with(true)
rails_session.get("https://www.example.com/url", "data", "headers") rails_session.get("https://www.example.com/url", "data", "headers")
@ -67,7 +67,7 @@ describe Webrat::RailsSession do
context "the URL is http://" do context "the URL is http://" do
it "should call #https! with true before the request" do it "should call #https! with true before the request" do
integration_session = mock("integration session", :get_via_redirect => nil) integration_session = mock("integration session", :request_via_redirect => nil)
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(integration_session)
integration_session.should_receive(:https!).with(false) integration_session.should_receive(:https!).with(false)
rails_session.get("http://www.example.com/url", "data", "headers") rails_session.get("http://www.example.com/url", "data", "headers")

View File

@ -7,7 +7,7 @@
# EOS # EOS
# @page.stub!(:url).and_return("/current") # @page.stub!(:url).and_return("/current")
# @session.should_receive(:get).with("/current", {}) # @session.should_receive(:get).with("/current", {})
# @session.clicks_button # @session.click_button
# end # end
# #
# it "should follow fully qualified secure local links" do # it "should follow fully qualified secure local links" do
@ -16,5 +16,5 @@
# EOS # EOS
# @session.should_receive(:https!).with(true) # @session.should_receive(:https!).with(true)
# @session.should_receive(:get).with("/page/sub", {}) # @session.should_receive(:get).with("/page/sub", {})
# @session.clicks_link "Jump to sub page" # @session.click_link "Jump to sub page"
# end # end