Compare commits
7 Commits
master
...
0-3-stable
Author | SHA1 | Date | |
---|---|---|---|
|
6da3371d84 | ||
|
3a956304a3 | ||
|
3d522a476a | ||
|
6d5205b7b7 | ||
|
5ccb10a411 | ||
|
ce799388c2 | ||
|
95e3260142 |
12
.gitignore
vendored
12
.gitignore
vendored
@ -4,15 +4,3 @@ pkg
|
||||
doc
|
||||
ri
|
||||
email.txt
|
||||
.svn
|
||||
log
|
||||
.project
|
||||
.loadpath
|
||||
*.swp
|
||||
results
|
||||
test_apps
|
||||
*.tmproj
|
||||
*.log
|
||||
*.pid
|
||||
bin
|
||||
vendor/gems
|
||||
|
13
Gemfile
13
Gemfile
@ -1,13 +0,0 @@
|
||||
gem "rake", "0.8.7"
|
||||
gem "rspec", "1.2.9"
|
||||
gem "diff-lcs", "1.1.2"
|
||||
gem "rack", "1.0.1"
|
||||
gem "nokogiri", "1.4.0"
|
||||
gem "merb-core", "1.0.15"
|
||||
gem "selenium-client", "1.2.17"
|
||||
gem "mechanize", "0.9.3"
|
||||
gem "rails", "2.3.4"
|
||||
gem "launchy", "0.3.3"
|
||||
gem "rack-test", "0.5.2"
|
||||
gem "sinatra", "0.9.4"
|
||||
gem "mongrel", "1.1.5"
|
359
History.txt
359
History.txt
@ -1,314 +1,3 @@
|
||||
== 0.7.1 / 2010-04-26
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Move verbose selenium output that can clutter build output behind setting
|
||||
* Added application_port_for_selenium to webrat configuration. The use case is when you want to test through a web server sitting in front of your application server. (Luke Melia)
|
||||
* New webrat configuration option selenium_firefox_profile which is passed to selenium server
|
||||
* Allow submit_form to select by CSS too (Damian Janowski)
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* Fix that current_url wasn't reflecting redirects in Mechanize [#332] (Emrys Ingersoll)
|
||||
* Fix attach_file with nested params [#341] (Álvaro Gil)
|
||||
* Fix that a 304 was considered a redirect (Larry Marburger)
|
||||
* Fix selection of LABEL elements in Selenium mode under IE [#317] (Damian Janowski, Noah Davis)
|
||||
* Fix have_xpath not matching negative expectation in the block [#182] (Luismi Cavallé)
|
||||
|
||||
== 0.7.0 / 2010-01-17
|
||||
|
||||
* Major enhancements
|
||||
|
||||
* Upgrade bundled Selenium server JAR to 2.0a1 (Henry Poydar and Jake Scruggs)
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Save and open page directory specified via configuration, defaults to tmp dir otherwise current dir (Noah Davis)
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* Added missing dependency "rack-test" to gemspec (LH #339) (Noah Davis)
|
||||
* Removed save_and_open_page's rewriting of static asset paths before saving (was not actually working) (Noah Davis)
|
||||
* Make "should contain" ignore extra whitespace when doing string comparisons (Noah Davis)
|
||||
* Make selenium matchers handle negative match more consistently with positive match (Luke Melia)
|
||||
|
||||
== 0.6.0 / 2009-11-28
|
||||
|
||||
REMOVED: Support for Hpricot + REXML as an alternative to Nokogiri.
|
||||
|
||||
Hpricot and REXML were difficult to work with, REXML is terribly slow,
|
||||
and Nokogiri is recommended even by the author of Hpricot (_why). Now
|
||||
that Nokogiri works on JRuby, Webrat is going to use it as its sole
|
||||
XML backend.
|
||||
|
||||
CHANGED: Due to a reorganization, if you're currently requiring "webrat/rspec-rails",
|
||||
please change your code to require "webrat/integrations/rspec-rails"
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Support Rails 2.3.4 JavaScript form authenticity tokens in simulated mode (Jonathan Weiss)
|
||||
* When a timeout occurs in wait_for, include the HTML from Selenium in the exception
|
||||
* Update the Merb support to be based directly on Rack (Simon Rozet)
|
||||
* Support multiple select fields (Kieran P)
|
||||
* When locating select options, always match against text, not HTML
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* Remove newlines from HTTP Basic authentication credentials (Michael Klett)
|
||||
* Require nokogiri form rspec-rails.rb (David Chelimsky)
|
||||
* Fix logger issue when running inside Cucumber (Damian Janowski)
|
||||
* Fix various issues related to submitting values with HTML entities (Kieran P)
|
||||
* Call #to_i on the :count option in matchers (Michael Christenson II)
|
||||
* Fix bug where multiline param values were getting truncated
|
||||
|
||||
== 0.5.3 / 2009-08-27
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Remove unnecessary requires which are to the wrong paths on Edge Rails
|
||||
|
||||
== 0.5.1 / 2009-08-18
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Base Webrat::MIME on Rack::Mime (Simon Rozet)
|
||||
* Support file uploads in Rack mode (Simon Rozet)
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* Fix bug in Webrat::Methods preventing Selenium mode from working [#277]
|
||||
|
||||
== 0.5.0 / 2009-08-12
|
||||
|
||||
* Major enhancements
|
||||
|
||||
* Depreacate :rack_test and :sinatra in favor of :rack, which uses Rack::Test (Simon Rozet)
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Don't require rubygems at runtime (Simon Rozet)
|
||||
|
||||
== 0.4.5 / 2009-08-10
|
||||
|
||||
* Major enhancements
|
||||
|
||||
* Ruby 1.9 compatibility (Michael Fellinger, Jakub Kuźma)
|
||||
* Improve performance (~2x) on JRuby by supporting Nokogiri
|
||||
* Added support for external app servers in selenium mode (basically don't start one) (Mike Gaffney)
|
||||
* Added support for uploading files for Merb (Ryan Carver)
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Upgrade to selenium-client to 1.2.16 (Brian Landau)
|
||||
* Upgrade selenium-server.jar to 1.0.1 (Brian Landau)
|
||||
* Make redirect detection work in the face of rational maths (like when ruby-units is active) (Piers Cawley)
|
||||
* Use Launchy to handle opening pages in the browser with cross-platform compatibility (Bryan Helmkamp)
|
||||
* Added support for field_labeled_locators ending in non word characters
|
||||
lh 148 (Zach Dennis)
|
||||
* Filled in tests on click link lh 195 (diabolo)
|
||||
* Added current_url to selenium session lh 215 (Luke Amdor)
|
||||
* Added silence spec to selenium lh 238 (Martin Gamsjaeger aka snusnu)
|
||||
* Added ability to configure the browser startup timeout for selenium lh 242 (Mike Gaffney, Mark Dodwell)
|
||||
* Added delegation for field_named lh194 (pivotal labs)
|
||||
* Added fix to keep from escaping field values in mechanize mode lh256 (jish)
|
||||
* Adding fixes for click button/link and made the integration specs pass for the same in selenium lh254 (Ldiehl, Matthias Marschall)
|
||||
* Adding clicking link by id in selenium mode lh221 (larrytheliquid)
|
||||
* Adding fix for have_selector and have_xpath in descendent blocks lh234 (Thomas Jack)
|
||||
* Adding fix for fields with labels with special characters (Thomas Jack, Mike Gaffney, Bryan Hemlkamp)
|
||||
* Deprecated current_page lh50 (Mike Gaffney)
|
||||
* Fixed issue with redirects and multiple hosts lh168 (Mutwin Kraus)
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* Wait for application servers socket on 0.0.0.0 instead of the application_address
|
||||
* Translate CSS and image paths with single quotes in save_and_open_page (Erin Staniland)
|
||||
|
||||
== 0.4.4 / 2009-04-06
|
||||
|
||||
* Major enhancements
|
||||
|
||||
* Make selenium process management code more robust and informative
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Add support for Rails javascript post links (Mark Menard)
|
||||
* Upgrade selenium-client dependency to 1.2.14, and update for new waiting
|
||||
API (Balint Erdi)
|
||||
* Change default app environment from "selenium" to "test"
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* Don't create a new instance of WWW::Mechanize for each request
|
||||
(Mark Menard)
|
||||
* Select fields with duplicate selected options sent an incorrect value (Noah Davis)
|
||||
|
||||
== 0.4.3 / 2009-03-17
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Support Rails 2.3. Use Rack::Utils to parse params (Matthew Ford)
|
||||
* Support for "modular" Sinatra app style (Simon Rozet)
|
||||
* Initial Merb and Sinatra compatibility for Selenium mode (Corey Donohoe)
|
||||
* When faced with a label with no for attribute, that contains a hidden field
|
||||
and another field, as can be the case in Rails 2.3's checkbox view,
|
||||
webrat now locates the non-hidden field. (Luke Melia)
|
||||
* Add application_framework config for Selenium mode to determine how to
|
||||
start and stop the app server (Corey Donohoe)
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* Fix following of absolute redirect URL in Sinatra (Simon Rozet)
|
||||
|
||||
== 0.4.2 / 2009-02-24
|
||||
|
||||
* Major enhancements
|
||||
|
||||
* Significant improvements to have_selector. It now supports specifying
|
||||
attributes in a hash and :count and :content options. See
|
||||
have_selector_spec.rb for more.
|
||||
* Add the same functionality mentioned above to have_xpath
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Squeeze extra whitespace out of failures messages from contain
|
||||
matcher
|
||||
* Detect infinite redirects and raise a Webrat::InfiniteRedirectError
|
||||
(Daniel Lucraft)
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* Properly quote single and double quotes strings in XPath
|
||||
* Fix warning caused by Nokogiri deprecating CSS::Parser.parse
|
||||
(Aaron Patterson)
|
||||
* Accept do/end blocks in matchers. [#157] (Peter Jaros)
|
||||
* Quote --chdir option to mongrel_rails to support RAILS_ROOTs with spaces
|
||||
(T.J. VanSlyke)
|
||||
|
||||
== 0.4.1 / 2009-01-31
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Support Sinatra 0.9 (Harry Vangberg)
|
||||
* Update query param parsing to work with latest Edge Rails
|
||||
* Added #redirected_to method to easily check where an external redirect was
|
||||
redirected to (Adam Greene)
|
||||
* Recognize input tags with type button (Lena Herrmann)
|
||||
* Add uncheck method to Selenium mode (Lee Bankewitz)
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* Make requests to a Rails app using a full URL instead of a relative path. This change
|
||||
is helpful for Rails apps that use subdomains. (John Hwang and Zach Dennis)
|
||||
* Follow redirects that are on the same domain but a different subdomain
|
||||
(Adam Greene)
|
||||
* rescue from Webrat::TimeoutError in selenium matchers which allows NegativeMatchers
|
||||
to behave correctly (Noah Davis)
|
||||
* Switch to using selenium.click instead of .check when checking a checkbox
|
||||
(Noah Davis)
|
||||
* Create tmp/pids directory if directory does not exist. (Amos King and Mike Gaffney)
|
||||
* Setup deprecated writers for the selenium_environment= and selenium_port= config
|
||||
* Ensure the previous pages params aren't passed through redirect (Daniel Lucraft and
|
||||
Bryan Helmkamp)
|
||||
* Labels should only search for fields within the current scope (Kyle Hargraves)
|
||||
|
||||
== 0.4.0 / 2009-01-18
|
||||
|
||||
* _IMPORTANT_ Breaking change:
|
||||
|
||||
* Removed init.rb auto-require of webrat/rails
|
||||
* Removed auto-require of webrat/rails when requiring webrat when RAILS_ENV is
|
||||
defined
|
||||
|
||||
In your env.rb or test_helper.rb file, ensure you have something like:
|
||||
|
||||
require "webrat"
|
||||
|
||||
Webrat.configure do |config|
|
||||
config.mode = :rails
|
||||
end
|
||||
|
||||
* Major enhancements
|
||||
|
||||
* Major improvements to Webrat::Selenium (Many contributors listed here)
|
||||
* Add assert_* methods for using Webrat's matchers w/o RSpec (Mike Gaffney, Amos King)
|
||||
* Added Webrat.configure method for Webrat configuration [#33] (Mike Gaffney)
|
||||
* Added select_time, select_date, and select_datetime to API. [#36] (Ben Mabey)
|
||||
* Use Hpricot and REXML when not parsing with Nokogiri (on JRuby, for example)
|
||||
|
||||
* Minor enhancements
|
||||
|
||||
* Added Selenium grid configuration and support. (Amos King && Cornel Borcean)
|
||||
* Support passing an ActiveRecord model to #within when in Rails mode [#68] (Luke Melia)
|
||||
* Make assert_* matchers in rails mode increment the assertions count [#123] (Amos King)
|
||||
* Added assert_* matchers to selenium matchers [#110] (Amos King)
|
||||
* Added assert_contain, assert_not_contain [#86] (Mike Gaffney, Amos King)
|
||||
* Add configuration options for the Selenium environment and port (Kieran Pilkington)
|
||||
* Maximize the browser window after initializing Selenium (Luke Melia)
|
||||
* Better inspect output for Webrat elements
|
||||
* Sets the Webrat mode with Configuration#mode= in the config block [#85] (Mike Gaffney)
|
||||
* Detect if the document is XML or HTML using the Content-Type when in Rails mode
|
||||
* Expose #selenium method for direct access to Selenium client
|
||||
* Check nokogiri gem version before requiring nokogiri
|
||||
* Include the Selenium server jar file in the gem (Bryan Helmkamp, Ben Schwarz)
|
||||
* Added key_down, key_up and fire_event to Selenium session (Fernando Garcia)
|
||||
* Fix outputing README during Rails plugin install (Fernando Garcia)
|
||||
* Strip newlines when matching label text (Miha Filej)
|
||||
* Add simple support for accessing Webrat's matchers from RSpec by requiring
|
||||
"webrat/rspec-rails" (David Chelimsky)
|
||||
* Support save_and_open_page in Windows and Cygwin (Mike Gaffney)
|
||||
* Added RadioField#checked? to indicated whether or not a radio button is checked
|
||||
(Luke Melia)
|
||||
* Add spec:jruby rake task for running Webrat's spec suite with JRuby
|
||||
* Added field_by_xpath to locate a Webrat::Field using arbitrary XPath expressions
|
||||
* Helpful error message for missing option values [#40] (Ben Mabey)
|
||||
* Add set_hidden_field method (Noah Davis, Bryan Helmkamp)
|
||||
* Add submit_form method for submitting a form by ID (Noah Davis, Bryan Helmkamp)
|
||||
* Switch to using Nokogiri.parse for simple XML/XHTML autodetection [#66]
|
||||
* Removed Webrat.root method, which seemed to be unused
|
||||
* Added automatic starting and stopping of the Selenium server and a Mongrel Rails
|
||||
app server when using webrat/selenium
|
||||
* Switch to using selenium-client gem and vendor selenium-server.jar (Luke Melia)
|
||||
* Added gemspec so the gem builds on GitHub now
|
||||
* Deprecate old style methods (fills_in is deprecated in favor of fill_in, etc.)
|
||||
* Improvements to the README and RDoc (Bryan Helmkamp, Mike Gaffney)
|
||||
* Allow clicking links by id and id regexp (Mike Gaffney)
|
||||
* Raise Webrat::DisabledFieldError when attempting to manipulate a disabled field
|
||||
* Raise Webrat::NotFoundErrors when an element is not found
|
||||
* Raise Webrat::PageLoadError when a failure occurs so that application exceptions
|
||||
can be more accurately tested (Ryan Briones)
|
||||
* Helpful error message for missing option in select box. [#40] (Ben Mabey)
|
||||
* Extracted save_and_open page to make it usable in Selenium mode (Luke Melia)
|
||||
* Added save_and_open_screengrab for Selenium mode (Luke Melia)
|
||||
|
||||
* Bug fixes
|
||||
|
||||
* field_labeled should disregard labels without matching fields (Kyle Hargraves)
|
||||
* Fixed bug where Scope was creating a new DOM rather than re-using the existing DOM.
|
||||
[#105] (Zach Dennis)
|
||||
* Support Rails > v2.2 by using ActionController::RequestParser for param parsing [#107]
|
||||
(Marcello Nuccio)
|
||||
* Raise a Webrat::NotFoundError if the scope passed to #within doesn't exist [#90]
|
||||
* Match against link _text_ which decodes character references.
|
||||
Useful for multibyte languages like Japanese (moronatural@gmail.com)
|
||||
* Fix params hash generation for Mechanize when Merb is not defined [#62]
|
||||
* Expose some Webrat methods that were missing from the Webrat::Methods module
|
||||
(Low Chin Chau)
|
||||
* Allow mechanize session to pass through basic auth (Ryan Briones)
|
||||
* Improvements to the Mechanize support (Jeremy Burks)
|
||||
* Fix following fully qualified local links (Lawrence Pit)
|
||||
* Fixed bug where Webrat would lose complex parameters (like foo[bar[baz]][])
|
||||
in Merb due to not correctly merging Mashes. (Drew Colthorp)
|
||||
* Extend Rails' ActionController::IntegrationTest instead of
|
||||
ActionController::Integration::Session (Fixes using Webrat's #select method and
|
||||
avoids usage of method_missing)
|
||||
* Ensure that Webrat::MechanizeSession.request_page always uses an absolute
|
||||
URL. (Graham Ashton)
|
||||
* Strip anchor tags from URIs before passing to Rails integration session
|
||||
(Noah Davis)
|
||||
* Treat text and regexp when matching Selenium buttons (Ross Kaffenberger)
|
||||
* Allow SeleniumSession's click_button to be called without an argument without
|
||||
blowing up (Luke Melia)
|
||||
|
||||
== 0.3.4 / 2008-12-29
|
||||
|
||||
* 1 Minor enhancement
|
||||
@ -329,30 +18,27 @@ CHANGED: Due to a reorganization, if you're currently requiring "webrat/rspec-ra
|
||||
|
||||
* 1 Minor enhancement
|
||||
|
||||
* 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)
|
||||
* 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
|
||||
|
||||
* 1 Minor enhancement
|
||||
|
||||
* Use @_webrat_session instance variable instead of @session for Merb integration
|
||||
to avoid collisions
|
||||
* Use @_webrat_session instance variable instead of @session for Merb integration to avoid collisions
|
||||
|
||||
== 0.3.0 / 2008-11-07
|
||||
|
||||
* 4 Major enhancements
|
||||
* 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)
|
||||
|
||||
* 37 Minor enhancements
|
||||
* 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 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)
|
||||
@ -365,29 +51,25 @@ CHANGED: Due to a reorganization, if you're currently requiring "webrat/rspec-ra
|
||||
* 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)
|
||||
* 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
|
||||
* 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)
|
||||
* Add support for redirect_to :back by sending HTTP_REFERER headers (Hendrik Volkmer)
|
||||
* 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 and non-JS implementations (Luke Melia and Bryan Helmkamp)
|
||||
* Add support for disabling JavaScript when clicking a link to enable testing of both JS
|
||||
and non-JS implementations (Luke Melia and Bryan Helmkamp)
|
||||
* Support  's as spaces in matching link text (Luke Melia)
|
||||
* Support button elements (Nick Sieger)
|
||||
* 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)
|
||||
* Added support for matching alt attributes in fields (primarly for clicks_button)
|
||||
(Aaron Quint)
|
||||
* 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) (Aaron Quint)
|
||||
* Support '&' in submitted values (Kyle Hargraves)
|
||||
* Support clicking links by title (Dan Barry)
|
||||
* Added missing spec for clicking image buttons (Tim Harper)
|
||||
@ -395,7 +77,7 @@ CHANGED: Due to a reorganization, if you're currently requiring "webrat/rspec-ra
|
||||
* Add support to click_button for IDs (Gwyn Morfey)
|
||||
* Miscellaneous core refactorings (Jan Suchal)
|
||||
|
||||
* 8 Bug fixes
|
||||
* Bug fixes
|
||||
|
||||
* Fix initialization of WWW::Mechanize (Derek Kastner)
|
||||
* Don't open blank pages in the browser (Kyle Hargraves)
|
||||
@ -404,8 +86,7 @@ CHANGED: Due to a reorganization, if you're currently requiring "webrat/rspec-ra
|
||||
* Fix bug with empty select list option (Kyle Hargraves)
|
||||
* Fix regression of not sending default values in password fields
|
||||
* 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)
|
||||
* 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
|
||||
|
||||
@ -424,27 +105,23 @@ CHANGED: Due to a reorganization, if you're currently requiring "webrat/rspec-ra
|
||||
* Added clicks_link_within(selector, link_text), allowing restricting link search
|
||||
to within a given css selector (Luke Melia)
|
||||
* 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 (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 (Kyle Hargraves)
|
||||
* Change clicks_link to find the shortest matching link (Luke Melia)
|
||||
* Improve matching for labels in potentially ambiguous cases
|
||||
|
||||
* 7 Bug fixes
|
||||
|
||||
* Fix incorrect serializing of collection inputs, i.e. name contains []
|
||||
(Kamal Fariz Mahyuddi)
|
||||
* Fix incorrect serializing of collection inputs, i.e. name contains [] (Kamal Fariz Mahyuddi)
|
||||
* Serialize empty text field values just like browsers (Kamal Fariz Mahyuddi)
|
||||
* Quick fix to avoid @dom not initialized warnings (Kamal Fariz Mahyuddi)
|
||||
* 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 (David Chelimsky)
|
||||
* Support param hashes nested more than one level (David Chelimsky)
|
||||
|
||||
== 0.1.0 / 2007-11-28
|
||||
|
||||
* 1 major enhancement
|
||||
|
||||
* Birthday!
|
||||
|
||||
|
85
README.rdoc
85
README.rdoc
@ -1,85 +0,0 @@
|
||||
= Webrat - Ruby Acceptance Testing for Web applications
|
||||
|
||||
- http://gitrdoc.com/brynary/webrat
|
||||
- http://groups.google.com/group/webrat
|
||||
- http://webrat.lighthouseapp.com/
|
||||
- http://github.com/brynary/webrat
|
||||
- #webrat on Freenode
|
||||
|
||||
== Description
|
||||
|
||||
Webrat lets you quickly write expressive and robust acceptance tests for a Ruby
|
||||
web application.
|
||||
|
||||
== Features
|
||||
|
||||
* Browser Simulator for expressive, high level acceptance testing without the
|
||||
performance hit and browser dependency of Selenium or Watir (See Webrat::Session)
|
||||
* Use the same API for Browser Simulator and real Selenium tests using
|
||||
Webrat::Selenium when necessary (eg. for testing AJAX interactions)
|
||||
* Supports multiple Ruby web frameworks: Rails, Merb and Sinatra
|
||||
* Supports popular test frameworks: RSpec, Cucumber, Test::Unit and Shoulda
|
||||
* Webrat::Matchers API for verifying rendered HTML using CSS, XPath, etc.
|
||||
|
||||
== Example
|
||||
|
||||
class SignupTest < ActionController::IntegrationTest
|
||||
|
||||
def test_trial_account_sign_up
|
||||
visit home_path
|
||||
click_link "Sign up"
|
||||
fill_in "Email", :with => "good@example.com"
|
||||
select "Free account"
|
||||
click_button "Register"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Behind the scenes, Webrat will ensure:
|
||||
|
||||
* If a link, form field or button is missing, the test will fail.
|
||||
* If a URL is invalid, the test will fail.
|
||||
* If a page load or form submission is unsuccessful, the test will fail.
|
||||
|
||||
== Installing Nokogiri
|
||||
|
||||
Users of Debian Linux (e.g. Ubuntu) need to run:
|
||||
|
||||
sudo apt-get install libxslt1-dev libxml2-dev.
|
||||
|
||||
Otherwise the Nokogiri gem, which Webrat depends on, won't install properly.
|
||||
|
||||
== Install for Rails
|
||||
|
||||
To install the latest release as a gem:
|
||||
|
||||
sudo gem install webrat
|
||||
|
||||
To install the latest code as a plugin: (_Note:_ This may be less stable than using a released version)
|
||||
|
||||
script/plugin install git://github.com/brynary/webrat.git
|
||||
|
||||
In your test_helper.rb or env.rb (for Cucumber) add:
|
||||
|
||||
require "webrat"
|
||||
|
||||
Webrat.configure do |config|
|
||||
config.mode = :rails
|
||||
end
|
||||
|
||||
== Install with Merb
|
||||
|
||||
Merb 1.0 has built-in, seamless Webrat support. Just start using
|
||||
methods from Webrat::Session in your specs.
|
||||
|
||||
== Authors
|
||||
|
||||
- Maintained by {Bryan Helmkamp}[mailto:bryan@brynary.com]
|
||||
- Original code written by {Seth Fitzsimmons}[mailto:seth@mojodna.net]
|
||||
- Initial development was sponsored by EastMedia[http://www.eastmedia.com]
|
||||
- Many other contributors. See attributions in History.txt
|
||||
|
||||
== License
|
||||
|
||||
Copyright (c) 2007-2008 Bryan Helmkamp, Seth Fitzsimmons.
|
||||
See MIT-LICENSE.txt in this directory.
|
90
README.txt
Normal file
90
README.txt
Normal file
@ -0,0 +1,90 @@
|
||||
=== Webrat
|
||||
|
||||
- [Code on GitHub](http://github.com/brynary/webrat)
|
||||
- [Tickets on Lighthouse](http://webrat.lighthouseapp.com/)
|
||||
|
||||
=== Description
|
||||
|
||||
Webrat (_Ruby Acceptance Testing for Web applications_)
|
||||
lets you quickly write robust and thorough acceptance tests for a Ruby
|
||||
web application. By leveraging the DOM, it can run tests similarly to an
|
||||
in-browser testing solution without the associated performance hit (and
|
||||
browser dependency). The result is tests that are less fragile and more
|
||||
effective at verifying that the app will respond properly to users.
|
||||
|
||||
When comparing Webrat with an in-browser testing solution like Watir or
|
||||
Selenium, the primary consideration should be how much JavaScript the
|
||||
application uses. In-browser testing is currently the only way to test JS, and
|
||||
that may make it a requirement for your project. If JavaScript is not central
|
||||
to your application, Webrat is a simpler, effective solution that will let you
|
||||
run your tests much faster and more frequently.
|
||||
|
||||
Initial development was sponsored by [EastMedia](http://www.eastmedia.com).
|
||||
|
||||
=== Synopsis
|
||||
|
||||
def test_sign_up
|
||||
visit "/"
|
||||
click_link "Sign up"
|
||||
fill_in "Email", :with => "good@example.com"
|
||||
select "Free account"
|
||||
click_button "Register"
|
||||
...
|
||||
end
|
||||
|
||||
Behind the scenes, this will perform the following work:
|
||||
|
||||
1. Verify that loading the home page is successful
|
||||
2. Verify that a "Sign up" link exists on the home page
|
||||
3. Verify that loading the URL pointed to by the "Sign up" link leads to a
|
||||
successful page
|
||||
4. Verify that there is an "Email" input field on the Sign Up page
|
||||
5. Verify that there is an select field on the Sign Up page with an option for
|
||||
"Free account"
|
||||
6. Verify that there is a "Register" submit button on the page
|
||||
7. Verify that submitting the Sign Up form with the values "good@example.com"
|
||||
and "Free account" leads to a successful page
|
||||
|
||||
Take special note of the things _not_ specified in that test, that might cause
|
||||
tests to break unnecessarily as your application evolves:
|
||||
|
||||
- The input field IDs or names (e.g. "user_email" or "user[email]"), which
|
||||
could change if you rename a model
|
||||
- The ID of the form element (Webrat can do a good job of guessing, even if
|
||||
there are multiple forms on the page.)
|
||||
- The URLs of links followed
|
||||
- The URL the form submission should be sent to, which could change if you
|
||||
adjust your routes or controllers
|
||||
- The HTTP method for the login request
|
||||
|
||||
A test written with Webrat can handle these changes to these without any modifications.
|
||||
|
||||
=== 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:
|
||||
|
||||
sudo gem install webrat
|
||||
|
||||
In your stories/helper.rb:
|
||||
|
||||
require "webrat"
|
||||
|
||||
You could also unpack the gem into vendor/plugins.
|
||||
|
||||
=== Authors
|
||||
|
||||
- Maintained by [Bryan Helmkamp](mailto:bryan@brynary.com)
|
||||
- Original code written by [Seth Fitzsimmons](mailto:seth@mojodna.net)
|
||||
- Many other contributors. See attributions in History.txt
|
||||
|
||||
=== License
|
||||
|
||||
Copyright (c) 2007 Bryan Helmkamp, Seth Fitzsimmons.
|
||||
See MIT-LICENSE.txt in this directory.
|
190
Rakefile
190
Rakefile
@ -1,143 +1,89 @@
|
||||
begin
|
||||
require 'rubygems'
|
||||
require "rake/gempackagetask"
|
||||
require 'rake/rdoctask'
|
||||
require "rake/clean"
|
||||
require 'spec'
|
||||
require 'spec/rake/spectask'
|
||||
rescue LoadError
|
||||
desc "Run specs"
|
||||
task(:spec) { $stderr.puts '`gem install rspec` to run specs' }
|
||||
else
|
||||
require 'spec/rake/verify_rcov'
|
||||
require './lib/webrat.rb'
|
||||
|
||||
##############################################################################
|
||||
# Package && release
|
||||
##############################################################################
|
||||
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/**/*"]
|
||||
|
||||
# rdoc
|
||||
s.has_rdoc = true
|
||||
s.extra_rdoc_files = %w(README.txt MIT-LICENSE.txt)
|
||||
|
||||
# Dependencies
|
||||
s.add_dependency "nokogiri", ">= 1.1.0"
|
||||
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"
|
||||
task :publish_rdoc => :docs do
|
||||
sh "scp -r doc/ brynary.com:/apps/uploads/webrat"
|
||||
end
|
||||
|
||||
desc "Run API and Core specs"
|
||||
Spec::Rake::SpecTask.new do |t|
|
||||
t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
|
||||
t.spec_files = FileList['spec/public/**/*_spec.rb'] + FileList['spec/private/**/*_spec.rb']
|
||||
t.spec_files = FileList['spec/**/*_spec.rb']
|
||||
end
|
||||
|
||||
desc "Run all specs in spec directory with RCov"
|
||||
Spec::Rake::SpecTask.new(:rcov) do |t|
|
||||
t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
|
||||
t.spec_files = FileList['spec/public/**/*_spec.rb'] + FileList['spec/private/**/*_spec.rb']
|
||||
t.spec_files = FileList['spec/**/*_spec.rb']
|
||||
t.rcov = true
|
||||
t.rcov_opts = lambda do
|
||||
IO.readlines(File.dirname(__FILE__) + "/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
|
||||
end
|
||||
end
|
||||
|
||||
RCov::VerifyTask.new(:verify_rcov => :rcov) do |t|
|
||||
t.threshold = 96.2 # Make sure you have rcov 0.7 or higher!
|
||||
end
|
||||
|
||||
desc "Run everything against multiruby"
|
||||
task :multiruby do
|
||||
result = system "multiruby -S rake spec"
|
||||
raise "Multiruby tests failed" unless result
|
||||
result = system "jruby -S rake spec"
|
||||
raise "JRuby tests failed" unless result
|
||||
|
||||
Dir.chdir "spec/integration/rails" do
|
||||
result = system "multiruby -S rake test_unit:rails"
|
||||
raise "Rails integration tests failed" unless result
|
||||
|
||||
result = system "jruby -S rake test_unit:rails"
|
||||
raise "Rails integration tests failed" unless result
|
||||
task :default do
|
||||
Rake::Task["verify_rcov"].invoke
|
||||
end
|
||||
|
||||
Dir.chdir "spec/integration/merb" do
|
||||
result = system "multiruby -S rake spec"
|
||||
raise "Merb integration tests failed" unless result
|
||||
|
||||
result = system "jruby -S rake spec"
|
||||
raise "Rails integration tests failed" unless result
|
||||
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
|
||||
|
||||
Dir.chdir "spec/integration/sinatra" do
|
||||
result = system "multiruby -S rake test"
|
||||
raise "Sinatra integration tests failed" unless result
|
||||
|
||||
result = system "jruby -S rake test"
|
||||
raise "Sinatra integration tests failed" unless result
|
||||
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
|
||||
|
||||
Dir.chdir "spec/integration/rack" do
|
||||
result = system "multiruby -S rake test"
|
||||
raise "Rack integration tests failed" unless result
|
||||
|
||||
result = system "jruby -S rake test"
|
||||
raise "Rack integration tests failed" unless result
|
||||
end
|
||||
|
||||
puts
|
||||
puts "Multiruby OK!"
|
||||
end
|
||||
|
||||
desc "Run each spec in isolation to test for dependency issues"
|
||||
task :spec_deps do
|
||||
Dir["spec/**/*_spec.rb"].each do |test|
|
||||
if !system("spec #{test} &> /dev/null")
|
||||
puts "Dependency Issues: #{test}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
namespace :spec do
|
||||
desc "Run the integration specs"
|
||||
task :integration => [
|
||||
"integration:rack",
|
||||
"integration:sinatra",
|
||||
"integration:merb",
|
||||
"integration:mechanize",
|
||||
"integration:rails:webrat",
|
||||
"integration:rails:selenium",
|
||||
]
|
||||
|
||||
namespace :integration do
|
||||
namespace :rails do
|
||||
task :selenium do
|
||||
Dir.chdir "spec/integration/rails" do
|
||||
result = system "rake -rubygems test_unit:selenium"
|
||||
raise "Rails integration tests failed" unless result
|
||||
end
|
||||
end
|
||||
|
||||
task :webrat do
|
||||
Dir.chdir "spec/integration/rails" do
|
||||
result = system "rake -rubygems test_unit:rails"
|
||||
raise "Rails integration tests failed" unless result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run the Merb integration specs"
|
||||
task :merb do
|
||||
Dir.chdir "spec/integration/merb" do
|
||||
result = system "rake -rubygems spec"
|
||||
raise "Merb integration tests failed" unless result
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run the Sinatra integration specs"
|
||||
task :sinatra do
|
||||
Dir.chdir "spec/integration/sinatra" do
|
||||
result = system "rake -rubygems test"
|
||||
raise "Sinatra integration tests failed" unless result
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run the Sinatra integration specs"
|
||||
task :rack do
|
||||
Dir.chdir "spec/integration/rack" do
|
||||
result = system "rake -rubygems test"
|
||||
raise "Rack integration tests failed" unless result
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run the Mechanize integration specs"
|
||||
task :mechanize do
|
||||
Dir.chdir "spec/integration/mechanize" do
|
||||
result = system "rake -rubygems spec"
|
||||
raise "Mechanize integration tests failed" unless result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Removes trailing whitespace'
|
||||
task :whitespace do
|
||||
sh %{find . -name '*.rb' -exec sed -i '' 's/ *$//g' {} \\;}
|
||||
end
|
||||
|
||||
task :default => :spec
|
||||
|
10
TODO.txt
Normal file
10
TODO.txt
Normal file
@ -0,0 +1,10 @@
|
||||
Run tests in separate processes to eliminate constant-level dependencies
|
||||
Add rake tasks for selenium runs
|
||||
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
|
||||
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
|
118
Thorfile
118
Thorfile
@ -1,118 +0,0 @@
|
||||
module GemHelpers
|
||||
|
||||
def generate_gemspec
|
||||
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), "lib")))
|
||||
require "webrat"
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "webrat"
|
||||
s.version = Webrat::VERSION
|
||||
s.author = "Bryan Helmkamp"
|
||||
s.email = "bryan@brynary.com"
|
||||
s.homepage = "http://github.com/brynary/webrat"
|
||||
s.summary = "Ruby Acceptance Testing for Web applications"
|
||||
s.description = <<-EOS.strip
|
||||
Webrat lets you quickly write expressive and robust acceptance tests
|
||||
for a Ruby web application. It supports simulating a browser inside
|
||||
a Ruby process to avoid the performance hit and browser dependency of
|
||||
Selenium or Watir, but the same API can also be used to drive real
|
||||
Selenium tests when necessary (eg. for testing AJAX interactions).
|
||||
Most Ruby web frameworks and testing frameworks are supported.
|
||||
EOS
|
||||
s.rubyforge_project = "webrat"
|
||||
|
||||
require "git"
|
||||
repo = Git.open(".")
|
||||
|
||||
s.files = normalize_files(repo.ls_files.keys - repo.lib.ignored_files)
|
||||
s.test_files = normalize_files(Dir['spec/**/*.rb'] - repo.lib.ignored_files)
|
||||
|
||||
s.has_rdoc = true
|
||||
s.extra_rdoc_files = %w[README.rdoc MIT-LICENSE.txt History.txt]
|
||||
|
||||
s.add_dependency "nokogiri", ">= 1.2.0"
|
||||
s.add_dependency "rack", ">= 1.0"
|
||||
s.add_dependency "rack-test", ">= 0.5.3"
|
||||
end
|
||||
end
|
||||
|
||||
def normalize_files(array)
|
||||
# only keep files, no directories, and sort
|
||||
array.select do |path|
|
||||
File.file?(path)
|
||||
end.sort
|
||||
end
|
||||
|
||||
# Adds extra space when outputting an array. This helps create better version
|
||||
# control diffs, because otherwise it is all on the same line.
|
||||
def prettyify_array(gemspec_ruby, array_name)
|
||||
gemspec_ruby.gsub(/s\.#{array_name.to_s} = \[.+?\]/) do |match|
|
||||
leadin, files = match[0..-2].split("[")
|
||||
leadin + "[\n #{files.split(",").join(",\n ")}\n ]"
|
||||
end
|
||||
end
|
||||
|
||||
def read_gemspec
|
||||
@read_gemspec ||= eval(File.read("webrat.gemspec"))
|
||||
end
|
||||
|
||||
def sh(command)
|
||||
puts command
|
||||
system command
|
||||
end
|
||||
end
|
||||
|
||||
class Default < Thor
|
||||
include GemHelpers
|
||||
|
||||
desc "gemspec", "Regenerate webrat.gemspec"
|
||||
def gemspec
|
||||
File.open("webrat.gemspec", "w") do |file|
|
||||
gemspec_ruby = generate_gemspec.to_ruby
|
||||
gemspec_ruby = prettyify_array(gemspec_ruby, :files)
|
||||
gemspec_ruby = prettyify_array(gemspec_ruby, :test_files)
|
||||
gemspec_ruby = prettyify_array(gemspec_ruby, :extra_rdoc_files)
|
||||
|
||||
file.write gemspec_ruby
|
||||
end
|
||||
|
||||
puts "Wrote gemspec to webrat.gemspec"
|
||||
read_gemspec.validate
|
||||
end
|
||||
|
||||
desc "build", "Build a webrat gem"
|
||||
def build
|
||||
sh "gem build webrat.gemspec"
|
||||
FileUtils.mkdir_p "pkg"
|
||||
FileUtils.mv read_gemspec.file_name, "pkg"
|
||||
end
|
||||
|
||||
desc "install", "Install the latest built gem"
|
||||
def install
|
||||
sh "gem install --local pkg/#{read_gemspec.file_name}"
|
||||
end
|
||||
|
||||
desc "release", "Release the current branch to GitHub and Gemcutter"
|
||||
def release
|
||||
gemspec
|
||||
build
|
||||
Release.new.tag
|
||||
Release.new.gem
|
||||
end
|
||||
end
|
||||
|
||||
class Release < Thor
|
||||
include GemHelpers
|
||||
|
||||
desc "tag", "Tag the gem on the origin server"
|
||||
def tag
|
||||
release_tag = "v#{read_gemspec.version}"
|
||||
sh "git tag -a #{release_tag} -m 'Tagging #{release_tag}'"
|
||||
sh "git push origin #{release_tag}"
|
||||
end
|
||||
|
||||
desc "gem", "Push the gem to Gemcutter"
|
||||
def gem
|
||||
sh "gem push pkg/#{read_gemspec.file_name}"
|
||||
end
|
||||
end
|
3
init.rb
Normal file
3
init.rb
Normal file
@ -0,0 +1,3 @@
|
||||
if RAILS_ENV == "test" || RAILS_ENV == "selenium"
|
||||
require File.join(File.dirname(__FILE__), "lib", "webrat")
|
||||
end
|
@ -1 +1 @@
|
||||
puts IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))
|
||||
puts IO.read(File.join(File.dirname(__FILE__), 'README'))
|
||||
|
@ -1,18 +1,39 @@
|
||||
require "rack"
|
||||
require "nokogiri"
|
||||
require "rubygems"
|
||||
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
module Webrat
|
||||
VERSION = "0.7.2.pre"
|
||||
VERSION = '0.3.4'
|
||||
|
||||
autoload :MechanizeAdapter, "webrat/adapters/mechanize"
|
||||
autoload :MerbAdapter, "webrat/adapters/merb"
|
||||
autoload :RackAdapter, "webrat/adapters/rack"
|
||||
autoload :RailsAdapter, "webrat/adapters/rails"
|
||||
autoload :SinatraAdapter, "webrat/adapters/sinatra"
|
||||
def self.root #:nodoc:
|
||||
defined?(RAILS_ROOT) ? RAILS_ROOT : Merb.root
|
||||
end
|
||||
|
||||
# The common base class for all exceptions raised by Webrat.
|
||||
class WebratError < StandardError
|
||||
def self.require_xml
|
||||
gem "nokogiri", ">= 1.1.0"
|
||||
|
||||
# We need Nokogiri's CSS to XPath support, even if using
|
||||
# REXML and Hpricot for parsing and searching
|
||||
require "nokogiri"
|
||||
|
||||
if on_java?
|
||||
require "hpricot"
|
||||
require "rexml/document"
|
||||
else
|
||||
require "webrat/core/nokogiri"
|
||||
end
|
||||
end
|
||||
|
||||
def self.on_java?
|
||||
RUBY_PLATFORM =~ /java/
|
||||
end
|
||||
end
|
||||
|
||||
Webrat.require_xml
|
||||
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
|
||||
|
@ -1,94 +0,0 @@
|
||||
require "mechanize"
|
||||
|
||||
module Webrat #:nodoc:
|
||||
class MechanizeAdapter #:nodoc:
|
||||
extend Forwardable
|
||||
|
||||
Mechanize = WWW::Mechanize if defined?(WWW::Mechanize)
|
||||
|
||||
attr_accessor :response
|
||||
alias :page :response
|
||||
|
||||
def initialize(*args)
|
||||
end
|
||||
|
||||
def request_page(url, http_method, data) #:nodoc:
|
||||
super(absolute_url(url), http_method, data)
|
||||
end
|
||||
|
||||
def get(url, data, headers_argument_not_used = nil)
|
||||
@response = mechanize.get(url, data)
|
||||
end
|
||||
|
||||
def post(url, data, headers_argument_not_used = nil)
|
||||
post_data = data.inject({}) do |memo, param|
|
||||
case param
|
||||
when Hash
|
||||
param.each {|attribute, value| memo[attribute] = value }
|
||||
memo
|
||||
when Array
|
||||
case param.last
|
||||
when Hash
|
||||
param.last.each {|attribute, value| memo["#{param.first}[#{attribute}]"] = value }
|
||||
else
|
||||
memo[param.first] = param.last
|
||||
end
|
||||
memo
|
||||
end
|
||||
end
|
||||
@response = mechanize.post(url, post_data)
|
||||
end
|
||||
|
||||
def response_body
|
||||
@response.content
|
||||
end
|
||||
|
||||
def response_code
|
||||
@response.code.to_i
|
||||
end
|
||||
|
||||
def response_headers
|
||||
@response.header
|
||||
end
|
||||
|
||||
def mechanize
|
||||
@mechanize ||= begin
|
||||
mechanize = Mechanize.new
|
||||
mechanize.redirect_ok = false
|
||||
mechanize
|
||||
end
|
||||
end
|
||||
|
||||
def_delegators :mechanize, :basic_auth
|
||||
|
||||
def absolute_url(url) #:nodoc:
|
||||
current_host, current_path = split_current_url
|
||||
if url =~ Regexp.new('^https?://')
|
||||
url
|
||||
elsif url =~ Regexp.new('^/')
|
||||
current_host + url
|
||||
elsif url =~ Regexp.new('^\.')
|
||||
current_host + absolute_path(current_path, url)
|
||||
else
|
||||
url
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def split_current_url
|
||||
current_url =~ Regexp.new('^(https?://[^/]+)(/.*)?')
|
||||
[Regexp.last_match(1), Regexp.last_match(2)]
|
||||
end
|
||||
|
||||
def absolute_path(current_path, url)
|
||||
levels_up = url.split('/').find_all { |x| x == '..' }.size
|
||||
ancestor = if current_path.nil?
|
||||
""
|
||||
else
|
||||
current_path.split("/")[0..(-1 - levels_up)].join("/")
|
||||
end
|
||||
descendent = url.split("/")[levels_up..-1].join
|
||||
"#{ancestor}/#{descendent}"
|
||||
end
|
||||
end
|
||||
end
|
@ -1,11 +0,0 @@
|
||||
require "webrat/integrations/merb"
|
||||
|
||||
module Webrat
|
||||
class MerbAdapter < RackAdapter #:nodoc:
|
||||
def initialize(context=nil)
|
||||
app = context.respond_to?(:app) ?
|
||||
context.app : Merb::Rack::Application.new
|
||||
super(Rack::Test::Session.new(Rack::MockSession.new(app, "www.example.com")))
|
||||
end
|
||||
end
|
||||
end
|
@ -1,29 +0,0 @@
|
||||
require "rack/test"
|
||||
|
||||
module Webrat
|
||||
class RackAdapter
|
||||
extend Forwardable
|
||||
|
||||
def_delegators :@session, :get, :post, :put, :delete
|
||||
|
||||
def initialize(session) #:nodoc:
|
||||
@session = session
|
||||
end
|
||||
|
||||
def response_body
|
||||
response.body
|
||||
end
|
||||
|
||||
def response_code
|
||||
response.status
|
||||
end
|
||||
|
||||
def response_headers
|
||||
response.headers
|
||||
end
|
||||
|
||||
def response
|
||||
@session.last_response
|
||||
end
|
||||
end
|
||||
end
|
@ -1,77 +0,0 @@
|
||||
require "webrat/integrations/rails"
|
||||
require "action_controller/record_identifier"
|
||||
|
||||
module Webrat
|
||||
class RailsAdapter #:nodoc:
|
||||
include ActionController::RecordIdentifier
|
||||
|
||||
attr_reader :integration_session
|
||||
|
||||
def initialize(session)
|
||||
@integration_session = session
|
||||
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
|
||||
|
||||
def response_headers
|
||||
response.headers
|
||||
end
|
||||
|
||||
def xml_content_type?
|
||||
response.headers["Content-Type"].to_s =~ /xml/
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def do_request(http_method, url, data, headers) #:nodoc:
|
||||
update_protocol(url)
|
||||
integration_session.send(http_method, normalize_url(url), data, headers)
|
||||
end
|
||||
|
||||
# remove protocol, host and anchor
|
||||
def normalize_url(href) #:nodoc:
|
||||
uri = URI.parse(href)
|
||||
normalized_url = []
|
||||
normalized_url << "#{uri.scheme}://" if uri.scheme
|
||||
normalized_url << uri.host if uri.host
|
||||
normalized_url << ":#{uri.port}" if uri.port && ![80,443].include?(uri.port)
|
||||
normalized_url << uri.path if uri.path
|
||||
normalized_url << "?#{uri.query}" if uri.query
|
||||
normalized_url.join
|
||||
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
|
@ -1,9 +0,0 @@
|
||||
module Webrat
|
||||
class SinatraAdapter < RackAdapter
|
||||
def initialize(context)
|
||||
app = context.respond_to?(:app) ? context.app : Sinatra::Application
|
||||
|
||||
super(Rack::Test::Session.new(Rack::MockSession.new(app, "www.example.com")))
|
||||
end
|
||||
end
|
||||
end
|
@ -1,13 +1,12 @@
|
||||
require "webrat/core/configuration"
|
||||
require "webrat/core/xml"
|
||||
require "webrat/core/nokogiri"
|
||||
require "webrat/core/logging"
|
||||
require "webrat/core/elements/form"
|
||||
require "webrat/core/flunk"
|
||||
require "webrat/core/form"
|
||||
require "webrat/core/scope"
|
||||
require "webrat/core/elements/link"
|
||||
require "webrat/core/elements/area"
|
||||
require "webrat/core/elements/label"
|
||||
require "webrat/core/elements/select_option"
|
||||
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"
|
||||
require "webrat/core/save_and_open_page"
|
||||
|
@ -1,22 +1,35 @@
|
||||
require "webrat/core/elements/element"
|
||||
|
||||
module Webrat
|
||||
class Area < Element #:nodoc:
|
||||
class Area #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
[".//area"]
|
||||
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}"
|
@ -1,114 +0,0 @@
|
||||
require "webrat/core_extensions/deprecate"
|
||||
require "pathname"
|
||||
|
||||
module Webrat
|
||||
|
||||
# Configures Webrat. If this is not done, Webrat will be created
|
||||
# with all of the default settings.
|
||||
def self.configure(configuration = Webrat.configuration)
|
||||
yield configuration if block_given?
|
||||
@@configuration = configuration
|
||||
end
|
||||
|
||||
def self.configuration # :nodoc:
|
||||
@@configuration ||= Webrat::Configuration.new
|
||||
end
|
||||
|
||||
# Webrat can be configured using the Webrat.configure method. For example:
|
||||
#
|
||||
# Webrat.configure do |config|
|
||||
# config.mode = :sinatra
|
||||
# end
|
||||
class Configuration
|
||||
|
||||
# Webrat's mode, set automatically when requiring webrat/rails, webrat/merb, etc.
|
||||
attr_reader :mode # :nodoc:
|
||||
|
||||
# Save and open pages with error status codes (500-599) in a browser? Defualts to true.
|
||||
attr_writer :open_error_files
|
||||
|
||||
# Save and open page storage directory, defaults to "tmp" under current directory if exists, otherwise current directory
|
||||
attr_accessor :saved_pages_dir
|
||||
|
||||
# Which rails environment should the selenium tests be run in? Defaults to test.
|
||||
attr_accessor :application_environment
|
||||
webrat_deprecate :selenium_environment, :application_environment
|
||||
webrat_deprecate :selenium_environment=, :application_environment=
|
||||
|
||||
# Which port is the application running on for selenium testing? Defaults to 3001.
|
||||
attr_accessor :application_port
|
||||
webrat_deprecate :selenium_port, :application_port
|
||||
webrat_deprecate :selenium_port=, :application_port=
|
||||
|
||||
# Which port should selenium use to access the application. Defaults to application_port
|
||||
attr_writer :application_port_for_selenium
|
||||
|
||||
def application_port_for_selenium
|
||||
@application_port_for_selenium || self.application_port
|
||||
end
|
||||
|
||||
# Which underlying app framework we're testing with selenium
|
||||
attr_accessor :application_framework
|
||||
|
||||
# Which server the application is running on for selenium testing? Defaults to localhost
|
||||
attr_accessor :application_address
|
||||
|
||||
# Which server Selenium server is running on. Defaults to nil(server starts in webrat process and runs locally)
|
||||
attr_accessor :selenium_server_address
|
||||
|
||||
# Which server Selenium port is running on. Defaults to 4444
|
||||
attr_accessor :selenium_server_port
|
||||
|
||||
# Set the key that Selenium uses to determine the browser running. Default *firefox
|
||||
attr_accessor :selenium_browser_key
|
||||
|
||||
# Set the timeout for waiting for the browser process to start
|
||||
attr_accessor :selenium_browser_startup_timeout
|
||||
|
||||
# Set the firefox profile for selenium to use
|
||||
attr_accessor :selenium_firefox_profile
|
||||
|
||||
# How many redirects to the same URL should be halted as an infinite redirect
|
||||
# loop? Defaults to 10
|
||||
attr_accessor :infinite_redirect_limit
|
||||
|
||||
# Print out the full HTML on wait failure
|
||||
# Defaults to false
|
||||
attr_accessor :selenium_verbose_output
|
||||
|
||||
def initialize # :nodoc:
|
||||
self.open_error_files = true
|
||||
self.application_environment = :test
|
||||
self.application_port = 3001
|
||||
self.application_address = 'localhost'
|
||||
self.application_framework = :rails
|
||||
self.selenium_server_port = 4444
|
||||
self.infinite_redirect_limit = 10
|
||||
self.selenium_browser_key = '*firefox'
|
||||
self.selenium_browser_startup_timeout = 5
|
||||
self.selenium_verbose_output = false
|
||||
|
||||
tmp_dir = Pathname.new(Dir.pwd).join("tmp")
|
||||
self.saved_pages_dir = tmp_dir.exist? ? tmp_dir : Dir.pwd
|
||||
end
|
||||
|
||||
def open_error_files? #:nodoc:
|
||||
@open_error_files ? true : false
|
||||
end
|
||||
|
||||
# Allows setting of webrat's mode, valid modes are:
|
||||
# :rails, :selenium, :rack, :sinatra, :mechanize, :merb
|
||||
def mode=(mode)
|
||||
@mode = mode.to_sym
|
||||
|
||||
begin
|
||||
require("webrat/integrations/#{mode}")
|
||||
rescue LoadError
|
||||
# Only some modes have integration code that needs to
|
||||
# be loaded, so this is OK
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -1,33 +0,0 @@
|
||||
module Webrat
|
||||
|
||||
class Element # :nodoc:
|
||||
|
||||
def self.load_all(session, dom)
|
||||
dom.xpath(*xpath_search).map do |element|
|
||||
load(session, element)
|
||||
end
|
||||
end
|
||||
|
||||
def self.load(session, element)
|
||||
return nil if element.nil?
|
||||
session.elements[element.path] ||= self.new(session, element)
|
||||
end
|
||||
|
||||
attr_reader :element
|
||||
|
||||
def initialize(session, element)
|
||||
@session = session
|
||||
@element = element
|
||||
end
|
||||
|
||||
def path
|
||||
@element.path
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<#{self.class} @element=#{element.inspect}>"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -1,438 +0,0 @@
|
||||
require "cgi"
|
||||
require "digest/md5"
|
||||
require "webrat/core_extensions/blank"
|
||||
require "webrat/core_extensions/nil_to_query_string"
|
||||
|
||||
require "webrat/core/elements/element"
|
||||
|
||||
module Webrat
|
||||
# Raised when Webrat is asked to manipulate a disabled form field
|
||||
class DisabledFieldError < WebratError
|
||||
end
|
||||
|
||||
class Field < Element #:nodoc:
|
||||
attr_reader :value
|
||||
|
||||
def self.xpath_search
|
||||
".//button|.//input|.//textarea|.//select"
|
||||
end
|
||||
|
||||
def self.xpath_search_excluding_hidden
|
||||
[".//button", ".//input[ @type != 'hidden']", ".//textarea", ".//select"]
|
||||
end
|
||||
|
||||
def self.field_classes
|
||||
@field_classes || []
|
||||
end
|
||||
|
||||
def self.inherited(klass)
|
||||
@field_classes ||= []
|
||||
@field_classes << klass
|
||||
# raise args.inspect
|
||||
end
|
||||
|
||||
def self.load(session, element)
|
||||
return nil if element.nil?
|
||||
session.elements[element.path] ||= field_class(element).new(session, element)
|
||||
end
|
||||
|
||||
def self.field_class(element)
|
||||
case element.name
|
||||
when "button" then ButtonField
|
||||
when "select"
|
||||
if element.attributes["multiple"].nil?
|
||||
SelectField
|
||||
else
|
||||
MultipleSelectField
|
||||
end
|
||||
when "textarea" then TextareaField
|
||||
else
|
||||
case element["type"]
|
||||
when "checkbox" then CheckboxField
|
||||
when "hidden" then HiddenField
|
||||
when "radio" then RadioField
|
||||
when "password" then PasswordField
|
||||
when "file" then FileField
|
||||
when "reset" then ResetField
|
||||
when "submit" then ButtonField
|
||||
when "button" then ButtonField
|
||||
when "image" then ButtonField
|
||||
else TextField
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(*args)
|
||||
super
|
||||
@value = default_value
|
||||
end
|
||||
|
||||
def label_text
|
||||
return nil if labels.empty?
|
||||
labels.first.text
|
||||
end
|
||||
|
||||
def id
|
||||
@element["id"]
|
||||
end
|
||||
|
||||
def disabled?
|
||||
@element.attributes.has_key?("disabled") && @element["disabled"] != 'false'
|
||||
end
|
||||
|
||||
def raise_error_if_disabled
|
||||
return unless disabled?
|
||||
raise DisabledFieldError.new("Cannot interact with disabled form element (#{self})")
|
||||
end
|
||||
|
||||
def to_query_string
|
||||
return nil if disabled?
|
||||
|
||||
query_string = case Webrat.configuration.mode
|
||||
when :rails, :merb, :rack, :sinatra
|
||||
build_query_string
|
||||
when :mechanize
|
||||
build_query_string(false)
|
||||
end
|
||||
|
||||
query_string
|
||||
end
|
||||
|
||||
def set(value)
|
||||
@value = value
|
||||
end
|
||||
|
||||
def unset
|
||||
@value = default_value
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def form
|
||||
Form.load(@session, form_element)
|
||||
end
|
||||
|
||||
def form_element
|
||||
parent = @element.parent
|
||||
|
||||
while parent.respond_to?(:parent)
|
||||
return parent if parent.name == 'form'
|
||||
parent = parent.parent
|
||||
end
|
||||
end
|
||||
|
||||
def name
|
||||
@element["name"]
|
||||
end
|
||||
|
||||
def build_query_string(escape_value=true)
|
||||
if @value.is_a?(Array)
|
||||
@value.collect {|value| "#{name}=#{ escape_value ? escape(value) : value }" }.join("&")
|
||||
else
|
||||
"#{name}=#{ escape_value ? escape(value) : value }"
|
||||
end
|
||||
end
|
||||
|
||||
def escape(value)
|
||||
CGI.escape(value.to_s)
|
||||
end
|
||||
|
||||
def escaped_value
|
||||
CGI.escape(@value.to_s)
|
||||
end
|
||||
|
||||
def labels
|
||||
@labels ||= label_elements.map do |element|
|
||||
Label.load(@session, element)
|
||||
end
|
||||
end
|
||||
|
||||
def label_elements
|
||||
return @label_elements unless @label_elements.nil?
|
||||
@label_elements = []
|
||||
|
||||
parent = @element.parent
|
||||
while parent.respond_to?(:parent)
|
||||
if parent.name == 'label'
|
||||
@label_elements.push parent
|
||||
break
|
||||
end
|
||||
parent = parent.parent
|
||||
end
|
||||
|
||||
unless id.blank?
|
||||
@label_elements += form.element.xpath(".//label[@for = '#{id}']")
|
||||
end
|
||||
|
||||
@label_elements
|
||||
end
|
||||
|
||||
def default_value
|
||||
@element["value"]
|
||||
end
|
||||
end
|
||||
|
||||
class ButtonField < Field #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
[".//button", ".//input[@type = 'submit']", ".//input[@type = 'button']", ".//input[@type = 'image']"]
|
||||
end
|
||||
|
||||
def to_query_string
|
||||
return nil if @value.nil?
|
||||
super
|
||||
end
|
||||
|
||||
def default_value
|
||||
nil
|
||||
end
|
||||
|
||||
def click
|
||||
raise_error_if_disabled
|
||||
set(@element["value"]) unless @element["name"].blank?
|
||||
form.submit
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class HiddenField < Field #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
".//input[@type = 'hidden']"
|
||||
end
|
||||
|
||||
def to_query_string
|
||||
if collection_name?
|
||||
super
|
||||
else
|
||||
checkbox_with_same_name = form.field_named(name, CheckboxField)
|
||||
|
||||
if checkbox_with_same_name.to_query_string.blank?
|
||||
super
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def collection_name?
|
||||
name =~ /\[\]/
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class CheckboxField < Field #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
".//input[@type = 'checkbox']"
|
||||
end
|
||||
|
||||
def to_query_string
|
||||
return nil if @value.nil?
|
||||
super
|
||||
end
|
||||
|
||||
def check
|
||||
raise_error_if_disabled
|
||||
set(@element["value"] || "on")
|
||||
end
|
||||
|
||||
def checked?
|
||||
@element["checked"] == "checked"
|
||||
end
|
||||
|
||||
def uncheck
|
||||
raise_error_if_disabled
|
||||
set(nil)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def default_value
|
||||
if @element["checked"] == "checked"
|
||||
@element["value"] || "on"
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class PasswordField < Field #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
".//input[@type = 'password']"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class RadioField < Field #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
".//input[@type = 'radio']"
|
||||
end
|
||||
|
||||
def to_query_string
|
||||
return nil if @value.nil?
|
||||
super
|
||||
end
|
||||
|
||||
def choose
|
||||
raise_error_if_disabled
|
||||
other_options.each do |option|
|
||||
option.set(nil)
|
||||
end
|
||||
|
||||
set(@element["value"] || "on")
|
||||
end
|
||||
|
||||
def checked?
|
||||
@element["checked"] == "checked"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def other_options
|
||||
form.fields.select { |f| f.name == name }
|
||||
end
|
||||
|
||||
def default_value
|
||||
if @element["checked"] == "checked"
|
||||
@element["value"] || "on"
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TextareaField < Field #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
".//textarea"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def default_value
|
||||
@element.inner_html
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class FileField < Field #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
".//input[@type = 'file']"
|
||||
end
|
||||
|
||||
attr_accessor :content_type
|
||||
|
||||
def set(value, content_type = nil)
|
||||
@original_value = @value
|
||||
@content_type ||= content_type
|
||||
super(value)
|
||||
end
|
||||
|
||||
def digest_value
|
||||
@value ? Digest::MD5.hexdigest(self.object_id.to_s) : ""
|
||||
end
|
||||
|
||||
def to_query_string
|
||||
@value.nil? ? set("") : set(digest_value)
|
||||
super
|
||||
end
|
||||
|
||||
def test_uploaded_file
|
||||
return "" if @original_value.blank?
|
||||
|
||||
case Webrat.configuration.mode
|
||||
when :rails
|
||||
if content_type
|
||||
ActionController::TestUploadedFile.new(@original_value, content_type)
|
||||
else
|
||||
ActionController::TestUploadedFile.new(@original_value)
|
||||
end
|
||||
when :rack, :merb
|
||||
Rack::Test::UploadedFile.new(@original_value, content_type)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TextField < Field #:nodoc:
|
||||
def self.xpath_search
|
||||
[".//input[@type = 'text']", ".//input[not(@type)]"]
|
||||
end
|
||||
end
|
||||
|
||||
class ResetField < Field #:nodoc:
|
||||
def self.xpath_search
|
||||
[".//input[@type = 'reset']"]
|
||||
end
|
||||
end
|
||||
|
||||
class SelectField < Field #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
[".//select[not(@multiple)]"]
|
||||
end
|
||||
|
||||
def options
|
||||
@options ||= SelectOption.load_all(@session, @element)
|
||||
end
|
||||
|
||||
def unset(value)
|
||||
@value = nil
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def default_value
|
||||
selected_options = @element.xpath(".//option[@selected = 'selected']")
|
||||
selected_options = @element.xpath(".//option[position() = 1]") if selected_options.empty?
|
||||
|
||||
selected_options.map do |option|
|
||||
return "" if option.nil?
|
||||
option["value"] || option.inner_html
|
||||
end.uniq.first
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class MultipleSelectField < Field #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
[".//select[@multiple='multiple']"]
|
||||
end
|
||||
|
||||
def options
|
||||
@options ||= SelectOption.load_all(@session, @element)
|
||||
end
|
||||
|
||||
def set(value)
|
||||
@value << value
|
||||
end
|
||||
|
||||
def unset(value)
|
||||
@value.delete(value)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Overwrite SelectField definition because we don't want to select the first option
|
||||
# (mutliples don't select the first option unlike their non multiple versions)
|
||||
def default_value
|
||||
selected_options = @element.xpath(".//option[@selected = 'selected']")
|
||||
|
||||
selected_options.map do |option|
|
||||
return "" if option.nil?
|
||||
option["value"] || option.inner_html
|
||||
end.uniq
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -1,127 +0,0 @@
|
||||
require "webrat/core/elements/field"
|
||||
require "webrat/core_extensions/blank"
|
||||
|
||||
require "webrat/core/elements/element"
|
||||
require "webrat/core/locators/field_named_locator"
|
||||
|
||||
module Webrat
|
||||
class Form < Element #:nodoc:
|
||||
attr_reader :element
|
||||
|
||||
def self.xpath_search
|
||||
[".//form"]
|
||||
end
|
||||
|
||||
def fields
|
||||
@fields ||= Field.load_all(@session, @element)
|
||||
end
|
||||
|
||||
def submit
|
||||
@session.request_page(form_action, form_method, params)
|
||||
end
|
||||
|
||||
def field_named(name, *field_types)
|
||||
Webrat::Locators::FieldNamedLocator.new(@session, dom, name, *field_types).locate
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def dom
|
||||
@session.dom.xpath(path).first
|
||||
end
|
||||
|
||||
def fields_by_type(field_types)
|
||||
if field_types.any?
|
||||
fields.select { |f| field_types.include?(f.class) }
|
||||
else
|
||||
fields
|
||||
end
|
||||
end
|
||||
|
||||
# iterate over all form fields to build a request querystring to get params from it,
|
||||
# for file_field we made a work around to pass a digest as value to later replace it
|
||||
# in params hash with the real file.
|
||||
def params
|
||||
query_string = []
|
||||
replaces = {}
|
||||
|
||||
fields.each do |field|
|
||||
next if field.to_query_string.nil?
|
||||
replaces.merge!({field.digest_value => field.test_uploaded_file}) if field.is_a?(FileField)
|
||||
query_string << field.to_query_string
|
||||
end
|
||||
|
||||
query_params = self.class.query_string_to_params(query_string.join('&'))
|
||||
|
||||
query_params = self.class.replace_params_values(query_params, replaces)
|
||||
|
||||
self.class.unescape_params(query_params)
|
||||
end
|
||||
|
||||
def form_method
|
||||
@element["method"].blank? ? :get : @element["method"].downcase
|
||||
end
|
||||
|
||||
def form_action
|
||||
@element["action"].blank? ? @session.current_url : @element["action"]
|
||||
end
|
||||
|
||||
def self.replace_param_value(params, oval, nval)
|
||||
output = Hash.new
|
||||
params.each do |key, value|
|
||||
case value
|
||||
when Hash
|
||||
value = replace_param_value(value, oval, nval)
|
||||
when Array
|
||||
value = value.map { |o| o == oval ? nval : ( o.is_a?(Hash) ? replace_param_value(o, oval, nval) : o) }
|
||||
when oval
|
||||
value = nval
|
||||
end
|
||||
output[key] = value
|
||||
end
|
||||
output
|
||||
end
|
||||
|
||||
def self.replace_params_values(params, values)
|
||||
values.each do |key, value|
|
||||
params = replace_param_value(params, key, value)
|
||||
end
|
||||
params
|
||||
end
|
||||
|
||||
def self.unescape_params(params)
|
||||
case params.class.name
|
||||
when 'Hash', 'Mash'
|
||||
params.each { |key,value| params[key] = unescape_params(value) }
|
||||
params
|
||||
when 'Array'
|
||||
params.collect { |value| unescape_params(value) }
|
||||
else
|
||||
params.is_a?(String) ? CGI.unescapeHTML(params) : params
|
||||
end
|
||||
end
|
||||
|
||||
def self.query_string_to_params(query_string)
|
||||
case Webrat.configuration.mode
|
||||
when :rails
|
||||
parse_rails_request_params(query_string)
|
||||
when :merb
|
||||
::Merb::Parse.query(query_string)
|
||||
when :rack, :sinatra
|
||||
Rack::Utils.parse_nested_query(query_string)
|
||||
else
|
||||
Hash[query_string.split('&').map {|query| [ query.split('=').first, query.split('=').last ]}]
|
||||
end
|
||||
end
|
||||
|
||||
def self.parse_rails_request_params(query_string)
|
||||
if defined?(ActionController::AbstractRequest)
|
||||
ActionController::AbstractRequest.parse_query_parameters(query_string)
|
||||
elsif defined?(ActionController::UrlEncodedPairParser)
|
||||
ActionController::UrlEncodedPairParser.parse_query_parameters(query_string)
|
||||
else
|
||||
Rack::Utils.parse_nested_query(query_string)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,31 +0,0 @@
|
||||
require "webrat/core/elements/element"
|
||||
|
||||
module Webrat
|
||||
class Label < Element #:nodoc:
|
||||
|
||||
attr_reader :element
|
||||
|
||||
def self.xpath_search
|
||||
[".//label"]
|
||||
end
|
||||
|
||||
def for_id
|
||||
@element["for"]
|
||||
end
|
||||
|
||||
def field
|
||||
Field.load(@session, field_element)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def field_element
|
||||
if for_id.blank?
|
||||
@element.xpath(*Field.xpath_search_excluding_hidden).first
|
||||
else
|
||||
@session.current_dom.css("#" + for_id).first
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,48 +0,0 @@
|
||||
require "webrat/core/elements/element"
|
||||
|
||||
module Webrat
|
||||
class SelectOption < Element #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
[".//option"]
|
||||
end
|
||||
|
||||
def choose
|
||||
select.raise_error_if_disabled
|
||||
select.set(value)
|
||||
end
|
||||
|
||||
def unchoose
|
||||
select.raise_error_if_disabled
|
||||
select.unset(value)
|
||||
end
|
||||
|
||||
def inner_text
|
||||
@element.inner_text
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def select
|
||||
SelectField.load(@session, select_element)
|
||||
end
|
||||
|
||||
def select_element
|
||||
parent = @element.parent
|
||||
|
||||
while parent.respond_to?(:parent)
|
||||
return parent if parent.name == 'select'
|
||||
parent = parent.parent
|
||||
end
|
||||
end
|
||||
|
||||
def value
|
||||
@element["value"] || @element.inner_html
|
||||
end
|
||||
|
||||
def label
|
||||
@element.inner_html
|
||||
end
|
||||
|
||||
end
|
||||
end
|
332
lib/webrat/core/field.rb
Normal file
332
lib/webrat/core/field.rb
Normal file
@ -0,0 +1,332 @@
|
||||
require "cgi"
|
||||
require "webrat/core_extensions/blank"
|
||||
require "webrat/core_extensions/nil_to_param"
|
||||
|
||||
module Webrat
|
||||
class Field #:nodoc:
|
||||
|
||||
def self.class_for_element(element)
|
||||
if element.name == "input"
|
||||
if %w[submit image].include?(element["type"])
|
||||
field_class = "button"
|
||||
else
|
||||
field_class = element["type"] || "text" #default type; 'type' attribute is not mandatory
|
||||
end
|
||||
else
|
||||
field_class = element.name
|
||||
end
|
||||
Webrat.const_get("#{field_class.capitalize}Field")
|
||||
rescue NameError
|
||||
raise "Invalid field element: #{element.inspect}"
|
||||
end
|
||||
|
||||
def initialize(form, element)
|
||||
@form = form
|
||||
@element = element
|
||||
|
||||
@value = default_value
|
||||
end
|
||||
|
||||
def label_text
|
||||
return nil if labels.empty?
|
||||
labels.first.text
|
||||
end
|
||||
|
||||
def matches_id?(id)
|
||||
@element["id"] == id.to_s
|
||||
end
|
||||
|
||||
def matches_name?(name)
|
||||
@element["name"] == name.to_s
|
||||
end
|
||||
|
||||
def matches_label?(label_text)
|
||||
return false if labels.empty?
|
||||
labels.any? { |label| label.matches_text?(label_text) }
|
||||
end
|
||||
|
||||
def matches_alt?(alt)
|
||||
@element["alt"] =~ /^\W*#{Regexp.escape(alt.to_s)}/i
|
||||
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
|
||||
return nil if disabled?
|
||||
|
||||
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
|
||||
|
||||
def set(value)
|
||||
@value = value
|
||||
end
|
||||
|
||||
def unset
|
||||
@value = default_value
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def id
|
||||
@element["id"]
|
||||
end
|
||||
|
||||
def name
|
||||
@element["name"]
|
||||
end
|
||||
|
||||
def escaped_value
|
||||
CGI.escape(@value.to_s)
|
||||
end
|
||||
|
||||
def labels
|
||||
@labels ||= label_elements.map { |element| Label.new(self, element) }
|
||||
end
|
||||
|
||||
def label_elements
|
||||
return @label_elements unless @label_elements.nil?
|
||||
@label_elements = []
|
||||
|
||||
parent = @element.parent
|
||||
while parent.respond_to?(:parent)
|
||||
if parent.name == 'label'
|
||||
@label_elements.push parent
|
||||
break
|
||||
end
|
||||
parent = parent.parent
|
||||
end
|
||||
|
||||
unless id.blank?
|
||||
@label_elements += @form.element.search("label[@for='#{id}']")
|
||||
end
|
||||
|
||||
@label_elements
|
||||
end
|
||||
|
||||
def default_value
|
||||
@element["value"]
|
||||
end
|
||||
|
||||
def replace_param_value(params, oval, nval)
|
||||
output = Hash.new
|
||||
params.each do |key, value|
|
||||
case value
|
||||
when Hash
|
||||
value = replace_param_value(value, oval, nval)
|
||||
when Array
|
||||
value = value.map { |o| o == oval ? nval : oval }
|
||||
when oval
|
||||
value = nval
|
||||
end
|
||||
output[key] = value
|
||||
end
|
||||
output
|
||||
end
|
||||
end
|
||||
|
||||
class ButtonField < Field #:nodoc:
|
||||
|
||||
def matches_text?(text)
|
||||
@element.inner_html =~ /#{Regexp.escape(text.to_s)}/i
|
||||
end
|
||||
|
||||
def matches_value?(value)
|
||||
@element["value"] =~ /^\W*#{Regexp.escape(value.to_s)}/i || matches_text?(value) || matches_alt?(value)
|
||||
end
|
||||
|
||||
def to_param
|
||||
return nil if @value.nil?
|
||||
super
|
||||
end
|
||||
|
||||
def default_value
|
||||
nil
|
||||
end
|
||||
|
||||
def click
|
||||
raise_error_if_disabled
|
||||
set(@element["value"]) unless @element["name"].blank?
|
||||
@form.submit
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class HiddenField < Field #:nodoc:
|
||||
|
||||
def to_param
|
||||
if collection_name?
|
||||
super
|
||||
else
|
||||
checkbox_with_same_name = @form.field(name, CheckboxField)
|
||||
|
||||
if checkbox_with_same_name.to_param.blank?
|
||||
super
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def collection_name?
|
||||
name =~ /\[\]/
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class CheckboxField < Field #:nodoc:
|
||||
|
||||
def to_param
|
||||
return nil if @value.nil?
|
||||
super
|
||||
end
|
||||
|
||||
def check
|
||||
raise_error_if_disabled
|
||||
set(@element["value"] || "on")
|
||||
end
|
||||
|
||||
def checked?
|
||||
@element["checked"] == "checked"
|
||||
end
|
||||
|
||||
def uncheck
|
||||
raise_error_if_disabled
|
||||
set(nil)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def default_value
|
||||
if @element["checked"] == "checked"
|
||||
@element["value"] || "on"
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class PasswordField < Field #:nodoc:
|
||||
end
|
||||
|
||||
class RadioField < Field #:nodoc:
|
||||
|
||||
def to_param
|
||||
return nil if @value.nil?
|
||||
super
|
||||
end
|
||||
|
||||
def choose
|
||||
raise_error_if_disabled
|
||||
other_options.each do |option|
|
||||
option.set(nil)
|
||||
end
|
||||
|
||||
set(@element["value"] || "on")
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def other_options
|
||||
@form.fields.select { |f| f.name == name }
|
||||
end
|
||||
|
||||
def default_value
|
||||
if @element["checked"] == "checked"
|
||||
@element["value"] || "on"
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TextareaField < Field #:nodoc:
|
||||
|
||||
protected
|
||||
|
||||
def default_value
|
||||
@element.inner_html
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class FileField < Field #:nodoc:
|
||||
|
||||
attr_accessor :content_type
|
||||
|
||||
def set(value, content_type = nil)
|
||||
super(value)
|
||||
@content_type = content_type
|
||||
end
|
||||
|
||||
def to_param
|
||||
if @value.nil?
|
||||
super
|
||||
else
|
||||
replace_param_value(super, @value, test_uploaded_file)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def test_uploaded_file
|
||||
if content_type
|
||||
ActionController::TestUploadedFile.new(@value, content_type)
|
||||
else
|
||||
ActionController::TestUploadedFile.new(@value)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TextField < Field #:nodoc:
|
||||
end
|
||||
|
||||
class ResetField < Field #:nodoc:
|
||||
end
|
||||
|
||||
class SelectField < Field #:nodoc:
|
||||
|
||||
def find_option(text)
|
||||
options.detect { |o| o.matches_text?(text) }
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def default_value
|
||||
selected_options = @element.search(".//option[@selected='selected']")
|
||||
selected_options = @element.search(".//option[position() = 1]") if selected_options.empty?
|
||||
|
||||
selected_options.map do |option|
|
||||
return "" if option.nil?
|
||||
option["value"] || option.inner_html
|
||||
end
|
||||
end
|
||||
|
||||
def options
|
||||
option_elements.map { |oe| SelectOption.new(self, oe) }
|
||||
end
|
||||
|
||||
def option_elements
|
||||
@element.search(".//option")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
7
lib/webrat/core/flunk.rb
Normal file
7
lib/webrat/core/flunk.rb
Normal file
@ -0,0 +1,7 @@
|
||||
module Flunk
|
||||
|
||||
def flunk(message) #:nodoc:
|
||||
raise message
|
||||
end
|
||||
|
||||
end
|
130
lib/webrat/core/form.rb
Normal file
130
lib/webrat/core/form.rb
Normal file
@ -0,0 +1,130 @@
|
||||
require "webrat/core/field"
|
||||
require "webrat/core_extensions/blank"
|
||||
|
||||
module Webrat
|
||||
class Form #:nodoc:
|
||||
attr_reader :element
|
||||
|
||||
def initialize(session, element)
|
||||
@session = session
|
||||
@element = element
|
||||
@fields = nil
|
||||
end
|
||||
|
||||
def field(locator, *field_types)
|
||||
field_with_id(locator, *field_types) ||
|
||||
field_named(locator, *field_types) ||
|
||||
field_labeled(locator, *field_types) ||
|
||||
nil
|
||||
end
|
||||
|
||||
def find_select_option(option_text)
|
||||
select_fields = fields_by_type([SelectField])
|
||||
|
||||
select_fields.each do |select_field|
|
||||
result = select_field.find_option(option_text)
|
||||
return result if result
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def find_button(value = nil)
|
||||
return fields_by_type([ButtonField]).first if value.nil?
|
||||
possible_buttons = fields_by_type([ButtonField])
|
||||
possible_buttons.detect { |possible_button| possible_button.matches_id?(value) } ||
|
||||
possible_buttons.detect { |possible_button| possible_button.matches_value?(value) }
|
||||
end
|
||||
|
||||
def fields
|
||||
return @fields if @fields
|
||||
|
||||
@fields = (@element.search(".//button", ".//input", ".//textarea", ".//select")).collect do |field_element|
|
||||
Field.class_for_element(field_element).new(self, field_element)
|
||||
end
|
||||
end
|
||||
|
||||
def submit
|
||||
@session.request_page(form_action, form_method, params)
|
||||
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
|
||||
|
||||
def fields_by_type(field_types)
|
||||
if field_types.any?
|
||||
fields.select { |f| field_types.include?(f.class) }
|
||||
else
|
||||
fields
|
||||
end
|
||||
end
|
||||
|
||||
def params
|
||||
all_params = {}
|
||||
|
||||
fields.each do |field|
|
||||
next if field.to_param.nil?
|
||||
merge(all_params, field.to_param)
|
||||
end
|
||||
|
||||
all_params
|
||||
end
|
||||
|
||||
def form_method
|
||||
@element["method"].blank? ? :get : @element["method"].downcase
|
||||
end
|
||||
|
||||
def form_action
|
||||
@element["action"].blank? ? @session.current_url : @element["action"]
|
||||
end
|
||||
|
||||
HASH = [Hash, HashWithIndifferentAccess] rescue [Hash]
|
||||
|
||||
def merge(all_params, new_param)
|
||||
new_param.each do |key, value|
|
||||
case all_params[key]
|
||||
when *HASH
|
||||
merge_hash_values(all_params[key], value)
|
||||
when Array
|
||||
all_params[key] += value
|
||||
else
|
||||
all_params[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def merge_hash_values(a, b) # :nodoc:
|
||||
a.keys.each do |k|
|
||||
if b.has_key?(k)
|
||||
case [a[k], b[k]].map{|value| value.class}
|
||||
when [Hash, Hash]
|
||||
a[k] = merge_hash_values(a[k], b[k])
|
||||
b.delete(k)
|
||||
when [Array, Array]
|
||||
a[k] += b[k]
|
||||
b.delete(k)
|
||||
end
|
||||
end
|
||||
end
|
||||
a.merge!(b)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
18
lib/webrat/core/label.rb
Normal file
18
lib/webrat/core/label.rb
Normal file
@ -0,0 +1,18 @@
|
||||
module Webrat
|
||||
class Label #:nodoc:
|
||||
|
||||
def initialize(field, element)
|
||||
@field = field
|
||||
@element = element
|
||||
end
|
||||
|
||||
def matches_text?(label_text)
|
||||
text =~ /^\W*#{Regexp.escape(label_text.to_s)}\b/i
|
||||
end
|
||||
|
||||
def text
|
||||
@element.inner_text
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,13 +1,11 @@
|
||||
require "English"
|
||||
|
||||
require "webrat/core_extensions/blank"
|
||||
require "webrat/core/elements/element"
|
||||
|
||||
module Webrat
|
||||
class Link < Element #:nodoc:
|
||||
class Link #:nodoc:
|
||||
|
||||
def self.xpath_search
|
||||
[".//a[@href]"]
|
||||
def initialize(session, element)
|
||||
@session = session
|
||||
@element = element
|
||||
end
|
||||
|
||||
def click(options = {})
|
||||
@ -23,18 +21,30 @@ module Webrat
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def matches_text?(link_text)
|
||||
html = text.gsub(' ',' ')
|
||||
|
||||
def id
|
||||
@element["id"]
|
||||
if link_text.is_a?(Regexp)
|
||||
matcher = link_text
|
||||
else
|
||||
matcher = /#{Regexp.escape(link_text.to_s)}/i
|
||||
end
|
||||
|
||||
html =~ matcher || title =~ matcher
|
||||
end
|
||||
|
||||
def text
|
||||
@element.inner_html
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def data
|
||||
authenticity_token.blank? ? {} : {"authenticity_token" => authenticity_token}
|
||||
end
|
||||
|
||||
def title
|
||||
@element["title"]
|
||||
@element['title']
|
||||
end
|
||||
|
||||
def href
|
||||
@ -44,7 +54,7 @@ module Webrat
|
||||
def absolute_href
|
||||
if href =~ /^\?/
|
||||
"#{@session.current_url}#{href}"
|
||||
elsif href !~ %r{^https?://} && (href !~ /^\//)
|
||||
elsif href !~ %r{^https?://www.example.com(/.*)} && (href !~ /^\//)
|
||||
"#{@session.current_url}/#{href}"
|
||||
else
|
||||
href
|
||||
@ -53,7 +63,7 @@ module Webrat
|
||||
|
||||
def authenticity_token
|
||||
return unless onclick && onclick.include?("s.setAttribute('name', 'authenticity_token');") &&
|
||||
( onclick =~ /s\.setAttribute\('value', '([a-f0-9]{40})'\);/ || onclick =~ /s\.setAttribute\('value', '(.{44})'\);/ )
|
||||
onclick =~ /s\.setAttribute\('value', '([a-f0-9]{40})'\);/
|
||||
$LAST_MATCH_INFO.captures.first
|
||||
end
|
||||
|
||||
@ -82,10 +92,8 @@ module Webrat
|
||||
:delete
|
||||
elsif onclick.include?("m.setAttribute('value', 'put')")
|
||||
:put
|
||||
elsif onclick.include?("m.setAttribute('value', 'post')")
|
||||
:post
|
||||
else
|
||||
raise Webrat::WebratError.new("No HTTP method for _method param in #{onclick.inspect}")
|
||||
raise "No HTTP method for _method param in #{onclick.inspect}"
|
||||
end
|
||||
end
|
||||
|
@ -1,19 +1,91 @@
|
||||
require "webrat/core/locators/area_locator"
|
||||
require "webrat/core/locators/button_locator"
|
||||
require "webrat/core/locators/field_labeled_locator"
|
||||
require "webrat/core/locators/label_locator"
|
||||
require "webrat/core/locators/field_named_locator"
|
||||
require "webrat/core/locators/field_by_id_locator"
|
||||
require "webrat/core/locators/select_option_locator"
|
||||
require "webrat/core/locators/link_locator"
|
||||
require "webrat/core/locators/field_locator"
|
||||
require "webrat/core/locators/form_locator"
|
||||
require "webrat/core_extensions/detect_mapped"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
def field_by_xpath(xpath)
|
||||
Field.load(@session, dom.xpath(xpath).first)
|
||||
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
|
||||
|
@ -1,38 +0,0 @@
|
||||
require "webrat/core/locators/locator"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class AreaLocator < Locator # :nodoc:
|
||||
|
||||
def locate
|
||||
Area.load(@session, area_element)
|
||||
end
|
||||
|
||||
def area_element
|
||||
area_elements.detect do |area_element|
|
||||
area_element["title"] =~ matcher ||
|
||||
area_element["id"] =~ matcher
|
||||
end
|
||||
end
|
||||
|
||||
def matcher
|
||||
/#{Regexp.escape(@value.to_s)}/i
|
||||
end
|
||||
|
||||
def area_elements
|
||||
@dom.xpath(*Area.xpath_search)
|
||||
end
|
||||
|
||||
def error_message
|
||||
"Could not find area with name #{@value}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def find_area(id_or_title) #:nodoc:
|
||||
AreaLocator.new(@session, dom, id_or_title).locate!
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,54 +0,0 @@
|
||||
require "webrat/core/locators/locator"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class ButtonLocator < Locator # :nodoc:
|
||||
|
||||
def locate
|
||||
ButtonField.load(@session, button_element)
|
||||
end
|
||||
|
||||
def button_element
|
||||
button_elements.detect do |element|
|
||||
@value.nil? ||
|
||||
matches_id?(element) ||
|
||||
matches_value?(element) ||
|
||||
matches_html?(element) ||
|
||||
matches_alt?(element)
|
||||
end
|
||||
end
|
||||
|
||||
def matches_id?(element)
|
||||
(@value.is_a?(Regexp) && element["id"] =~ @value) ||
|
||||
(!@value.is_a?(Regexp) && element["id"] == @value.to_s)
|
||||
end
|
||||
|
||||
def matches_value?(element)
|
||||
element["value"] =~ /^\W*#{Regexp.escape(@value.to_s)}/i
|
||||
end
|
||||
|
||||
def matches_html?(element)
|
||||
element.inner_html =~ /#{Regexp.escape(@value.to_s)}/i
|
||||
end
|
||||
|
||||
def matches_alt?(element)
|
||||
element["alt"] =~ /^\W*#{Regexp.escape(@value.to_s)}/i
|
||||
end
|
||||
|
||||
def button_elements
|
||||
@dom.xpath(*ButtonField.xpath_search)
|
||||
end
|
||||
|
||||
def error_message
|
||||
"Could not find button #{@value.inspect}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def find_button(value) #:nodoc:
|
||||
ButtonLocator.new(@session, dom, value).locate!
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,37 +0,0 @@
|
||||
require "webrat/core/locators/locator"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class FieldByIdLocator < Locator # :nodoc:
|
||||
|
||||
def locate
|
||||
Field.load(@session, field_element)
|
||||
end
|
||||
|
||||
def field_element
|
||||
field_elements.detect do |field_element|
|
||||
if @value.is_a?(Regexp)
|
||||
field_element["id"] =~ @value
|
||||
else
|
||||
field_element["id"] == @value.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def field_elements
|
||||
@dom.xpath(*Field.xpath_search)
|
||||
end
|
||||
|
||||
def error_message
|
||||
"Could not find field with id #{@value.inspect}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def field_with_id(id, *field_types)
|
||||
FieldByIdLocator.new(@session, dom, id, *field_types).locate!
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,56 +0,0 @@
|
||||
require "webrat/core_extensions/detect_mapped"
|
||||
require "webrat/core/locators/locator"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class FieldLabeledLocator < Locator # :nodoc:
|
||||
|
||||
def locate
|
||||
matching_labels.any? && matching_labels.detect_mapped { |label| label.field }
|
||||
end
|
||||
|
||||
def matching_labels
|
||||
matching_label_elements.sort_by do |label_element|
|
||||
text(label_element).length
|
||||
end.map do |label_element|
|
||||
Label.load(@session, label_element)
|
||||
end
|
||||
end
|
||||
|
||||
def matching_label_elements
|
||||
label_elements.select do |label_element|
|
||||
text(label_element) =~ /^\W*#{Regexp.escape(@value.to_s)}(\b|\Z)/i
|
||||
end
|
||||
end
|
||||
|
||||
def label_elements
|
||||
@dom.xpath(*Label.xpath_search)
|
||||
end
|
||||
|
||||
def error_message
|
||||
"Could not find field labeled #{@value.inspect}"
|
||||
end
|
||||
|
||||
def text(element)
|
||||
str = element.inner_text
|
||||
str.gsub!("\n","")
|
||||
str.strip!
|
||||
str.squeeze!(" ")
|
||||
str
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Locates a form field based on a <tt>label</tt> element in the HTML source.
|
||||
# This can be useful in order to verify that a field is pre-filled with the
|
||||
# correct value.
|
||||
#
|
||||
# Example:
|
||||
# field_labeled("First name").value.should == "Bryan"
|
||||
def field_labeled(label, *field_types)
|
||||
FieldLabeledLocator.new(@session, dom, label, *field_types).locate!
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,25 +0,0 @@
|
||||
require "webrat/core/locators/locator"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class FieldLocator < Locator # :nodoc:
|
||||
|
||||
def locate
|
||||
FieldByIdLocator.new(@session, @dom, @value).locate ||
|
||||
FieldNamedLocator.new(@session, @dom, @value, *@field_types).locate ||
|
||||
FieldLabeledLocator.new(@session, @dom, @value, *@field_types).locate
|
||||
end
|
||||
|
||||
def error_message
|
||||
"Could not find field: #{@value.inspect}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def field(*args) # :nodoc:
|
||||
FieldLocator.new(@session, dom, *args).locate!
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,41 +0,0 @@
|
||||
require "webrat/core/locators/locator"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class FieldNamedLocator < Locator # :nodoc:
|
||||
|
||||
def locate
|
||||
Field.load(@session, field_element)
|
||||
end
|
||||
|
||||
def field_element
|
||||
field_elements.detect do |field_element|
|
||||
field_element["name"] == @value.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def field_elements
|
||||
@dom.xpath(*xpath_searches)
|
||||
end
|
||||
|
||||
def xpath_searches
|
||||
if @field_types.any?
|
||||
@field_types.map { |field_type| field_type.xpath_search }.flatten
|
||||
else
|
||||
Field.xpath_search
|
||||
end
|
||||
end
|
||||
|
||||
def error_message
|
||||
"Could not find field named #{@value.inspect}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def field_named(name, *field_types)
|
||||
FieldNamedLocator.new(@session, dom, name, *field_types).locate!
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,19 +0,0 @@
|
||||
require "webrat/core/locators/locator"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class FormLocator < Locator # :nodoc:
|
||||
|
||||
def locate
|
||||
Form.load(@session, form_element)
|
||||
end
|
||||
|
||||
def form_element
|
||||
@dom.css("#" + @value).first || @dom.css(@value).first
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,34 +0,0 @@
|
||||
require "webrat/core_extensions/detect_mapped"
|
||||
require "webrat/core/locators/locator"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class LabelLocator < Locator # :nodoc:
|
||||
|
||||
def locate
|
||||
Label.load(@session, label_element)
|
||||
end
|
||||
|
||||
def label_element
|
||||
label_elements.detect do |label_element|
|
||||
text(label_element) =~ /^\W*#{Regexp.escape(@value.to_s)}(\b|\Z)/i
|
||||
end
|
||||
end
|
||||
|
||||
def label_elements
|
||||
@dom.xpath(*Label.xpath_search)
|
||||
end
|
||||
|
||||
def text(label_element)
|
||||
str = label_element.inner_text
|
||||
str.gsub!("\n","")
|
||||
str.strip!
|
||||
str.squeeze!(" ")
|
||||
str
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,74 +0,0 @@
|
||||
require "webrat/core/locators/locator"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class LinkLocator < Locator # :nodoc:
|
||||
|
||||
def locate
|
||||
Link.load(@session, link_element)
|
||||
end
|
||||
|
||||
def link_element
|
||||
matching_links.min { |a, b| a.inner_text.length <=> b.inner_text.length }
|
||||
end
|
||||
|
||||
def matching_links
|
||||
@matching_links ||= link_elements.select do |link_element|
|
||||
matches_text?(link_element) ||
|
||||
matches_id?(link_element)
|
||||
end
|
||||
end
|
||||
|
||||
def matches_text?(link)
|
||||
if @value.is_a?(Regexp)
|
||||
matcher = @value
|
||||
else
|
||||
matcher = /#{Regexp.escape(@value.to_s)}/i
|
||||
end
|
||||
|
||||
replace_nbsp(link.inner_text) =~ matcher ||
|
||||
replace_nbsp_ref(link.inner_html) =~ matcher ||
|
||||
link["title"] =~ matcher
|
||||
end
|
||||
|
||||
def matches_id?(link)
|
||||
if @value.is_a?(Regexp)
|
||||
link["id"] =~ @value ? true : false
|
||||
else
|
||||
link["id"] == @value ? true : false
|
||||
end
|
||||
end
|
||||
|
||||
def link_elements
|
||||
@dom.xpath(*Link.xpath_search)
|
||||
end
|
||||
|
||||
def replace_nbsp(str)
|
||||
if str.respond_to?(:valid_encoding?)
|
||||
if str.valid_encoding?
|
||||
str.gsub(/\xc2\xa0/u, ' ')
|
||||
else
|
||||
str.force_encoding('UTF-8').gsub(/\xc2\xa0/u, ' ')
|
||||
end
|
||||
else
|
||||
str.gsub(/\xc2\xa0/u, ' ')
|
||||
end
|
||||
end
|
||||
|
||||
def replace_nbsp_ref(str)
|
||||
str.gsub(' ',' ').gsub(' ', ' ')
|
||||
end
|
||||
|
||||
def error_message
|
||||
"Could not find link with text or title or id #{@value.inspect}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def find_link(text_or_title_or_id) #:nodoc:
|
||||
LinkLocator.new(@session, dom, text_or_title_or_id).locate!
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,20 +0,0 @@
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class Locator # :nodoc:
|
||||
|
||||
def initialize(session, dom, value, *field_types)
|
||||
@session = session
|
||||
@dom = dom
|
||||
@value = value
|
||||
@field_types = field_types
|
||||
end
|
||||
|
||||
def locate!
|
||||
locate || raise(NotFoundError.new(error_message))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,59 +0,0 @@
|
||||
require "webrat/core_extensions/detect_mapped"
|
||||
require "webrat/core/locators/locator"
|
||||
|
||||
module Webrat
|
||||
module Locators
|
||||
|
||||
class SelectOptionLocator < Locator # :nodoc:
|
||||
|
||||
def initialize(session, dom, option_text, id_or_name_or_label)
|
||||
@session = session
|
||||
@dom = dom
|
||||
@option_text = option_text
|
||||
@id_or_name_or_label = id_or_name_or_label
|
||||
end
|
||||
|
||||
def locate
|
||||
if @id_or_name_or_label
|
||||
field = FieldLocator.new(@session, @dom, @id_or_name_or_label, SelectField).locate!
|
||||
|
||||
field.options.detect do |o|
|
||||
if @option_text.is_a?(Regexp)
|
||||
o.element.inner_text =~ @option_text
|
||||
else
|
||||
o.inner_text == @option_text.to_s
|
||||
end
|
||||
end
|
||||
else
|
||||
option_element = option_elements.detect do |o|
|
||||
if @option_text.is_a?(Regexp)
|
||||
o.inner_text =~ @option_text
|
||||
else
|
||||
o.inner_text == @option_text.to_s
|
||||
end
|
||||
end
|
||||
|
||||
SelectOption.load(@session, option_element)
|
||||
end
|
||||
end
|
||||
|
||||
def option_elements
|
||||
@dom.xpath(*SelectOption.xpath_search)
|
||||
end
|
||||
|
||||
def error_message
|
||||
if @id_or_name_or_label
|
||||
"The '#{@option_text}' option was not found in the #{@id_or_name_or_label.inspect} select box"
|
||||
else
|
||||
"Could not find option #{@option_text.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def select_option(option_text, id_or_name_or_label = nil) #:nodoc:
|
||||
SelectOptionLocator.new(@session, dom, option_text, id_or_name_or_label).locate!
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,21 +1,23 @@
|
||||
require "logger"
|
||||
|
||||
module Webrat
|
||||
module Logging #:nodoc:
|
||||
|
||||
def warn_log(message) # :nodoc:
|
||||
return unless logger
|
||||
logger.warn message
|
||||
end
|
||||
|
||||
def debug_log(message) # :nodoc:
|
||||
return unless logger
|
||||
logger.debug message
|
||||
end
|
||||
|
||||
def logger # :nodoc:
|
||||
case Webrat.configuration.mode
|
||||
when :rails
|
||||
defined?(RAILS_DEFAULT_LOGGER) ? RAILS_DEFAULT_LOGGER : nil
|
||||
when :merb
|
||||
::Merb.logger
|
||||
if defined? RAILS_DEFAULT_LOGGER
|
||||
RAILS_DEFAULT_LOGGER
|
||||
elsif defined? Merb
|
||||
Merb.logger
|
||||
else
|
||||
@logger ||= ::Logger.new("webrat.log")
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -7,31 +7,68 @@ module Webrat
|
||||
end
|
||||
|
||||
def matches?(stringlike)
|
||||
@document = Webrat::XML.document(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.gsub(/\s+/, ' ').include?(@content)
|
||||
@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#{squeeze_space(@element)}"
|
||||
"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#{squeeze_space(@element)}"
|
||||
end
|
||||
|
||||
def squeeze_space(inner_text)
|
||||
inner_text.gsub(/^\s*$/, "").squeeze("\n")
|
||||
"expected the following element's content to not #{content_message}:\n#{@element}"
|
||||
end
|
||||
|
||||
def content_message
|
||||
@ -46,23 +83,12 @@ module Webrat
|
||||
|
||||
# Matches the contents of an HTML document with
|
||||
# whatever string is supplied
|
||||
#
|
||||
# ---
|
||||
# @api public
|
||||
def contain(content)
|
||||
HasContent.new(content)
|
||||
end
|
||||
|
||||
# Asserts that the body of the response contain
|
||||
# the supplied string or regexp
|
||||
def assert_contain(content)
|
||||
hc = HasContent.new(content)
|
||||
assert hc.matches?(response_body), hc.failure_message
|
||||
end
|
||||
|
||||
# Asserts that the body of the response
|
||||
# does not contain the supplied string or regepx
|
||||
def assert_not_contain(content)
|
||||
hc = HasContent.new(content)
|
||||
assert !hc.matches?(response_body), hc.negative_failure_message
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,44 +1,22 @@
|
||||
require "webrat/core/matchers/have_xpath"
|
||||
|
||||
module Webrat
|
||||
module Matchers
|
||||
|
||||
class HaveSelector < HaveXpath #:nodoc:
|
||||
|
||||
# ==== Returns
|
||||
# String:: The failure message.
|
||||
def failure_message
|
||||
"expected following output to contain a #{tag_inspect} tag:\n#{@document}"
|
||||
"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 output to omit a #{tag_inspect}:\n#{@document}"
|
||||
end
|
||||
|
||||
def tag_inspect
|
||||
options = @options.dup
|
||||
count = options.delete(:count)
|
||||
content = options.delete(:content)
|
||||
|
||||
html = "<#{@expected}"
|
||||
options.each do |k,v|
|
||||
html << " #{k}='#{v}'"
|
||||
end
|
||||
|
||||
if content
|
||||
html << ">#{content}</#{@expected}>"
|
||||
else
|
||||
html << "/>"
|
||||
end
|
||||
|
||||
html
|
||||
"expected following text to not match selector #{@expected}:\n#{@document}"
|
||||
end
|
||||
|
||||
def query
|
||||
Nokogiri::CSS.parse(@expected.to_s).map do |ast|
|
||||
ast.to_xpath
|
||||
end.first
|
||||
Nokogiri::CSS::Parser.parse(*super).map { |ast| ast.to_xpath }
|
||||
end
|
||||
|
||||
end
|
||||
@ -50,25 +28,12 @@ module Webrat
|
||||
#
|
||||
# ==== Returns
|
||||
# HaveSelector:: A new have selector matcher.
|
||||
def have_selector(name, attributes = {}, &block)
|
||||
HaveSelector.new(name, attributes, &block)
|
||||
# ---
|
||||
# @api public
|
||||
def have_selector(expected, &block)
|
||||
HaveSelector.new(expected, &block)
|
||||
end
|
||||
alias_method :match_selector, :have_selector
|
||||
|
||||
|
||||
# Asserts that the body of the response contains
|
||||
# the supplied selector
|
||||
def assert_have_selector(name, attributes = {}, &block)
|
||||
matcher = HaveSelector.new(name, attributes, &block)
|
||||
assert matcher.matches?(response_body), matcher.failure_message
|
||||
end
|
||||
|
||||
# Asserts that the body of the response
|
||||
# does not contain the supplied string or regepx
|
||||
def assert_have_no_selector(name, attributes = {}, &block)
|
||||
matcher = HaveSelector.new(name, attributes, &block)
|
||||
assert !matcher.matches?(response_body), matcher.negative_failure_message
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,21 +1,58 @@
|
||||
require "webrat/core/matchers/have_selector"
|
||||
|
||||
module Webrat
|
||||
|
||||
module HaveTagMatcher
|
||||
|
||||
def have_tag(*args, &block)
|
||||
have_selector(*args, &block)
|
||||
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
|
||||
|
||||
def assert_have_tag(*args, &block)
|
||||
assert_have_selector(*args, &block)
|
||||
end
|
||||
|
||||
def assert_have_no_tag(*args, &block)
|
||||
assert_have_no_selector(*args, &block)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,71 +1,72 @@
|
||||
require "webrat/core/xml"
|
||||
|
||||
module Webrat
|
||||
module Matchers
|
||||
|
||||
class HaveXpath #:nodoc:
|
||||
def initialize(expected, options = {}, &block)
|
||||
def initialize(expected, &block)
|
||||
@expected = expected
|
||||
@options = options
|
||||
@block = block
|
||||
end
|
||||
|
||||
def matches?(stringlike, &block)
|
||||
@block ||= block
|
||||
matched = matches(stringlike)
|
||||
|
||||
@block.call(matched) if @block
|
||||
|
||||
if @options[:count]
|
||||
matched.size == @options[:count].to_i
|
||||
def matches?(stringlike)
|
||||
if defined?(Nokogiri::XML)
|
||||
matches_nokogiri?(stringlike)
|
||||
else
|
||||
matched.any?
|
||||
matches_rexml?(stringlike)
|
||||
end
|
||||
end
|
||||
|
||||
def matches(stringlike)
|
||||
nokogiri_matches(stringlike)
|
||||
def matches_rexml?(stringlike)
|
||||
@query = query
|
||||
|
||||
@document = 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 nokogiri_matches(stringlike)
|
||||
def matches_nokogiri?(stringlike)
|
||||
if Nokogiri::XML::NodeSet === stringlike
|
||||
@query = query.gsub(%r'^//', './/')
|
||||
@query = query.map { |q| q.gsub(%r'//', './') }
|
||||
else
|
||||
@query = query
|
||||
end
|
||||
|
||||
add_options_conditions_to(@query)
|
||||
|
||||
@document = Webrat::XML.document(stringlike)
|
||||
@document.xpath(*@query)
|
||||
@document = Webrat.nokogiri_document(stringlike)
|
||||
matched = @document.xpath(*@query)
|
||||
matched.any? && (!@block || @block.call(matched))
|
||||
end
|
||||
|
||||
def add_options_conditions_to(query)
|
||||
add_attributes_conditions_to(query)
|
||||
add_content_condition_to(query)
|
||||
end
|
||||
def rexml_document(stringlike)
|
||||
stringlike = stringlike.body.to_s if stringlike.respond_to?(:body)
|
||||
|
||||
def add_attributes_conditions_to(query)
|
||||
attribute_conditions = []
|
||||
|
||||
@options.each do |key, value|
|
||||
next if [:content, :count].include?(key)
|
||||
attribute_conditions << "@#{key} = #{xpath_escape(value)}"
|
||||
end
|
||||
|
||||
if attribute_conditions.any?
|
||||
query << "[#{attribute_conditions.join(' and ')}]"
|
||||
case stringlike
|
||||
when REXML::Document
|
||||
stringlike.root
|
||||
when REXML::Node, Array
|
||||
@query = query.map { |q| q.gsub(%r'//', './') }
|
||||
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
|
||||
|
||||
def add_content_condition_to(query)
|
||||
if @options[:content]
|
||||
query << "[contains(., #{xpath_escape(@options[:content])})]"
|
||||
end
|
||||
end
|
||||
|
||||
def query
|
||||
@expected
|
||||
[@expected].flatten.compact
|
||||
end
|
||||
|
||||
# ==== Returns
|
||||
@ -79,23 +80,6 @@ module Webrat
|
||||
def negative_failure_message
|
||||
"expected following text to not match xpath #{@expected}:\n#{@document}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def xpath_escape(string)
|
||||
if string.include?("'") && string.include?('"')
|
||||
parts = string.split("'").map do |part|
|
||||
"'#{part}'"
|
||||
end
|
||||
|
||||
"concat(" + parts.join(", \"'\", ") + ")"
|
||||
elsif string.include?("'")
|
||||
"\"#{string}\""
|
||||
else
|
||||
"'#{string}'"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Matches HTML content against an XPath query
|
||||
@ -105,20 +89,12 @@ module Webrat
|
||||
#
|
||||
# ==== Returns
|
||||
# HaveXpath:: A new have xpath matcher.
|
||||
def have_xpath(expected, options = {}, &block)
|
||||
HaveXpath.new(expected, options, &block)
|
||||
# ---
|
||||
# @api public
|
||||
def have_xpath(expected, &block)
|
||||
HaveXpath.new(expected, &block)
|
||||
end
|
||||
alias_method :match_xpath, :have_xpath
|
||||
|
||||
def assert_have_xpath(expected, options = {}, &block)
|
||||
hs = HaveXpath.new(expected, options, &block)
|
||||
assert hs.matches?(response_body), hs.failure_message
|
||||
end
|
||||
|
||||
def assert_have_no_xpath(expected, options = {}, &block)
|
||||
hs = HaveXpath.new(expected, options, &block)
|
||||
assert !hs.matches?(response_body), hs.negative_failure_message
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -3,26 +3,15 @@ module Webrat
|
||||
|
||||
def self.delegate_to_session(*meths)
|
||||
meths.each do |meth|
|
||||
self.class_eval(<<-RUBY, __FILE__, __LINE__)
|
||||
self.class_eval <<-RUBY
|
||||
def #{meth}(*args, &blk)
|
||||
webrat_session.#{meth}(*args, &blk)
|
||||
@_webrat_session ||= ::Webrat::MerbSession.new
|
||||
@_webrat_session.#{meth}(*args, &blk)
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
|
||||
def webrat
|
||||
webrat_session
|
||||
end
|
||||
|
||||
def webrat_session
|
||||
@_webrat_session ||= begin
|
||||
session = Webrat.session_class.new
|
||||
session.adapter = Webrat.adapter_class.new(self) if session.respond_to?(:adapter=)
|
||||
session
|
||||
end
|
||||
end
|
||||
|
||||
# all of these methods delegate to the @session, which should
|
||||
# be created transparently.
|
||||
#
|
||||
@ -34,31 +23,22 @@ module Webrat
|
||||
:within,
|
||||
:header, :http_accept, :basic_auth,
|
||||
:save_and_open_page,
|
||||
:fills_in, :fill_in,
|
||||
:checks, :check,
|
||||
:unchecks, :uncheck,
|
||||
:chooses, :choose,
|
||||
:selects, :select,
|
||||
:unselects, :unselect,
|
||||
:attaches_file, :attach_file,
|
||||
:fill_in,
|
||||
:check,
|
||||
:uncheck,
|
||||
:choose,
|
||||
:select,
|
||||
:attach_file,
|
||||
:cookies,
|
||||
:response,
|
||||
:current_page,
|
||||
:current_url,
|
||||
:clicks_link, :click_link,
|
||||
:clicks_area, :click_area,
|
||||
:clicks_button, :click_button,
|
||||
:click_link,
|
||||
:click_area,
|
||||
:click_button,
|
||||
:reload, :reloads,
|
||||
:clicks_link_within, :click_link_within,
|
||||
:field_labeled,
|
||||
:select_option,
|
||||
:set_hidden_field, :submit_form,
|
||||
:request_page, :current_dom,
|
||||
:response_body,
|
||||
:selects_date, :selects_time, :selects_datetime,
|
||||
:select_date, :select_time, :select_datetime,
|
||||
:field_by_xpath,
|
||||
:field_with_id,
|
||||
:selenium,
|
||||
:simulate, :automate,
|
||||
:field_named
|
||||
:clicks_link_within,
|
||||
:field_labeled
|
||||
|
||||
end
|
||||
end
|
@ -1,18 +1,29 @@
|
||||
module Webrat #:nodoc:
|
||||
module MIME #:nodoc:
|
||||
MIME_TYPES = Rack::Mime::MIME_TYPES.dup.merge(
|
||||
".multipart_form" => "multipart/form-data",
|
||||
".url_encoded_form" => "application/x-www-form-urlencoded"
|
||||
).freeze
|
||||
module Webrat
|
||||
module MIME
|
||||
|
||||
def mime_type(type)
|
||||
return type if type.nil? || type.to_s.include?("/")
|
||||
type = ".#{type}" unless type.to_s[0] == ?.
|
||||
MIME_TYPES.fetch(type) { |invalid_type|
|
||||
raise ArgumentError.new("Invalid Mime type: #{invalid_type}")
|
||||
}
|
||||
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
|
||||
|
||||
module_function :mime_type
|
||||
end
|
||||
end
|
44
lib/webrat/core/nokogiri.rb
Normal file
44
lib/webrat/core/nokogiri.rb
Normal 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
|
@ -1,28 +0,0 @@
|
||||
module Webrat
|
||||
module SaveAndOpenPage
|
||||
# Saves the page out to RAILS_ROOT/tmp/ and opens it in the default
|
||||
# web browser if on OS X. Useful for debugging.
|
||||
#
|
||||
# Example:
|
||||
# save_and_open_page
|
||||
def save_and_open_page
|
||||
return unless File.exist?(Webrat.configuration.saved_pages_dir)
|
||||
|
||||
filename = "#{Webrat.configuration.saved_pages_dir}/webrat-#{Time.now.to_i}.html"
|
||||
|
||||
File.open(filename, "w") do |f|
|
||||
f.write response_body
|
||||
end
|
||||
|
||||
open_in_browser(filename)
|
||||
end
|
||||
|
||||
def open_in_browser(path) # :nodoc
|
||||
require "launchy"
|
||||
Launchy::Browser.run(path)
|
||||
rescue LoadError
|
||||
warn "Sorry, you need to install launchy to open pages: `gem install launchy`"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,14 +1,11 @@
|
||||
require "webrat/core/elements/form"
|
||||
require "nokogiri"
|
||||
require "webrat/core/form"
|
||||
require "webrat/core/locators"
|
||||
require "webrat/core_extensions/deprecate"
|
||||
|
||||
module Webrat
|
||||
# An HTML element (link, button, field, etc.) that Webrat expected was not found on the page
|
||||
class NotFoundError < WebratError
|
||||
end
|
||||
|
||||
class Scope
|
||||
include Logging
|
||||
include Flunk
|
||||
include Locators
|
||||
|
||||
def self.from_page(session, response, response_body) #:nodoc:
|
||||
@ -25,16 +22,9 @@ module Webrat
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :session
|
||||
|
||||
def initialize(session, &block) #:nodoc:
|
||||
@selector, @dom = nil
|
||||
@session = session
|
||||
instance_eval(&block) if block_given?
|
||||
|
||||
if @selector && scoped_dom.nil?
|
||||
raise Webrat::NotFoundError.new("The scope was not found on the page: #{@selector.inspect}")
|
||||
end
|
||||
end
|
||||
|
||||
# Verifies an input field or textarea exists on the current page, and stores a value for
|
||||
@ -53,17 +43,7 @@ module Webrat
|
||||
field.set(options[:with])
|
||||
end
|
||||
|
||||
webrat_deprecate :fills_in, :fill_in
|
||||
|
||||
# Verifies that a hidden field exists on the current page and sets
|
||||
# the value to that given by the <tt>:to</tt> option.
|
||||
#
|
||||
# Example:
|
||||
# set_hidden_field 'user_id', :to => 1
|
||||
def set_hidden_field(field_locator, options = {})
|
||||
field = locate_field(field_locator, HiddenField)
|
||||
field.set(options[:to])
|
||||
end
|
||||
alias_method :fills_in, :fill_in
|
||||
|
||||
# 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.
|
||||
@ -74,7 +54,7 @@ module Webrat
|
||||
locate_field(field_locator, CheckboxField).check
|
||||
end
|
||||
|
||||
webrat_deprecate :checks, :check
|
||||
alias_method :checks, :check
|
||||
|
||||
# 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.
|
||||
@ -85,7 +65,7 @@ module Webrat
|
||||
locate_field(field_locator, CheckboxField).uncheck
|
||||
end
|
||||
|
||||
webrat_deprecate :unchecks, :uncheck
|
||||
alias_method :unchecks, :uncheck
|
||||
|
||||
# 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.
|
||||
@ -96,7 +76,7 @@ module Webrat
|
||||
locate_field(field_locator, RadioField).choose
|
||||
end
|
||||
|
||||
webrat_deprecate :chooses, :choose
|
||||
alias_method :chooses, :choose
|
||||
|
||||
# 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
|
||||
@ -104,149 +84,33 @@ module Webrat
|
||||
# a label. Stores the option's value to be sent when the form is submitted.
|
||||
#
|
||||
# Examples:
|
||||
# select "January"
|
||||
# select "February", :from => "event_month"
|
||||
# select "February", :from => "Event Month"
|
||||
def select(option_text, options = {})
|
||||
select_option(option_text, options[:from]).choose
|
||||
# selects "January"
|
||||
# selects "February", :from => "event_month"
|
||||
# selects "February", :from => "Event Month"
|
||||
def selects(option_text, options = {})
|
||||
find_select_option(option_text, options[:from]).choose
|
||||
end
|
||||
|
||||
webrat_deprecate :selects, :select
|
||||
|
||||
# Verifies that a an option element exists on the current page with the specified
|
||||
# text. You can optionally restrict the search to a specific select list by
|
||||
# assigning <tt>options[:from]</tt> the value of the select list's name or
|
||||
# a label. Remove the option's value before the form is submitted.
|
||||
#
|
||||
# Examples:
|
||||
# unselect "January"
|
||||
# unselect "February", :from => "event_month"
|
||||
# unselect "February", :from => "Event Month"
|
||||
def unselect(option_text, options={})
|
||||
select_option(option_text, options[:from]).unchoose
|
||||
end
|
||||
|
||||
webrat_deprecate :unselects, :unselect
|
||||
|
||||
DATE_TIME_SUFFIXES = {
|
||||
:year => '1i',
|
||||
:month => '2i',
|
||||
:day => '3i',
|
||||
:hour => '4i',
|
||||
:minute => '5i'
|
||||
}
|
||||
|
||||
# Verifies that date elements (year, month, day) exist on the current page
|
||||
# with the specified values. You can optionally restrict the search to a specific
|
||||
# date's elements by assigning <tt>options[:from]</tt> the value of the date's
|
||||
# label. Selects all the date elements with date provided. The date provided may
|
||||
# be a string or a Date/Time object.
|
||||
#
|
||||
# Rail's convention is used for detecting the date elements. All elements
|
||||
# are assumed to have a shared prefix. You may also specify the prefix
|
||||
# by assigning <tt>options[:id_prefix]</tt>.
|
||||
#
|
||||
# Examples:
|
||||
# select_date "January 23, 2004"
|
||||
# select_date "April 26, 1982", :from => "Birthday"
|
||||
# select_date Date.parse("December 25, 2000"), :from => "Event"
|
||||
# select_date "April 26, 1982", :id_prefix => 'birthday'
|
||||
def select_date(date_to_select, options ={})
|
||||
date = date_to_select.is_a?(Date) || date_to_select.is_a?(Time) ?
|
||||
date_to_select : Date.parse(date_to_select)
|
||||
|
||||
id_prefix = locate_id_prefix(options) do
|
||||
year_field = FieldByIdLocator.new(@session, dom, /(.*?)_#{DATE_TIME_SUFFIXES[:year]}$/).locate
|
||||
raise NotFoundError.new("No date fields were found") unless year_field && year_field.id =~ /(.*?)_1i/
|
||||
$1
|
||||
end
|
||||
|
||||
select date.year, :from => "#{id_prefix}_#{DATE_TIME_SUFFIXES[:year]}"
|
||||
select date.strftime('%B'), :from => "#{id_prefix}_#{DATE_TIME_SUFFIXES[:month]}"
|
||||
select date.day, :from => "#{id_prefix}_#{DATE_TIME_SUFFIXES[:day]}"
|
||||
end
|
||||
|
||||
webrat_deprecate :selects_date, :select_date
|
||||
|
||||
# Verifies that time elements (hour, minute) exist on the current page
|
||||
# with the specified values. You can optionally restrict the search to a specific
|
||||
# time's elements by assigning <tt>options[:from]</tt> the value of the time's
|
||||
# label. Selects all the time elements with date provided. The time provided may
|
||||
# be a string or a Time object.
|
||||
#
|
||||
# Rail's convention is used for detecting the time elements. All elements are
|
||||
# assumed to have a shared prefix. You may specify the prefix by assigning
|
||||
# <tt>options[:id_prefix]</tt>.
|
||||
#
|
||||
# Note: Just like Rails' time_select helper this assumes the form is using
|
||||
# 24 hour select boxes, and not 12 hours with AM/PM.
|
||||
#
|
||||
# Examples:
|
||||
# select_time "9:30"
|
||||
# select_date "3:30PM", :from => "Party Time"
|
||||
# select_date Time.parse("10:00PM"), :from => "Event"
|
||||
# select_date "10:30AM", :id_prefix => 'meeting'
|
||||
def select_time(time_to_select, options ={})
|
||||
time = time_to_select.is_a?(Time) ? time_to_select : Time.parse(time_to_select)
|
||||
|
||||
id_prefix = locate_id_prefix(options) do
|
||||
hour_field = FieldByIdLocator.new(@session, dom, /(.*?)_#{DATE_TIME_SUFFIXES[:hour]}$/).locate
|
||||
raise NotFoundError.new("No time fields were found") unless hour_field && hour_field.id =~ /(.*?)_4i/
|
||||
$1
|
||||
end
|
||||
|
||||
select time.hour.to_s.rjust(2,'0'), :from => "#{id_prefix}_#{DATE_TIME_SUFFIXES[:hour]}"
|
||||
select time.min.to_s.rjust(2,'0'), :from => "#{id_prefix}_#{DATE_TIME_SUFFIXES[:minute]}"
|
||||
end
|
||||
|
||||
webrat_deprecate :selects_time, :select_time
|
||||
|
||||
# Verifies and selects all the date and time elements on the current page.
|
||||
# See #select_time and #select_date for more details and available options.
|
||||
#
|
||||
# Examples:
|
||||
# select_datetime "January 23, 2004 10:30AM"
|
||||
# select_datetime "April 26, 1982 7:00PM", :from => "Birthday"
|
||||
# select_datetime Time.parse("December 25, 2000 15:30"), :from => "Event"
|
||||
# select_datetime "April 26, 1982 5:50PM", :id_prefix => 'birthday'
|
||||
def select_datetime(time_to_select, options ={})
|
||||
time = time_to_select.is_a?(Time) ? time_to_select : Time.parse(time_to_select)
|
||||
|
||||
options[:id_prefix] ||= (options[:from] ? FieldByIdLocator.new(@session, dom, options[:from]).locate : nil)
|
||||
|
||||
select_date time, options
|
||||
select_time time, options
|
||||
end
|
||||
|
||||
webrat_deprecate :selects_datetime, :select_datetime
|
||||
alias_method :select, :selects
|
||||
|
||||
# Verifies that an input file field exists on the current page and sets
|
||||
# its value to the given +file+, so that the file will be uploaded
|
||||
# along with the form. An optional <tt>content_type</tt> may be given.
|
||||
#
|
||||
# Example:
|
||||
# attach_file "Resume", "/path/to/the/resume.txt"
|
||||
# attach_file "Photo", "/path/to/the/image.png", "image/png"
|
||||
# attaches_file "Resume", "/path/to/the/resume.txt"
|
||||
# attaches_file "Photo", "/path/to/the/image.png", "image/png"
|
||||
def attach_file(field_locator, path, content_type = nil)
|
||||
locate_field(field_locator, FileField).set(path, content_type)
|
||||
end
|
||||
|
||||
webrat_deprecate :attaches_file, :attach_file
|
||||
alias_method :attaches_file, :attach_file
|
||||
|
||||
# Issues a request for the URL pointed to by an <tt>area</tt> tag
|
||||
# on the current page, follows any redirects, and verifies the
|
||||
# final page load was successful.
|
||||
#
|
||||
# The area used is the first area whose title or id contains the
|
||||
# given +area_name+ (case is ignored).
|
||||
#
|
||||
# Example:
|
||||
# click_area 'Australia'
|
||||
def click_area(area_name)
|
||||
find_area(area_name).click
|
||||
end
|
||||
|
||||
webrat_deprecate :clicks_area, :click_area
|
||||
alias_method :clicks_area, :click_area
|
||||
|
||||
# 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.
|
||||
@ -260,23 +124,17 @@ module Webrat
|
||||
# Passing a :method in the options hash overrides the HTTP method used
|
||||
# for making the link request
|
||||
#
|
||||
# It will try to find links by (in order of precedence):
|
||||
# innerHTML, with simple handling
|
||||
# title
|
||||
# id
|
||||
#
|
||||
# innerHTML and title are matchable by text subtring or Regexp
|
||||
# id is matchable by full text equality or Regexp
|
||||
#
|
||||
# Example:
|
||||
# click_link "Sign up"
|
||||
#
|
||||
# click_link "Sign up", :javascript => false
|
||||
#
|
||||
# click_link "Sign up", :method => :put
|
||||
def click_link(text_or_title_or_id, options = {})
|
||||
find_link(text_or_title_or_id).click(options)
|
||||
def click_link(link_text, options = {})
|
||||
find_link(link_text).click(options)
|
||||
end
|
||||
|
||||
webrat_deprecate :clicks_link, :click_link
|
||||
alias_method :clicks_link, :click_link
|
||||
|
||||
# Verifies that a submit button exists for the form, then submits the form, follows
|
||||
# any redirects, and verifies the final page was successful.
|
||||
@ -291,19 +149,7 @@ module Webrat
|
||||
find_button(value).click
|
||||
end
|
||||
|
||||
webrat_deprecate :clicks_button, :click_button
|
||||
|
||||
# Submit the form with the given id.
|
||||
#
|
||||
# Note that +click_button+ is usually preferrable for simulating
|
||||
# form submissions, as you may specify part of the button text
|
||||
# rather than the form id.
|
||||
#
|
||||
# Example:
|
||||
# submit_form 'login'
|
||||
def submit_form(id)
|
||||
FormLocator.new(@session, dom, id).locate.submit
|
||||
end
|
||||
alias_method :clicks_button, :click_button
|
||||
|
||||
def dom # :nodoc:
|
||||
return @dom if @dom
|
||||
@ -321,19 +167,13 @@ module Webrat
|
||||
|
||||
def page_dom #:nodoc:
|
||||
return @response.dom if @response.respond_to?(:dom)
|
||||
|
||||
if @session.xml_content_type?
|
||||
dom = Webrat::XML.xml_document(@response_body)
|
||||
else
|
||||
dom = Webrat::XML.html_document(@response_body)
|
||||
end
|
||||
|
||||
Webrat::XML.define_dom_method(@response, dom)
|
||||
dom = Webrat.nokogiri_document(@response_body)
|
||||
Webrat.define_dom_method(@response, dom)
|
||||
return dom
|
||||
end
|
||||
|
||||
def scoped_dom
|
||||
@scope.dom.css(@selector).first
|
||||
def scoped_dom #:nodoc:
|
||||
Webrat.nokogiri_document(@scope.dom.search(@selector).first.to_html)
|
||||
end
|
||||
|
||||
def locate_field(field_locator, *field_types) #:nodoc:
|
||||
@ -344,22 +184,24 @@ module Webrat
|
||||
end
|
||||
end
|
||||
|
||||
def locate_id_prefix(options, &location_strategy) #:nodoc:
|
||||
return options[:id_prefix] if options[:id_prefix]
|
||||
|
||||
if options[:from]
|
||||
if (label = LabelLocator.new(@session, dom, options[:from]).locate)
|
||||
label.for_id
|
||||
else
|
||||
raise NotFoundError.new("Could not find the label with text #{options[:from]}")
|
||||
def areas #:nodoc:
|
||||
dom.search("area").map do |element|
|
||||
Area.new(@session, element)
|
||||
end
|
||||
else
|
||||
yield
|
||||
end
|
||||
|
||||
def links #:nodoc:
|
||||
dom.search("a[@href]").map do |link_element|
|
||||
Link.new(@session, link_element)
|
||||
end
|
||||
end
|
||||
|
||||
def forms #:nodoc:
|
||||
@forms ||= Form.load_all(@session, dom)
|
||||
return @forms if @forms
|
||||
|
||||
@forms = dom.search("form").map do |form_element|
|
||||
Form.new(@session, form_element)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
29
lib/webrat/core/select_option.rb
Normal file
29
lib/webrat/core/select_option.rb
Normal file
@ -0,0 +1,29 @@
|
||||
module Webrat
|
||||
class SelectOption #:nodoc:
|
||||
|
||||
def initialize(select, element)
|
||||
@select = select
|
||||
@element = element
|
||||
end
|
||||
|
||||
def matches_text?(text)
|
||||
if text.is_a?(Regexp)
|
||||
@element.inner_html =~ text
|
||||
else
|
||||
@element.inner_html == text.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def choose
|
||||
@select.raise_error_if_disabled
|
||||
@select.set(value)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def value
|
||||
@element["value"] || @element.inner_html
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -2,81 +2,37 @@ require "forwardable"
|
||||
require "ostruct"
|
||||
|
||||
require "webrat/core/mime"
|
||||
require "webrat/core/save_and_open_page"
|
||||
|
||||
module Webrat
|
||||
# A page load or form submission returned an unsuccessful response code (500-599)
|
||||
class PageLoadError < WebratError
|
||||
end
|
||||
|
||||
class InfiniteRedirectError < WebratError
|
||||
end
|
||||
|
||||
def self.session_class
|
||||
if Webrat.configuration.mode == :selenium
|
||||
SeleniumSession
|
||||
else
|
||||
Session
|
||||
end
|
||||
end
|
||||
|
||||
def self.adapter_class
|
||||
case Webrat.configuration.mode
|
||||
when :rails
|
||||
RailsAdapter
|
||||
when :merb
|
||||
MerbAdapter
|
||||
when :rack
|
||||
RackAdapter
|
||||
when :rack_test
|
||||
warn("The :rack_test mode is deprecated. Please use :rack instead")
|
||||
require "webrat/rack"
|
||||
RackAdapter
|
||||
when :sinatra
|
||||
warn("The :sinatra mode is deprecated. Please use :rack instead")
|
||||
SinatraAdapter
|
||||
when :mechanize
|
||||
MechanizeAdapter
|
||||
else
|
||||
raise WebratError.new(<<-STR)
|
||||
Unknown Webrat mode: #{Webrat.configuration.mode.inspect}
|
||||
|
||||
Please ensure you have a Webrat configuration block that specifies a mode
|
||||
in your test_helper.rb, spec_helper.rb, or env.rb (for Cucumber).
|
||||
|
||||
This configure block supercedes the need to require "webrat/<framework>".
|
||||
|
||||
For example:
|
||||
|
||||
Webrat.configure do |config|
|
||||
config.mode = :rails
|
||||
end
|
||||
STR
|
||||
end
|
||||
end
|
||||
|
||||
class Session
|
||||
extend Forwardable
|
||||
include Logging
|
||||
include SaveAndOpenPage
|
||||
|
||||
attr_accessor :adapter
|
||||
include Flunk
|
||||
|
||||
attr_reader :current_url
|
||||
attr_reader :elements
|
||||
|
||||
def_delegators :@adapter, :response, :response_code, :response_body, :response_headers,
|
||||
:response_body=, :response_code=,
|
||||
:get, :post, :put, :delete
|
||||
|
||||
def initialize(adapter = nil)
|
||||
@adapter = adapter
|
||||
def initialize #:nodoc:
|
||||
@http_method = :get
|
||||
@data = {}
|
||||
@default_headers = {}
|
||||
@custom_headers = {}
|
||||
@current_url = nil
|
||||
reset
|
||||
end
|
||||
|
||||
# Saves the page out to RAILS_ROOT/tmp/ and opens it in the default
|
||||
# web browser if on OS X. Useful for debugging.
|
||||
#
|
||||
# Example:
|
||||
# save_and_open_page
|
||||
def save_and_open_page
|
||||
return unless File.exist?(saved_page_dir)
|
||||
|
||||
filename = "#{saved_page_dir}/webrat-#{Time.now.to_i}.html"
|
||||
|
||||
File.open(filename, "w") do |f|
|
||||
f.write rewrite_css_and_image_references(response_body)
|
||||
end
|
||||
|
||||
open_in_browser(filename)
|
||||
end
|
||||
|
||||
def current_dom #:nodoc:
|
||||
@ -85,7 +41,6 @@ For example:
|
||||
|
||||
# For backwards compatibility -- removing in 1.0
|
||||
def current_page #:nodoc:
|
||||
warn "current_page is deprecated and will be going away in the next release. Use current_url instead."
|
||||
page = OpenStruct.new
|
||||
page.url = @current_url
|
||||
page.http_method = @http_method
|
||||
@ -93,6 +48,14 @@ For example:
|
||||
page
|
||||
end
|
||||
|
||||
def doc_root #:nodoc:
|
||||
nil
|
||||
end
|
||||
|
||||
def saved_page_dir #:nodoc:
|
||||
File.expand_path(".")
|
||||
end
|
||||
|
||||
def header(key, value)
|
||||
@custom_headers[key] = value
|
||||
end
|
||||
@ -102,7 +65,7 @@ For example:
|
||||
end
|
||||
|
||||
def basic_auth(user, pass)
|
||||
encoded_login = ["#{user}:#{pass}"].pack("m*").gsub(/\n/, '')
|
||||
encoded_login = ["#{user}:#{pass}"].pack("m*")
|
||||
header('HTTP_AUTHORIZATION', "Basic #{encoded_login}")
|
||||
end
|
||||
|
||||
@ -115,63 +78,28 @@ For example:
|
||||
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 || {}
|
||||
else
|
||||
send "#{http_method}", url, data || {}, h
|
||||
end
|
||||
|
||||
process_request(http_method, url, data, h)
|
||||
|
||||
save_and_open_page if exception_caught? && Webrat.configuration.open_error_files?
|
||||
raise PageLoadError.new("Page load was not successful (Code: #{response_code.inspect}):\n#{formatted_error}") unless success_code?
|
||||
|
||||
reset
|
||||
save_and_open_page if exception_caught?
|
||||
flunk("Page load was not successful (Code: #{response_code.inspect}):\n#{formatted_error}") unless success_code?
|
||||
|
||||
@_scopes = nil
|
||||
@_page_scope = nil
|
||||
@current_url = url
|
||||
@http_method = http_method
|
||||
@data = data
|
||||
|
||||
if internal_redirect?
|
||||
check_for_infinite_redirects
|
||||
request_page(response_location, :get, {})
|
||||
end
|
||||
|
||||
return response
|
||||
end
|
||||
|
||||
def check_for_infinite_redirects
|
||||
if current_url == response_location
|
||||
@_identical_redirect_count ||= 0
|
||||
@_identical_redirect_count += 1
|
||||
end
|
||||
|
||||
if infinite_redirect_limit_exceeded?
|
||||
raise InfiniteRedirectError.new("#{Webrat.configuration.infinite_redirect_limit} redirects to the same URL (#{current_url.inspect})")
|
||||
end
|
||||
end
|
||||
|
||||
def infinite_redirect_limit_exceeded?
|
||||
Webrat.configuration.infinite_redirect_limit &&
|
||||
(@_identical_redirect_count || 0) > Webrat.configuration.infinite_redirect_limit
|
||||
end
|
||||
|
||||
def success_code? #:nodoc:
|
||||
(200..499).include?(response_code)
|
||||
end
|
||||
|
||||
def redirect? #:nodoc:
|
||||
[301, 302, 303, 307].include?(response_code)
|
||||
end
|
||||
|
||||
def internal_redirect?
|
||||
return false unless redirect?
|
||||
#should keep internal_redirects if the subdomain changes
|
||||
current_host_domain = current_host.split('.')[-2..-1].join('.') rescue current_host
|
||||
response_location_host_domain = response_location_host.split('.')[-2..-1].join('.') rescue response_location_host
|
||||
current_host_domain == response_location_host_domain
|
||||
end
|
||||
|
||||
#easy helper to pull out where we were redirected to
|
||||
def redirected_to
|
||||
redirect? ? response_location : nil
|
||||
end
|
||||
|
||||
def exception_caught? #:nodoc:
|
||||
response_body =~ /Exception caught/
|
||||
end
|
||||
@ -182,11 +110,14 @@ For example:
|
||||
|
||||
# Reloads the last page requested. Note that this will resubmit forms
|
||||
# and their data.
|
||||
def reload
|
||||
#
|
||||
# Example:
|
||||
# reloads
|
||||
def reloads
|
||||
request_page(@current_url, @http_method, @data)
|
||||
end
|
||||
|
||||
webrat_deprecate :reloads, :reload
|
||||
alias_method :reload, :reloads
|
||||
|
||||
|
||||
# Works like click_link, but only looks for the link text within a given selector
|
||||
@ -199,7 +130,7 @@ For example:
|
||||
end
|
||||
end
|
||||
|
||||
webrat_deprecate :clicks_link_within, :click_link_within
|
||||
alias_method :clicks_link_within, :click_link_within
|
||||
|
||||
def within(selector)
|
||||
scopes.push(Scope.from_scope(self, current_scope, selector))
|
||||
@ -217,7 +148,16 @@ For example:
|
||||
request_page(url, http_method, data)
|
||||
end
|
||||
|
||||
webrat_deprecate :visits, :visit
|
||||
alias_method :visits, :visit
|
||||
|
||||
def open_in_browser(path) #:nodoc
|
||||
`open #{path}`
|
||||
end
|
||||
|
||||
def rewrite_css_and_image_references(response_html) #:nodoc
|
||||
return response_html unless doc_root
|
||||
response_html.gsub(/"\/(stylesheets|images)/, doc_root + '/\1')
|
||||
end
|
||||
|
||||
# Subclasses can override this to show error messages without html
|
||||
def formatted_error #:nodoc:
|
||||
@ -232,72 +172,17 @@ For example:
|
||||
@_page_scope ||= Scope.from_page(self, response, response_body)
|
||||
end
|
||||
|
||||
def dom
|
||||
page_scope.dom
|
||||
end
|
||||
|
||||
def xml_content_type?
|
||||
false
|
||||
end
|
||||
|
||||
def simulate
|
||||
return if Webrat.configuration.mode == :selenium
|
||||
yield
|
||||
end
|
||||
|
||||
def automate
|
||||
return unless Webrat.configuration.mode == :selenium
|
||||
yield
|
||||
end
|
||||
|
||||
def_delegators :current_scope, :fill_in, :fills_in
|
||||
def_delegators :current_scope, :set_hidden_field
|
||||
def_delegators :current_scope, :submit_form
|
||||
def_delegators :current_scope, :check, :checks
|
||||
def_delegators :current_scope, :uncheck, :unchecks
|
||||
def_delegators :current_scope, :choose, :chooses
|
||||
def_delegators :current_scope, :select, :selects
|
||||
def_delegators :current_scope, :unselect, :unselects
|
||||
def_delegators :current_scope, :select_datetime, :selects_datetime
|
||||
def_delegators :current_scope, :select_date, :selects_date
|
||||
def_delegators :current_scope, :select_time, :selects_time
|
||||
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_button, :clicks_button
|
||||
def_delegators :current_scope, :should_see
|
||||
def_delegators :current_scope, :should_not_see
|
||||
def_delegators :current_scope, :field_labeled
|
||||
def_delegators :current_scope, :field_by_xpath
|
||||
def_delegators :current_scope, :field_with_id
|
||||
def_delegators :current_scope, :select_option
|
||||
def_delegators :current_scope, :field_named
|
||||
|
||||
private
|
||||
|
||||
def process_request(http_method, url, data, headers)
|
||||
if headers.empty?
|
||||
send "#{http_method}", url, data || {}
|
||||
else
|
||||
send "#{http_method}", url, data || {}, headers
|
||||
end
|
||||
end
|
||||
|
||||
def response_location
|
||||
response_headers['Location']
|
||||
end
|
||||
|
||||
def current_host
|
||||
URI.parse(current_url).host || @custom_headers["Host"] || "www.example.com"
|
||||
end
|
||||
|
||||
def response_location_host
|
||||
URI.parse(response_location).host || "www.example.com"
|
||||
end
|
||||
|
||||
def reset
|
||||
@elements = {}
|
||||
@_scopes = nil
|
||||
@_page_scope = nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,72 +0,0 @@
|
||||
require "webrat/core_extensions/meta_class"
|
||||
|
||||
module Webrat #:nodoc:
|
||||
module XML #:nodoc:
|
||||
|
||||
def self.document(stringlike) #:nodoc:
|
||||
return stringlike.dom if stringlike.respond_to?(:dom)
|
||||
|
||||
if Nokogiri::HTML::Document === stringlike
|
||||
stringlike
|
||||
elsif Nokogiri::XML::NodeSet === stringlike
|
||||
stringlike
|
||||
elsif stringlike.respond_to?(:body)
|
||||
Nokogiri::HTML(stringlike.body.to_s)
|
||||
else
|
||||
Nokogiri::HTML(stringlike.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def self.html_document(stringlike) #:nodoc:
|
||||
return stringlike.dom if stringlike.respond_to?(:dom)
|
||||
|
||||
if Nokogiri::HTML::Document === stringlike
|
||||
stringlike
|
||||
elsif Nokogiri::XML::NodeSet === stringlike
|
||||
stringlike
|
||||
elsif stringlike.respond_to?(:body)
|
||||
Nokogiri::HTML(stringlike.body.to_s)
|
||||
else
|
||||
Nokogiri::HTML(stringlike.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def self.xml_document(stringlike) #:nodoc:
|
||||
return stringlike.dom if stringlike.respond_to?(:dom)
|
||||
|
||||
if Nokogiri::HTML::Document === stringlike
|
||||
stringlike
|
||||
elsif Nokogiri::XML::NodeSet === stringlike
|
||||
stringlike
|
||||
elsif stringlike.respond_to?(:body)
|
||||
Nokogiri::XML(stringlike.body.to_s)
|
||||
else
|
||||
Nokogiri::XML(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
|
||||
end
|
||||
|
||||
module Nokogiri #:nodoc:
|
||||
module CSS #:nodoc:
|
||||
class XPathVisitor #:nodoc:
|
||||
|
||||
def visit_pseudo_class_text(node) #:nodoc:
|
||||
"@type='text'"
|
||||
end
|
||||
|
||||
def visit_pseudo_class_password(node) #:nodoc:
|
||||
"@type='password'"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,5 @@
|
||||
class Module #:nodoc:
|
||||
def webrat_deprecate(old_method_name, new_method_name)
|
||||
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)
|
||||
|
131
lib/webrat/core_extensions/hash_with_indifferent_access.rb
Normal file
131
lib/webrat/core_extensions/hash_with_indifferent_access.rb
Normal 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
|
@ -1,5 +1,5 @@
|
||||
class NilClass #:nodoc:
|
||||
def to_query_string
|
||||
def to_param
|
||||
nil
|
||||
end
|
||||
end
|
@ -1,27 +0,0 @@
|
||||
class TCPSocket
|
||||
|
||||
def self.wait_for_service_with_timeout(options)
|
||||
start_time = Time.now
|
||||
|
||||
until listening_service?(options)
|
||||
verbose_wait
|
||||
|
||||
if options[:timeout] && (Time.now > start_time + options[:timeout])
|
||||
raise SocketError.new("Socket did not open within #{options[:timeout]} seconds")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.wait_for_service_termination_with_timeout(options)
|
||||
start_time = Time.now
|
||||
|
||||
while listening_service?(options)
|
||||
verbose_wait
|
||||
|
||||
if options[:timeout] && (Time.now > start_time + options[:timeout])
|
||||
raise SocketError.new("Socket did not terminate within #{options[:timeout]} seconds")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -1,10 +0,0 @@
|
||||
module Merb #:nodoc:
|
||||
module Test #:nodoc:
|
||||
module RequestHelper #:nodoc:
|
||||
def request(uri, env = {})
|
||||
@_webrat_session ||= Webrat::MerbAdapter.new
|
||||
@_webrat_session.response = @_webrat_session.request(uri, env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,25 +0,0 @@
|
||||
require "action_controller"
|
||||
require "action_controller/integration"
|
||||
|
||||
module ActionController #:nodoc:
|
||||
IntegrationTest.class_eval do
|
||||
include Webrat::Methods
|
||||
include Webrat::Matchers
|
||||
|
||||
# The Rails version of within supports passing in a model and Webrat
|
||||
# will apply a scope based on Rails' dom_id for that model.
|
||||
#
|
||||
# Example:
|
||||
# within User.last do
|
||||
# click_link "Delete"
|
||||
# end
|
||||
def within(selector_or_object, &block)
|
||||
if selector_or_object.is_a?(String)
|
||||
super
|
||||
else
|
||||
super('#' + RecordIdentifier.dom_id(selector_or_object), &block)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,11 +0,0 @@
|
||||
# Supports using the matchers in controller, helper, and view specs if you're
|
||||
# using rspec-rails. Just add a require statement to spec/spec_helper.rb or env.rb:
|
||||
#
|
||||
# require 'webrat/integrations/rspec-rails'
|
||||
#
|
||||
require "nokogiri"
|
||||
require "webrat/core/matchers"
|
||||
|
||||
Spec::Runner.configure do |config|
|
||||
config.include(Webrat::Matchers, :type => [:controller, :helper, :view])
|
||||
end
|
@ -1,11 +0,0 @@
|
||||
require "webrat/selenium"
|
||||
|
||||
if defined?(ActionController::IntegrationTest)
|
||||
module ActionController #:nodoc:
|
||||
IntegrationTest.class_eval do
|
||||
include Webrat::Methods
|
||||
include Webrat::Selenium::Methods
|
||||
include Webrat::Selenium::Matchers
|
||||
end
|
||||
end
|
||||
end
|
28
lib/webrat/mechanize.rb
Normal file
28
lib/webrat/mechanize.rb
Normal file
@ -0,0 +1,28 @@
|
||||
require "mechanize"
|
||||
|
||||
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
|
@ -1,9 +1,75 @@
|
||||
require "webrat"
|
||||
require "webrat/core"
|
||||
|
||||
# This is a temporary hack to support backwards compatibility
|
||||
# with Merb 1.0.8 until it's updated to use the new Webrat.configure
|
||||
# syntax
|
||||
require "cgi"
|
||||
gem "extlib"
|
||||
require "extlib"
|
||||
require "merb-core"
|
||||
|
||||
Webrat.configure do |config|
|
||||
config.mode = :merb
|
||||
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
24
lib/webrat/rack.rb
Normal 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
|
102
lib/webrat/rails.rb
Normal file
102
lib/webrat/rails.rb
Normal file
@ -0,0 +1,102 @@
|
||||
require "webrat"
|
||||
|
||||
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
|
18
lib/webrat/rails/redirect_actions.rb
Normal file
18
lib/webrat/rails/redirect_actions.rb
Normal file
@ -0,0 +1,18 @@
|
||||
# For Rails before http://dev.rubyonrails.org/ticket/10497 was committed
|
||||
module Webrat
|
||||
module RedirectActions #:nodoc:
|
||||
|
||||
def put_via_redirect(path, parameters = {}, headers = {})
|
||||
put path, parameters, headers
|
||||
follow_redirect! while redirect?
|
||||
status
|
||||
end
|
||||
|
||||
def delete_via_redirect(path, parameters = {}, headers = {})
|
||||
delete path, parameters, headers
|
||||
follow_redirect! while redirect?
|
||||
status
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,2 +0,0 @@
|
||||
warn("Requiring 'webrat/rspec-rails' is deprecated. Please require 'webrat/integrations/rspec-rails' instead")
|
||||
require "webrat/integrations/rspec-rails"
|
@ -1,70 +1,3 @@
|
||||
require "webrat"
|
||||
require "selenium/client"
|
||||
require "webrat/selenium/silence_stream"
|
||||
require "selenium"
|
||||
require "webrat/selenium/selenium_session"
|
||||
require "webrat/selenium/matchers"
|
||||
require "webrat/core_extensions/tcp_socket"
|
||||
|
||||
module Webrat
|
||||
# To use Webrat's Selenium support, you'll need the selenium-client gem installed.
|
||||
# Activate it with (for example, in your <tt>env.rb</tt>):
|
||||
#
|
||||
# require "webrat"
|
||||
#
|
||||
# Webrat.configure do |config|
|
||||
# config.mode = :selenium
|
||||
# end
|
||||
#
|
||||
# == Dropping down to the selenium-client API
|
||||
#
|
||||
# If you ever need to do something with Selenium not provided in the Webrat API,
|
||||
# you can always drop down to the selenium-client API using the <tt>selenium</tt> method.
|
||||
# For example:
|
||||
#
|
||||
# When "I drag the photo to the left" do
|
||||
# selenium.dragdrop("id=photo_123", "+350, 0")
|
||||
# end
|
||||
#
|
||||
# == Choosing the underlying framework to test
|
||||
#
|
||||
# Webrat assumes you're using rails by default but it can also work with sinatra
|
||||
# and merb. To take advantage of this you can use the configuration block to
|
||||
# set the application_framework variable.
|
||||
# require "webrat"
|
||||
#
|
||||
# Webrat.configure do |config|
|
||||
# config.mode = :selenium
|
||||
# config.application_port = 4567
|
||||
# config.application_framework = :sinatra # could also be :merb
|
||||
# end
|
||||
#
|
||||
# == Auto-starting of the appserver and java server
|
||||
#
|
||||
# Webrat will automatically start the Selenium Java server process and an instance
|
||||
# of Mongrel when a test is run. The Mongrel will run in the "selenium" environment
|
||||
# instead of "test", so ensure you've got that defined, and will run on port
|
||||
# Webrat.configuration.application_port.
|
||||
#
|
||||
# == Waiting
|
||||
#
|
||||
# In order to make writing Selenium tests as easy as possible, Webrat will automatically
|
||||
# wait for the correct elements to exist on the page when trying to manipulate them
|
||||
# with methods like <tt>fill_in</tt>, etc. In general, this means you should be able to write
|
||||
# your Webrat::Selenium tests ignoring the concurrency issues that can plague in-browser
|
||||
# testing, so long as you're using the Webrat API.
|
||||
module Selenium
|
||||
module Methods
|
||||
def response
|
||||
webrat_session.response
|
||||
end
|
||||
|
||||
def wait_for(*args, &block)
|
||||
webrat_session.wait_for(*args, &block)
|
||||
end
|
||||
|
||||
def save_and_open_screengrab
|
||||
webrat_session.save_and_open_screengrab
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,40 +0,0 @@
|
||||
module Webrat
|
||||
module Selenium
|
||||
|
||||
class ApplicationServerFactory
|
||||
|
||||
def self.app_server_instance
|
||||
case Webrat.configuration.application_framework
|
||||
when :sinatra
|
||||
require "webrat/selenium/application_servers/sinatra"
|
||||
return Webrat::Selenium::ApplicationServers::Sinatra.new
|
||||
when :merb
|
||||
require "webrat/selenium/application_servers/merb"
|
||||
return Webrat::Selenium::ApplicationServers::Merb.new
|
||||
when :rails
|
||||
require "webrat/selenium/application_servers/rails"
|
||||
return Webrat::Selenium::ApplicationServers::Rails.new
|
||||
when :external
|
||||
require "webrat/selenium/application_servers/external"
|
||||
return Webrat::Selenium::ApplicationServers::External.new
|
||||
else
|
||||
raise WebratError.new(<<-STR)
|
||||
Unknown Webrat application_framework: #{Webrat.configuration.application_framework.inspect}
|
||||
|
||||
Please ensure you have a Webrat configuration block that specifies an application_framework
|
||||
in your test_helper.rb, spec_helper.rb, or env.rb (for Cucumber).
|
||||
|
||||
For example:
|
||||
|
||||
Webrat.configure do |config|
|
||||
# ...
|
||||
config.application_framework = :rails
|
||||
end
|
||||
STR
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,5 +0,0 @@
|
||||
require "webrat/selenium/application_servers/base"
|
||||
require "webrat/selenium/application_servers/sinatra"
|
||||
require "webrat/selenium/application_servers/merb"
|
||||
require "webrat/selenium/application_servers/rails"
|
||||
require "webrat/selenium/application_servers/external"
|
@ -1,46 +0,0 @@
|
||||
require "webrat/selenium/silence_stream"
|
||||
|
||||
module Webrat
|
||||
module Selenium
|
||||
module ApplicationServers
|
||||
class Base
|
||||
include Webrat::Selenium::SilenceStream
|
||||
|
||||
def boot
|
||||
start
|
||||
wait
|
||||
stop_at_exit
|
||||
end
|
||||
|
||||
def stop_at_exit
|
||||
at_exit do
|
||||
stop
|
||||
end
|
||||
end
|
||||
|
||||
def wait
|
||||
$stderr.print "==> Waiting for #{Webrat.configuration.application_framework} application server on port #{Webrat.configuration.application_port}... "
|
||||
wait_for_socket
|
||||
$stderr.print "Ready!\n"
|
||||
end
|
||||
|
||||
def wait_for_socket
|
||||
silence_stream(STDOUT) do
|
||||
TCPSocket.wait_for_service_with_timeout \
|
||||
:host => "0.0.0.0",
|
||||
:port => Webrat.configuration.application_port.to_i,
|
||||
:timeout => 30 # seconds
|
||||
end
|
||||
rescue SocketError
|
||||
fail
|
||||
end
|
||||
|
||||
def prepare_pid_file(file_path, pid_file_name)
|
||||
FileUtils.mkdir_p File.expand_path(file_path)
|
||||
File.expand_path("#{file_path}/#{pid_file_name}")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,26 +0,0 @@
|
||||
require "webrat/selenium/application_servers/base"
|
||||
|
||||
module Webrat
|
||||
module Selenium
|
||||
module ApplicationServers
|
||||
class External < Webrat::Selenium::ApplicationServers::Base
|
||||
def start
|
||||
warn "Webrat Ignoring Start Of Application Server Due to External Mode"
|
||||
end
|
||||
|
||||
def stop
|
||||
end
|
||||
|
||||
def fail
|
||||
end
|
||||
|
||||
def pid_file
|
||||
end
|
||||
|
||||
def wait
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,50 +0,0 @@
|
||||
require "webrat/selenium/application_servers/base"
|
||||
|
||||
module Webrat
|
||||
module Selenium
|
||||
module ApplicationServers
|
||||
class Merb < Webrat::Selenium::ApplicationServers::Base
|
||||
|
||||
def start
|
||||
system start_command
|
||||
end
|
||||
|
||||
def stop
|
||||
silence_stream(STDOUT) do
|
||||
pid = File.read(pid_file)
|
||||
system("kill -9 #{pid}")
|
||||
FileUtils.rm_f pid_file
|
||||
end
|
||||
end
|
||||
|
||||
def fail
|
||||
$stderr.puts
|
||||
$stderr.puts
|
||||
$stderr.puts "==> Failed to boot the Merb application server... exiting!"
|
||||
$stderr.puts
|
||||
$stderr.puts "Verify you can start a Merb server on port #{Webrat.configuration.application_port} with the following command:"
|
||||
$stderr.puts
|
||||
$stderr.puts " #{start_command}"
|
||||
exit
|
||||
end
|
||||
|
||||
def pid_file
|
||||
"log/merb.#{Webrat.configuration.application_port}.pid"
|
||||
end
|
||||
|
||||
def start_command
|
||||
"#{merb_command} -d -p #{Webrat.configuration.application_port} -e #{Webrat.configuration.application_environment}"
|
||||
end
|
||||
|
||||
def merb_command
|
||||
if File.exist?('bin/merb')
|
||||
merb_cmd = 'bin/merb'
|
||||
else
|
||||
merb_cmd = 'merb'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,44 +0,0 @@
|
||||
require "webrat/selenium/application_servers/base"
|
||||
|
||||
module Webrat
|
||||
module Selenium
|
||||
module ApplicationServers
|
||||
class Rails < Webrat::Selenium::ApplicationServers::Base
|
||||
|
||||
def start
|
||||
system start_command
|
||||
end
|
||||
|
||||
def stop
|
||||
silence_stream(STDOUT) do
|
||||
system stop_command
|
||||
end
|
||||
end
|
||||
|
||||
def fail
|
||||
$stderr.puts
|
||||
$stderr.puts
|
||||
$stderr.puts "==> Failed to boot the Rails application server... exiting!"
|
||||
$stderr.puts
|
||||
$stderr.puts "Verify you can start a Rails server on port #{Webrat.configuration.application_port} with the following command:"
|
||||
$stderr.puts
|
||||
$stderr.puts " #{start_command}"
|
||||
exit
|
||||
end
|
||||
|
||||
def pid_file
|
||||
prepare_pid_file("#{RAILS_ROOT}/tmp/pids", "mongrel_selenium.pid")
|
||||
end
|
||||
|
||||
def start_command
|
||||
"mongrel_rails start -d --chdir='#{RAILS_ROOT}' --port=#{Webrat.configuration.application_port} --environment=#{Webrat.configuration.application_environment} --pid #{pid_file} &"
|
||||
end
|
||||
|
||||
def stop_command
|
||||
"mongrel_rails stop -c #{RAILS_ROOT} --pid #{pid_file}"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,37 +0,0 @@
|
||||
require "webrat/selenium/application_servers/base"
|
||||
|
||||
module Webrat
|
||||
module Selenium
|
||||
module ApplicationServers
|
||||
class Sinatra < Webrat::Selenium::ApplicationServers::Base
|
||||
|
||||
def start
|
||||
fork do
|
||||
File.open('rack.pid', 'w') { |fp| fp.write Process.pid }
|
||||
exec 'rackup', File.expand_path(Dir.pwd + '/config.ru'), '-p', Webrat.configuration.application_port.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def stop
|
||||
silence_stream(STDOUT) do
|
||||
pid = File.read(pid_file)
|
||||
system("kill -9 #{pid}")
|
||||
FileUtils.rm_f pid_file
|
||||
end
|
||||
end
|
||||
|
||||
def fail
|
||||
$stderr.puts
|
||||
$stderr.puts
|
||||
$stderr.puts "==> Failed to boot the Sinatra application server... exiting!"
|
||||
exit
|
||||
end
|
||||
|
||||
def pid_file
|
||||
prepare_pid_file(Dir.pwd, 'rack.pid')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,19 +1,12 @@
|
||||
if (locator == '*') {
|
||||
return selenium.browserbot.locationStrategies['xpath'].call(this, "//input[@type='submit']", inDocument, inWindow)
|
||||
}
|
||||
var buttons = inDocument.getElementsByTagName('button');
|
||||
var inputs = inDocument.getElementsByTagName('input');
|
||||
var result = $A(inputs).concat($A(buttons)).find(function(candidate){
|
||||
var type = candidate.getAttribute('type');
|
||||
if (type == 'submit' || type == 'image' || type == 'button') {
|
||||
var matches_id = PatternMatcher.matches(locator, candidate.id);
|
||||
var matches_value = PatternMatcher.matches(locator, candidate.value);
|
||||
var matches_html = PatternMatcher.matches(locator, candidate.innerHTML);
|
||||
var matches_alt = PatternMatcher.matches(locator, candidate.alt);
|
||||
if (matches_id || matches_value || matches_html || matches_alt) {
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
});
|
||||
return result;
|
||||
|
@ -1,48 +1,16 @@
|
||||
// Credit to: http://simonwillison.net/2006/Jan/20/escape/
|
||||
RegExp.escape = function(text) {
|
||||
if (!arguments.callee.sRE) {
|
||||
var specials = [
|
||||
'/', '.', '*', '+', '?', '|',
|
||||
'(', ')', '[', ']', '{', '}', '\\'
|
||||
];
|
||||
arguments.callee.sRE = new RegExp(
|
||||
'(\\' + specials.join('|\\') + ')', 'g'
|
||||
);
|
||||
}
|
||||
return text.replace(arguments.callee.sRE, '\\$1');
|
||||
};
|
||||
|
||||
var allLabels = inDocument.getElementsByTagName("label");
|
||||
var regExp = new RegExp('^\\W*' + RegExp.escape(locator) + '(\\b|$)', 'i');
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//reverse length sort
|
||||
candidateLabels = candidateLabels.sortBy(function(s) {
|
||||
return s.length * -1;
|
||||
});
|
||||
|
||||
candidateLabels = candidateLabels.sortBy(function(s) { return s.length * -1; }); //reverse length sort
|
||||
var locatedLabel = candidateLabels.first();
|
||||
var labelFor = null;
|
||||
|
||||
if (locatedLabel.getAttribute('for')) {
|
||||
labelFor = locatedLabel.getAttribute('for');
|
||||
} else if (locatedLabel.attributes['for']) { // IE
|
||||
labelFor = locatedLabel.attributes['for'].nodeValue;
|
||||
}
|
||||
|
||||
var labelFor = locatedLabel.getAttribute('for');
|
||||
if ((labelFor == null) && (locatedLabel.hasChildNodes())) {
|
||||
return locatedLabel.getElementsByTagName('button')[0]
|
||||
|| locatedLabel.getElementsByTagName('input')[0]
|
||||
|| locatedLabel.getElementsByTagName('textarea')[0]
|
||||
|| locatedLabel.getElementsByTagName('select')[0];
|
||||
return locatedLabel.firstChild; //TODO: should find the first form field, not just any node
|
||||
}
|
||||
|
||||
return selenium.browserbot.locationStrategies['id'].call(this, labelFor, inDocument, inWindow);
|
||||
|
@ -1,5 +1,4 @@
|
||||
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)
|
||||
|
@ -1,32 +1,9 @@
|
||||
var links = inDocument.getElementsByTagName('a');
|
||||
|
||||
var candidateLinks = $A(links).select(function(candidateLink) {
|
||||
var textMatched = false;
|
||||
var titleMatched = false;
|
||||
var idMatched = false;
|
||||
|
||||
if (getText(candidateLink).toLowerCase().indexOf(locator.toLowerCase()) != -1) {
|
||||
textMatched = true;
|
||||
}
|
||||
|
||||
if (candidateLink.title.toLowerCase().indexOf(locator.toLowerCase()) != -1) {
|
||||
titleMatched = true;
|
||||
}
|
||||
|
||||
if (candidateLink.id.toLowerCase().indexOf(locator.toLowerCase()) != -1) {
|
||||
idMatched = true;
|
||||
}
|
||||
|
||||
return textMatched || idMatched || titleMatched;
|
||||
return PatternMatcher.matches(locator, getText(candidateLink));
|
||||
});
|
||||
|
||||
if (candidateLinks.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//reverse length sort
|
||||
candidateLinks = candidateLinks.sortBy(function(s) {
|
||||
return s.length * -1;
|
||||
});
|
||||
|
||||
candidateLinks = candidateLinks.sortBy(function(s) { return s.length * -1; }); //reverse length sort
|
||||
return candidateLinks.first();
|
||||
|
@ -1,4 +0,0 @@
|
||||
require "webrat/selenium/matchers/have_xpath"
|
||||
require "webrat/selenium/matchers/have_selector"
|
||||
# require "webrat/selenium/matchers/have_tag"
|
||||
require "webrat/selenium/matchers/have_content"
|
@ -1,78 +0,0 @@
|
||||
module Webrat
|
||||
module Selenium
|
||||
module Matchers
|
||||
class HasContent #:nodoc:
|
||||
def initialize(content)
|
||||
@content = content
|
||||
end
|
||||
|
||||
def matches?(response)
|
||||
response.session.wait_for do
|
||||
response.selenium.is_text_present(text_finder)
|
||||
end
|
||||
rescue Webrat::TimeoutError => e
|
||||
@error_message = e.message
|
||||
false
|
||||
end
|
||||
|
||||
def does_not_match?(response)
|
||||
response.session.wait_for do
|
||||
!response.selenium.is_text_present(text_finder)
|
||||
end
|
||||
rescue Webrat::TimeoutError => e
|
||||
@error_message = e.message
|
||||
false
|
||||
end
|
||||
|
||||
# ==== Returns
|
||||
# String:: The failure message.
|
||||
def failure_message
|
||||
"expected the response to #{content_message}:\n#{@error_message}"
|
||||
end
|
||||
|
||||
# ==== Returns
|
||||
# String:: The failure message to be displayed in negative matches.
|
||||
def negative_failure_message
|
||||
"expected the response to not #{content_message}"
|
||||
end
|
||||
|
||||
def content_message
|
||||
case @content
|
||||
when String
|
||||
"include \"#{@content}\""
|
||||
when Regexp
|
||||
"match #{@content.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
def text_finder
|
||||
if @content.is_a?(Regexp)
|
||||
"regexp:#{@content.source}"
|
||||
else
|
||||
@content
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Matches the contents of an HTML document with
|
||||
# whatever string is supplied
|
||||
def contain(content)
|
||||
HasContent.new(content)
|
||||
end
|
||||
|
||||
# Asserts that the body of the response contain
|
||||
# the supplied string or regexp
|
||||
def assert_contain(content)
|
||||
hc = HasContent.new(content)
|
||||
assert hc.matches?(response), hc.failure_message
|
||||
end
|
||||
|
||||
# Asserts that the body of the response
|
||||
# does not contain the supplied string or regepx
|
||||
def assert_not_contain(content)
|
||||
hc = HasContent.new(content)
|
||||
assert !hc.matches?(response), hc.negative_failure_message
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,57 +0,0 @@
|
||||
module Webrat
|
||||
module Selenium
|
||||
module Matchers
|
||||
class HaveSelector
|
||||
def initialize(expected)
|
||||
@expected = expected
|
||||
end
|
||||
|
||||
def matches?(response)
|
||||
response.session.wait_for do
|
||||
response.selenium.is_element_present("css=#{@expected}")
|
||||
end
|
||||
rescue Webrat::TimeoutError
|
||||
false
|
||||
end
|
||||
|
||||
def does_not_match?(response)
|
||||
response.session.wait_for do
|
||||
!response.selenium.is_element_present("css=#{@expected}")
|
||||
end
|
||||
rescue Webrat::TimeoutError
|
||||
false
|
||||
end
|
||||
|
||||
# ==== 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
|
||||
end
|
||||
|
||||
def have_selector(content)
|
||||
HaveSelector.new(content)
|
||||
end
|
||||
|
||||
# Asserts that the body of the response contains
|
||||
# the supplied selector
|
||||
def assert_have_selector(expected)
|
||||
hs = HaveSelector.new(expected)
|
||||
assert hs.matches?(response), hs.failure_message
|
||||
end
|
||||
|
||||
# Asserts that the body of the response
|
||||
# does not contain the supplied string or regepx
|
||||
def assert_have_no_selector(expected)
|
||||
hs = HaveSelector.new(expected)
|
||||
assert !hs.matches?(response), hs.negative_failure_message
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,72 +0,0 @@
|
||||
module Webrat
|
||||
module Selenium
|
||||
module Matchers
|
||||
|
||||
class HaveTag < 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.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
|
||||
|
||||
# Asserts that the body of the response contains
|
||||
# the supplied tag with the associated selectors
|
||||
def assert_have_tag(name, attributes = {})
|
||||
ht = HaveTag.new([name, attributes])
|
||||
assert ht.matches?(response), ht.failure_message
|
||||
end
|
||||
|
||||
# Asserts that the body of the response
|
||||
# does not contain the supplied string or regepx
|
||||
def assert_have_no_tag(name, attributes = {})
|
||||
ht = HaveTag.new([name, attributes])
|
||||
assert !ht.matches?(response), ht.negative_failure_message
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,53 +0,0 @@
|
||||
module Webrat
|
||||
module Selenium
|
||||
module Matchers
|
||||
class HaveXpath
|
||||
def initialize(expected)
|
||||
@expected = expected
|
||||
end
|
||||
|
||||
def matches?(response)
|
||||
response.session.wait_for do
|
||||
response.selenium.is_element_present("xpath=#{@expected}")
|
||||
end
|
||||
rescue Webrat::TimeoutError
|
||||
false
|
||||
end
|
||||
|
||||
def does_not_match?(response)
|
||||
response.session.wait_for do
|
||||
!response.selenium.is_element_present("xpath=#{@expected}")
|
||||
end
|
||||
rescue Webrat::TimeoutError
|
||||
false
|
||||
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
|
||||
|
||||
def have_xpath(xpath)
|
||||
HaveXpath.new(xpath)
|
||||
end
|
||||
|
||||
def assert_have_xpath(expected)
|
||||
hs = HaveXpath.new(expected)
|
||||
assert hs.matches?(response), hs.failure_message
|
||||
end
|
||||
|
||||
def assert_have_no_xpath(expected)
|
||||
hs = HaveXpath.new(expected)
|
||||
assert !hs.matches?(response), hs.negative_failure_message
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,89 +0,0 @@
|
||||
module Webrat
|
||||
module Selenium
|
||||
|
||||
class SeleniumRCServer
|
||||
|
||||
include Webrat::Selenium::SilenceStream
|
||||
|
||||
def self.boot
|
||||
new.boot
|
||||
end
|
||||
|
||||
def boot
|
||||
return if selenium_grid?
|
||||
|
||||
start
|
||||
wait
|
||||
stop_at_exit
|
||||
end
|
||||
|
||||
def start
|
||||
silence_stream(STDOUT) do
|
||||
remote_control.start :background => true
|
||||
end
|
||||
end
|
||||
|
||||
def stop_at_exit
|
||||
at_exit do
|
||||
stop
|
||||
end
|
||||
end
|
||||
|
||||
def remote_control
|
||||
return @remote_control if @remote_control
|
||||
server_options = { :timeout => Webrat.configuration.selenium_browser_startup_timeout }
|
||||
server_options[:firefox_profile] = Webrat.configuration.selenium_firefox_profile if Webrat.configuration.selenium_firefox_profile
|
||||
|
||||
@remote_control = ::Selenium::RemoteControl::RemoteControl.new("0.0.0.0",
|
||||
Webrat.configuration.selenium_server_port,
|
||||
server_options)
|
||||
|
||||
@remote_control.jar_file = jar_path
|
||||
|
||||
return @remote_control
|
||||
end
|
||||
|
||||
def jar_path
|
||||
File.expand_path(__FILE__ + "../../../../../vendor/selenium-server.jar")
|
||||
end
|
||||
|
||||
def selenium_grid?
|
||||
Webrat.configuration.selenium_server_address
|
||||
end
|
||||
|
||||
def wait
|
||||
$stderr.print "==> Waiting for Selenium RC server on port #{Webrat.configuration.selenium_server_port}... "
|
||||
wait_for_socket
|
||||
$stderr.print "Ready!\n"
|
||||
rescue SocketError
|
||||
fail
|
||||
end
|
||||
|
||||
def wait_for_socket
|
||||
silence_stream(STDOUT) do
|
||||
TCPSocket.wait_for_service_with_timeout \
|
||||
:host => (Webrat.configuration.selenium_server_address || "0.0.0.0"),
|
||||
:port => Webrat.configuration.selenium_server_port,
|
||||
:timeout => 45 # seconds
|
||||
end
|
||||
end
|
||||
|
||||
def fail
|
||||
$stderr.puts
|
||||
$stderr.puts
|
||||
$stderr.puts "==> Failed to boot the Selenium RC server... exiting!"
|
||||
exit
|
||||
end
|
||||
|
||||
def stop
|
||||
silence_stream(STDOUT) do
|
||||
::Selenium::RemoteControl::RemoteControl.new("0.0.0.0",
|
||||
Webrat.configuration.selenium_server_port,
|
||||
:timeout => 5).stop
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,111 +1,85 @@
|
||||
require "webrat/core/save_and_open_page"
|
||||
require "webrat/selenium/selenium_rc_server"
|
||||
require "webrat/selenium/application_server_factory"
|
||||
require "webrat/selenium/application_servers/base"
|
||||
|
||||
begin
|
||||
require "selenium"
|
||||
rescue LoadError => e
|
||||
e.message << " (You may need to install the selenium-rc gem)"
|
||||
raise e
|
||||
end
|
||||
|
||||
module Webrat
|
||||
class TimeoutError < WebratError
|
||||
end
|
||||
|
||||
class SeleniumResponse
|
||||
attr_reader :body
|
||||
attr_reader :session
|
||||
|
||||
def initialize(session, body)
|
||||
@session = session
|
||||
@body = body
|
||||
end
|
||||
|
||||
def selenium
|
||||
session.selenium
|
||||
end
|
||||
end
|
||||
|
||||
class SeleniumSession
|
||||
include Webrat::SaveAndOpenPage
|
||||
include Webrat::Selenium::SilenceStream
|
||||
|
||||
def initialize(*args) # :nodoc:
|
||||
end
|
||||
|
||||
def simulate
|
||||
end
|
||||
|
||||
def automate
|
||||
yield
|
||||
def initialize(selenium_driver) #:nodoc:
|
||||
@selenium = selenium_driver
|
||||
extend_selenium
|
||||
define_location_strategies
|
||||
end
|
||||
|
||||
def visit(url)
|
||||
selenium.open(url)
|
||||
@selenium.open(url)
|
||||
end
|
||||
|
||||
webrat_deprecate :visits, :visit
|
||||
alias_method :visits, :visit
|
||||
|
||||
def fill_in(field_identifier, options)
|
||||
locator = "webrat=#{field_identifier}"
|
||||
selenium.wait_for_element locator, :timeout_in_seconds => 5
|
||||
selenium.type(locator, "#{options[:with]}")
|
||||
locator = "webrat=#{Regexp.escape(field_identifier)}"
|
||||
@selenium.type(locator, "#{options[:with]}")
|
||||
end
|
||||
|
||||
webrat_deprecate :fills_in, :fill_in
|
||||
|
||||
def response
|
||||
SeleniumResponse.new(self, response_body)
|
||||
end
|
||||
alias_method :fills_in, :fill_in
|
||||
|
||||
def response_body #:nodoc:
|
||||
selenium.get_html_source
|
||||
end
|
||||
|
||||
def current_url
|
||||
selenium.location
|
||||
@selenium.get_html_source
|
||||
end
|
||||
|
||||
def click_button(button_text_or_regexp = nil, options = {})
|
||||
if button_text_or_regexp.is_a?(Hash) && options == {}
|
||||
pattern, options = nil, button_text_or_regexp
|
||||
elsif button_text_or_regexp
|
||||
else
|
||||
pattern = adjust_if_regexp(button_text_or_regexp)
|
||||
end
|
||||
pattern ||= '*'
|
||||
locator = "button=#{pattern}"
|
||||
|
||||
selenium.wait_for_element locator, :timeout_in_seconds => 5
|
||||
selenium.click locator
|
||||
@selenium.click("button=#{pattern}")
|
||||
wait_for_result(options[:wait])
|
||||
end
|
||||
|
||||
webrat_deprecate :clicks_button, :click_button
|
||||
alias_method :clicks_button, :click_button
|
||||
|
||||
def click_link(link_text_or_regexp, options = {})
|
||||
if link_text_or_regexp.is_a?(Regexp)
|
||||
pattern = "evalregex:#{link_text_or_regexp.inspect}"
|
||||
else
|
||||
pattern = link_text_or_regexp.to_s
|
||||
pattern = adjust_if_regexp(link_text_or_regexp)
|
||||
@selenium.click("webratlink=#{pattern}")
|
||||
wait_for_result(options[:wait])
|
||||
end
|
||||
|
||||
locator = "webratlink=#{pattern}"
|
||||
selenium.wait_for_element locator, :timeout_in_seconds => 5
|
||||
selenium.click locator
|
||||
end
|
||||
|
||||
webrat_deprecate :clicks_link, :click_link
|
||||
alias_method :clicks_link, :click_link
|
||||
|
||||
def click_link_within(selector, link_text, options = {})
|
||||
locator = "webratlinkwithin=#{selector}|#{link_text}"
|
||||
selenium.wait_for_element locator, :timeout_in_seconds => 5
|
||||
selenium.click locator
|
||||
@selenium.click("webratlinkwithin=#{selector}|#{link_text}")
|
||||
wait_for_result(options[:wait])
|
||||
end
|
||||
|
||||
webrat_deprecate :clicks_link_within, :click_link_within
|
||||
alias_method :clicks_link_within, :click_link_within
|
||||
|
||||
def select(option_text, options = {})
|
||||
def wait_for_result(wait_type)
|
||||
if wait_type == :ajax
|
||||
wait_for_ajax
|
||||
elsif wait_type == :effects
|
||||
wait_for_effects
|
||||
else
|
||||
wait_for_page_to_load
|
||||
end
|
||||
end
|
||||
|
||||
def wait_for_page_to_load(timeout = 15000)
|
||||
@selenium.wait_for_page_to_load(timeout)
|
||||
end
|
||||
|
||||
def wait_for_ajax(timeout = 15000)
|
||||
@selenium.wait_for_condition "Ajax.activeRequestCount == 0", timeout
|
||||
end
|
||||
|
||||
def wait_for_effects(timeout = 15000)
|
||||
@selenium.wait_for_condition "window.Effect.Queue.size() == 0", timeout
|
||||
end
|
||||
|
||||
def wait_for_ajax_and_effects
|
||||
wait_for_ajax
|
||||
wait_for_effects
|
||||
end
|
||||
|
||||
def selects(option_text, options = {})
|
||||
id_or_name_or_label = options[:from]
|
||||
|
||||
if id_or_name_or_label
|
||||
@ -113,159 +87,50 @@ module Webrat
|
||||
else
|
||||
select_locator = "webratselectwithoption=#{option_text}"
|
||||
end
|
||||
|
||||
selenium.wait_for_element select_locator, :timeout_in_seconds => 5
|
||||
selenium.select(select_locator, option_text)
|
||||
@selenium.select(select_locator, option_text)
|
||||
end
|
||||
|
||||
webrat_deprecate :selects, :select
|
||||
|
||||
def choose(label_text)
|
||||
locator = "webrat=#{label_text}"
|
||||
selenium.wait_for_element locator, :timeout_in_seconds => 5
|
||||
selenium.click locator
|
||||
@selenium.click("webrat=#{label_text}")
|
||||
end
|
||||
|
||||
webrat_deprecate :chooses, :choose
|
||||
alias_method :chooses, :choose
|
||||
|
||||
def check(label_text)
|
||||
locator = "webrat=#{label_text}"
|
||||
selenium.wait_for_element locator, :timeout_in_seconds => 5
|
||||
selenium.click locator
|
||||
end
|
||||
alias_method :uncheck, :check
|
||||
|
||||
webrat_deprecate :checks, :check
|
||||
|
||||
def fire_event(field_identifier, event)
|
||||
locator = "webrat=#{Regexp.escape(field_identifier)}"
|
||||
selenium.fire_event(locator, "#{event}")
|
||||
@selenium.check("webrat=#{label_text}")
|
||||
end
|
||||
|
||||
def key_down(field_identifier, key_code)
|
||||
locator = "webrat=#{Regexp.escape(field_identifier)}"
|
||||
selenium.key_down(locator, key_code)
|
||||
alias_method :checks, :check
|
||||
|
||||
def is_ordered(*args) #:nodoc:
|
||||
@selenium.is_ordered(*args)
|
||||
end
|
||||
|
||||
def key_up(field_identifier, key_code)
|
||||
locator = "webrat=#{Regexp.escape(field_identifier)}"
|
||||
selenium.key_up(locator, key_code)
|
||||
end
|
||||
|
||||
def wait_for(params={})
|
||||
timeout = params[:timeout] || 5
|
||||
message = params[:message] || "Timeout exceeded"
|
||||
|
||||
begin_time = Time.now
|
||||
|
||||
while (Time.now - begin_time) < timeout
|
||||
value = nil
|
||||
|
||||
begin
|
||||
value = yield
|
||||
rescue Exception => e
|
||||
unless is_ignorable_wait_for_exception?(e)
|
||||
raise e
|
||||
end
|
||||
end
|
||||
|
||||
return value if value
|
||||
|
||||
sleep 0.25
|
||||
end
|
||||
|
||||
error_message = "#{message} (after #{timeout} sec)"
|
||||
|
||||
if $browser && Webrat.configuration.selenium_verbose_output
|
||||
error_message += <<-EOS
|
||||
|
||||
|
||||
HTML of the page was:
|
||||
|
||||
#{selenium.get_html_source}"
|
||||
EOS
|
||||
end
|
||||
|
||||
raise Webrat::TimeoutError.new(error_message)
|
||||
true
|
||||
end
|
||||
|
||||
def selenium
|
||||
return $browser if $browser
|
||||
setup
|
||||
$browser
|
||||
end
|
||||
|
||||
webrat_deprecate :browser, :selenium
|
||||
|
||||
|
||||
def save_and_open_screengrab
|
||||
return unless File.exist?(Webrat.configuration.saved_pages_dir)
|
||||
|
||||
filename = "#{Webrat.configuration.saved_pages_dir}/webrat-#{Time.now.to_i}.png"
|
||||
|
||||
if $browser.chrome_backend?
|
||||
$browser.capture_entire_page_screenshot(filename, '')
|
||||
else
|
||||
$browser.capture_screenshot(filename)
|
||||
end
|
||||
open_in_browser(filename)
|
||||
|
||||
def dragdrop(*args) #:nodoc:
|
||||
@selenium.dragdrop(*args)
|
||||
end
|
||||
|
||||
protected
|
||||
def is_ignorable_wait_for_exception?(exception) #:nodoc:
|
||||
if defined?(::Spec::Expectations::ExpectationNotMetError)
|
||||
return true if exception.class == ::Spec::Expectations::ExpectationNotMetError
|
||||
end
|
||||
return true if [::Selenium::CommandError, Webrat::WebratError].include?(exception.class)
|
||||
return false
|
||||
end
|
||||
|
||||
def setup #:nodoc:
|
||||
Webrat::Selenium::SeleniumRCServer.boot
|
||||
Webrat::Selenium::ApplicationServerFactory.app_server_instance.boot
|
||||
|
||||
create_browser
|
||||
$browser.start
|
||||
|
||||
extend_selenium
|
||||
define_location_strategies
|
||||
$browser.window_maximize
|
||||
end
|
||||
|
||||
|
||||
def create_browser
|
||||
$browser = ::Selenium::Client::Driver.new(Webrat.configuration.selenium_server_address || "localhost",
|
||||
Webrat.configuration.selenium_server_port, Webrat.configuration.selenium_browser_key, "http://#{Webrat.configuration.application_address}:#{Webrat.configuration.application_port_for_selenium}")
|
||||
$browser.set_speed(0) unless Webrat.configuration.selenium_server_address
|
||||
|
||||
at_exit do
|
||||
silence_stream(STDOUT) do
|
||||
$browser.stop
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def adjust_if_regexp(text_or_regexp) #:nodoc:
|
||||
if text_or_regexp.is_a?(Regexp)
|
||||
"evalregex:#{text_or_regexp.inspect}"
|
||||
else
|
||||
"evalregex:/#{text_or_regexp}/"
|
||||
text_or_regexp
|
||||
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)
|
||||
@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)
|
||||
@selenium.add_location_strategy(strategy_name, strategy_js)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,18 +0,0 @@
|
||||
module Webrat
|
||||
module Selenium
|
||||
module SilenceStream
|
||||
# active_support already defines silence_stream, no need to do that again if it's already present.
|
||||
# http://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/kernel/reporting.rb
|
||||
unless Kernel.respond_to?(:silence_stream)
|
||||
def silence_stream(stream)
|
||||
old_stream = stream.dup
|
||||
stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
|
||||
stream.sync = true
|
||||
yield
|
||||
ensure
|
||||
stream.reopen(old_stream)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
19
lib/webrat/sinatra.rb
Normal file
19
lib/webrat/sinatra.rb
Normal 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
|
23
spec/api/basic_auth_spec.rb
Normal file
23
spec/api/basic_auth_spec.rb
Normal 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
|
136
spec/api/check_spec.rb
Normal file
136
spec/api/check_spec.rb
Normal file
@ -0,0 +1,136 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
||||
|
||||
describe "check" do
|
||||
before do
|
||||
@session = Webrat::TestSession.new
|
||||
end
|
||||
|
||||
it "should fail if no checkbox found" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
</form>
|
||||
EOS
|
||||
|
||||
lambda { @session.check "remember_me" }.should raise_error
|
||||
end
|
||||
|
||||
it "should fail if input is not a checkbox" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="text" name="remember_me" />
|
||||
</form>
|
||||
EOS
|
||||
|
||||
lambda { @session.check "remember_me" }.should raise_error
|
||||
end
|
||||
|
||||
it "should check rails style checkboxes" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_tos" name="user[tos]" type="checkbox" value="1" />
|
||||
<input name="user[tos]" type="hidden" value="0" />
|
||||
<label for="user_tos">TOS</label>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"tos" => "1"})
|
||||
@session.check "TOS"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should result in the value on being posted if not specified" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="checkbox" name="remember_me" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "remember_me" => "on")
|
||||
@session.check "remember_me"
|
||||
@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
|
||||
|
||||
it "should result in a custom value being posted" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="checkbox" name="remember_me" value="yes" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "remember_me" => "yes")
|
||||
@session.check "remember_me"
|
||||
@session.click_button
|
||||
end
|
||||
end
|
||||
|
||||
describe "uncheck" do
|
||||
before do
|
||||
@session = Webrat::TestSession.new
|
||||
end
|
||||
|
||||
it "should fail if no checkbox found" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
</form>
|
||||
EOS
|
||||
|
||||
lambda { @session.uncheck "remember_me" }.should raise_error
|
||||
end
|
||||
|
||||
it "should fail if input is not a checkbox" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="text" name="remember_me" />
|
||||
</form>
|
||||
EOS
|
||||
|
||||
lambda { @session.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
|
||||
|
||||
it "should uncheck rails style checkboxes" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_tos" name="user[tos]" type="checkbox" value="1" checked="checked" />
|
||||
<input name="user[tos]" type="hidden" value="0" />
|
||||
<label for="user_tos">TOS</label>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"tos" => "0"})
|
||||
@session.check "TOS"
|
||||
@session.uncheck "TOS"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should result in value not being posted" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="checkbox" name="remember_me" value="yes" checked="checked" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", {})
|
||||
@session.uncheck "remember_me"
|
||||
@session.click_button
|
||||
end
|
||||
end
|
@ -1,32 +1,31 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
||||
|
||||
describe "choose" do
|
||||
before do
|
||||
@session = Webrat::TestSession.new
|
||||
end
|
||||
|
||||
it "should fail if no radio buttons found" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
lambda { choose "first option" }.should raise_error(Webrat::NotFoundError)
|
||||
lambda { @session.choose "first option" }.should raise_error
|
||||
end
|
||||
|
||||
it "should fail if input is not a radio button" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="text" name="first_option" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
lambda { choose "first_option" }.should raise_error(Webrat::NotFoundError)
|
||||
lambda { @session.choose "first_option" }.should raise_error
|
||||
end
|
||||
|
||||
it "should check rails style radio buttons" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_gender_male" name="user[gender]" type="radio" value="M" />
|
||||
<label for="user_gender_male">Male</label>
|
||||
@ -34,16 +33,14 @@ describe "choose" do
|
||||
<label for="user_gender_female">Female</label>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"gender" => "M"})
|
||||
choose "Male"
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"gender" => "M"})
|
||||
@session.choose "Male"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should only submit last chosen value" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_gender_male" name="user[gender]" type="radio" value="M" />
|
||||
<label for="user_gender_male">Male</label>
|
||||
@ -51,57 +48,49 @@ describe "choose" do
|
||||
<label for="user_gender_female">Female</label>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"gender" => "M"})
|
||||
choose "Female"
|
||||
choose "Male"
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"gender" => "M"})
|
||||
@session.choose "Female"
|
||||
@session.choose "Male"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should fail if the radio button is disabled" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="radio" name="first_option" disabled="disabled" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
lambda { choose "first_option" }.should raise_error(Webrat::DisabledFieldError)
|
||||
lambda { @session.choose "first_option" }.should raise_error
|
||||
end
|
||||
|
||||
it "should result in the value on being posted if not specified" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="radio" name="first_option" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "first_option" => "on")
|
||||
choose "first_option"
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "first_option" => "on")
|
||||
@session.choose "first_option"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should result in the value on being posted if not specified and checked by default" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="radio" name="first_option" checked="checked"/>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "first_option" => "on")
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "first_option" => "on")
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should result in the value of the selected radio button being posted when a subsequent one is checked by default" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input id="user_gender_male" name="user[gender]" type="radio" value="M" />
|
||||
<label for="user_gender_male">Male</label>
|
||||
@ -109,10 +98,9 @@ describe "choose" do
|
||||
<label for="user_gender_female">Female</label>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"gender" => "M"})
|
||||
choose "Male"
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "user" => {"gender" => "M"})
|
||||
@session.choose "Male"
|
||||
@session.click_button
|
||||
end
|
||||
end
|
@ -1,106 +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
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@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>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/page", {})
|
||||
click_area "Berlin"
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page", {})
|
||||
@session.click_area "Berlin"
|
||||
end
|
||||
|
||||
it "should assert valid response" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@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>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.response_code = 501
|
||||
lambda { click_area "Berlin" }.should raise_error(Webrat::PageLoadError)
|
||||
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
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@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>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.stub!(:redirect? => false)
|
||||
webrat_session.response_code = status
|
||||
lambda { click_area "Berlin" }.should_not raise_error
|
||||
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
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@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>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
lambda {
|
||||
click_area "Missing area"
|
||||
}.should raise_error(Webrat::NotFoundError)
|
||||
@session.click_area "Missing area"
|
||||
}.should raise_error
|
||||
end
|
||||
|
||||
it "should not be case sensitive" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@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>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/page", {})
|
||||
click_area "berlin"
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page", {})
|
||||
@session.click_area "berlin"
|
||||
end
|
||||
|
||||
|
||||
it "should follow relative links" do
|
||||
webrat_session.stub!(:current_url => "/page")
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@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>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/page/sub", {})
|
||||
click_area "Berlin"
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page/sub", {})
|
||||
@session.click_area "Berlin"
|
||||
end
|
||||
|
||||
it "should follow fully qualified local links" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@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>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("http://www.example.com/page", {})
|
||||
click_area "Berlin"
|
||||
EOS
|
||||
@session.should_receive(:get).with("http://www.example.com/page", {})
|
||||
@session.click_area "Berlin"
|
||||
end
|
||||
|
||||
it "should follow query parameters" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@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>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/page?foo=bar", {})
|
||||
click_area "Berlin"
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page?foo=bar", {})
|
||||
@session.click_area "Berlin"
|
||||
end
|
||||
end
|
@ -1,244 +1,210 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
||||
|
||||
describe "click_button" do
|
||||
it "should fail if no buttons" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="get" action="/login"></form>
|
||||
</html>
|
||||
HTML
|
||||
before do
|
||||
@session = Webrat::TestSession.new
|
||||
end
|
||||
|
||||
lambda { click_button }.should raise_error(Webrat::NotFoundError)
|
||||
it "should fail if no buttons" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login"></form>
|
||||
EOS
|
||||
|
||||
lambda { @session.click_button }.should raise_error
|
||||
end
|
||||
|
||||
it "should fail if input is not a submit button" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input type="reset" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
lambda { click_button }.should raise_error(Webrat::NotFoundError)
|
||||
lambda { @session.click_button }.should raise_error
|
||||
end
|
||||
|
||||
|
||||
it "should fail if button is disabled" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input type="submit" disabled="disabled" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
lambda { click_button }.should raise_error(Webrat::DisabledFieldError)
|
||||
lambda { @session.click_button }.should raise_error
|
||||
end
|
||||
|
||||
it "should default to get method" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form action="/login">
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get)
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get)
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should assert valid response" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form action="/login">
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.response_code = 501
|
||||
lambda { click_button }.should raise_error(Webrat::PageLoadError)
|
||||
EOS
|
||||
@session.response_code = 501
|
||||
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
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form action="/login">
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.stub!(:redirect? => false)
|
||||
webrat_session.response_code = status
|
||||
lambda { click_button }.should_not raise_error
|
||||
EOS
|
||||
@session.response_code = status
|
||||
lambda { @session.click_button }.should_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
it "should submit the first form by default" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/form1">
|
||||
<input type="submit" />
|
||||
</form>
|
||||
<form method="get" action="/form2">
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/form1", {})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/form1", {})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should not explode on file fields" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/form1">
|
||||
<input type="file" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
click_button
|
||||
EOS
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should submit the form with the specified button" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/form1">
|
||||
<input type="submit" />
|
||||
</form>
|
||||
<form method="get" action="/form2">
|
||||
<input type="submit" value="Form2" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/form2", {})
|
||||
click_button "Form2"
|
||||
EOS
|
||||
@session.should_receive(:get).with("/form2", {})
|
||||
@session.click_button "Form2"
|
||||
end
|
||||
|
||||
it "should use action from form" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", {})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", {})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should use method from form" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post)
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:post)
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send button as param if it has a name" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="submit" name="cancel" value="Cancel" />
|
||||
<input type="submit" name="login" value="Login" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "login" => "Login")
|
||||
click_button("Login")
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "login" => "Login")
|
||||
@session.click_button("Login")
|
||||
end
|
||||
|
||||
it "should not send button as param if it has no name" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="submit" name="cancel" value="Cancel" />
|
||||
<input type="submit" value="Login" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", {})
|
||||
click_button("Login")
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", {})
|
||||
@session.click_button("Login")
|
||||
end
|
||||
|
||||
it "should send default password field values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_password" name="user[password]" value="mypass" type="password" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"password" => "mypass"})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"password" => "mypass"})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send default hidden field values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_email" name="user[email]" value="test@example.com" type="hidden" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"email" => "test@example.com"})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"email" => "test@example.com"})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send default text field values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"email" => "test@example.com"})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"email" => "test@example.com"})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should not send disabled field values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input disabled="disabled" id="user_email" name="user[email]" value="test@example.com" type="text" />
|
||||
<input disabled="disabled" id="user_gender_male" name="user[gender]" type="radio" value="M" />
|
||||
<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="disabled" id="user_gender_female" name="user[gender]" type="radio" value="F" checked="checked" />
|
||||
<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>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", {})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", {})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send default checked fields" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_tos" name="user[tos]" value="1" type="checkbox" checked="checked" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"tos" => "1"})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"tos" => "1"})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send default radio options" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_gender_male" name="user[gender]" type="radio" value="M" />
|
||||
<label for="user_gender_male">Male</label>
|
||||
@ -246,43 +212,37 @@ describe "click_button" do
|
||||
<label for="user_gender_female">Female</label>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"gender" => "F"})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"gender" => "F"})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send correct data for rails style unchecked fields" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_tos" name="user[tos]" type="checkbox" value="1" />
|
||||
<input name="user[tos]" type="hidden" value="0" /> TOS
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"tos" => "0"})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"tos" => "0"})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send correct data for rails style checked fields" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_tos" name="user[tos]" type="checkbox" value="1" checked="checked" />
|
||||
<input name="user[tos]" type="hidden" value="0" /> TOS
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"tos" => "1"})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"tos" => "1"})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send default collection fields" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="checkbox" name="options[]" value="burger" checked="checked" />
|
||||
<input type="radio" name="options[]" value="fries" checked="checked" />
|
||||
@ -296,56 +256,37 @@ describe "click_button" do
|
||||
<input type="hidden" name="response[choices][][selected]" value="two" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login",
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login",
|
||||
"options" => ["burger", "fries", "soda", "soda", "dessert"],
|
||||
"response" => { "choices" => [{"selected" => "one"}, {"selected" => "two"}, {"selected" => "two"}]})
|
||||
click_button
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should not send default unchecked fields" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_tos" name="user[tos]" value="1" type="checkbox" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", {})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", {})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send default textarea values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/posts">
|
||||
<textarea name="post[body]">Post body here!</textarea>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/posts", "post" => {"body" => "Post body here!"})
|
||||
click_button
|
||||
end
|
||||
|
||||
it "should properly handle HTML entities in textarea default values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/posts">
|
||||
<textarea name="post[body]">Peanut butter & jelly</textarea>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/posts", "post" => {"body" => "Peanut butter & jelly"})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:post).with("/posts", "post" => {"body" => "Post body here!"})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send default selected option value from select" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<select name="month">
|
||||
<option value="1">January</option>
|
||||
@ -353,15 +294,13 @@ describe "click_button" do
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "month" => "2")
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "month" => "2")
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send default selected option inner html from select when no value attribute" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<select name="month">
|
||||
<option>January</option>
|
||||
@ -369,15 +308,13 @@ describe "click_button" do
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "month" => "February")
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "month" => "February")
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send first select option value when no option selected" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<select name="month">
|
||||
<option value="1">January</option>
|
||||
@ -385,110 +322,83 @@ describe "click_button" do
|
||||
</select>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "month" => "1")
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "month" => "1")
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should handle nested properties" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input type="text" id="contestant_scores_12" name="contestant[scores][1]" value="2"/>
|
||||
<input type="text" id="contestant_scores_13" name="contestant[scores][3]" value="4"/>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "contestant" => {"scores" => {'1' => '2', '3' => '4'}})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "contestant" => {"scores" => {'1' => '2', '3' => '4'}})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should send default empty text field values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_email" name="user[email]" value="" type="text" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"email" => ""})
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"email" => ""})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should recognize button tags" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_email" name="user[email]" value="" type="text" />
|
||||
<button type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"email" => ""})
|
||||
click_button
|
||||
end
|
||||
|
||||
it "should recognize input tags with the type button" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form action="/">
|
||||
<input type="button" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get)
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"email" => ""})
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should recognize image button tags" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form action="/">
|
||||
<input type="image" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get)
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:get)
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should find buttons by their IDs" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form action="/">
|
||||
<input type="submit" id="my_button" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get)
|
||||
click_button "my_button"
|
||||
EOS
|
||||
@session.should_receive(:get)
|
||||
@session.click_button "my_button"
|
||||
end
|
||||
|
||||
it "should find image buttons by their alt text" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form action="/">
|
||||
<input type="image" alt="Go" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get)
|
||||
click_button "Go"
|
||||
EOS
|
||||
@session.should_receive(:get)
|
||||
@session.click_button "Go"
|
||||
end
|
||||
|
||||
it "should recognize button tags by content" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
<input id="user_email" name="user[email]" value="" type="text" />
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:get).with("/login", "user" => {"email" => ""})
|
||||
click_button "Login"
|
||||
EOS
|
||||
@session.should_receive(:get).with("/login", "user" => {"email" => ""})
|
||||
@session.click_button "Login"
|
||||
end
|
||||
end
|
288
spec/api/click_link_spec.rb
Normal file
288
spec/api/click_link_spec.rb
Normal file
@ -0,0 +1,288 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
||||
|
||||
describe "click_link" do
|
||||
before do
|
||||
@session = Webrat::TestSession.new
|
||||
end
|
||||
|
||||
it "should use get by default" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page">Link text</a>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page", {})
|
||||
@session.click_link "Link text"
|
||||
end
|
||||
|
||||
it "should click get links" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page">Link text</a>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page", {})
|
||||
@session.click_link "Link text", :method => :get
|
||||
end
|
||||
|
||||
it "should click delete links" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page">Link text</a>
|
||||
EOS
|
||||
@session.should_receive(:delete).with("/page", {})
|
||||
@session.click_link "Link text", :method => :delete
|
||||
end
|
||||
|
||||
|
||||
it "should click post links" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page">Link text</a>
|
||||
EOS
|
||||
@session.should_receive(:post).with("/page", {})
|
||||
@session.click_link "Link text", :method => :post
|
||||
end
|
||||
|
||||
it "should click put links" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page">Link text</a>
|
||||
EOS
|
||||
@session.should_receive(:put).with("/page", {})
|
||||
@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
|
||||
|
||||
it "should click rails javascript links with authenticity tokens" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/posts" onclick="var f = document.createElement('form');
|
||||
f.style.display = 'none';
|
||||
this.parentNode.appendChild(f);
|
||||
f.method = 'POST';
|
||||
f.action = this.href;
|
||||
var s = document.createElement('input');
|
||||
s.setAttribute('type', 'hidden');
|
||||
s.setAttribute('name', 'authenticity_token');
|
||||
s.setAttribute('value', 'aa79cb354597a60a3786e7e291ed4f74d77d3a62');
|
||||
f.appendChild(s);
|
||||
f.submit();
|
||||
return false;">Posts</a>
|
||||
EOS
|
||||
@session.should_receive(:post).with("/posts", "authenticity_token" => "aa79cb354597a60a3786e7e291ed4f74d77d3a62")
|
||||
@session.click_link "Posts"
|
||||
end
|
||||
|
||||
it "should click rails javascript delete links" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/posts/1" onclick="var f = document.createElement('form');
|
||||
f.style.display = 'none';
|
||||
this.parentNode.appendChild(f);
|
||||
f.method = 'POST';
|
||||
f.action = this.href;
|
||||
var m = document.createElement('input');
|
||||
m.setAttribute('type', 'hidden');
|
||||
m.setAttribute('name', '_method');
|
||||
m.setAttribute('value', 'delete');
|
||||
f.appendChild(m);
|
||||
f.submit();
|
||||
return false;">Delete</a>
|
||||
EOS
|
||||
@session.should_receive(:delete).with("/posts/1", {})
|
||||
@session.click_link "Delete"
|
||||
end
|
||||
|
||||
it "should click rails javascript post links" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/posts" onclick="var f = document.createElement('form');
|
||||
f.style.display = 'none';
|
||||
this.parentNode.appendChild(f);
|
||||
f.method = 'POST';
|
||||
f.action = this.href;
|
||||
f.submit();
|
||||
return false;">Posts</a>
|
||||
EOS
|
||||
@session.should_receive(:post).with("/posts", {})
|
||||
@session.click_link "Posts"
|
||||
end
|
||||
|
||||
it "should click rails javascript post links without javascript" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/posts" onclick="var f = document.createElement('form');
|
||||
f.style.display = 'none';
|
||||
this.parentNode.appendChild(f);
|
||||
f.method = 'POST';
|
||||
f.action = this.href;
|
||||
f.submit();
|
||||
return false;">Posts</a>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/posts", {})
|
||||
@session.click_link "Posts", :javascript => false
|
||||
end
|
||||
|
||||
it "should click rails javascript put links" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/posts" onclick="var f = document.createElement('form');
|
||||
f.style.display = 'none';
|
||||
this.parentNode.appendChild(f);
|
||||
f.method = 'POST';
|
||||
f.action = this.href;
|
||||
var m = document.createElement('input');
|
||||
m.setAttribute('type', 'hidden');
|
||||
m.setAttribute('name', '_method');
|
||||
m.setAttribute('value', 'put');
|
||||
f.appendChild(m);
|
||||
f.submit();
|
||||
return false;">Put</a></h2>
|
||||
EOS
|
||||
@session.should_receive(:put).with("/posts", {})
|
||||
@session.click_link "Put"
|
||||
end
|
||||
|
||||
it "should fail if the javascript link doesn't have a value for the _method input" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/posts/1" onclick="var f = document.createElement('form');
|
||||
f.style.display = 'none';
|
||||
this.parentNode.appendChild(f);
|
||||
f.method = 'POST';
|
||||
f.action = this.href;
|
||||
var m = document.createElement('input');
|
||||
m.setAttribute('type', 'hidden');
|
||||
m.setAttribute('name', '_method');
|
||||
f.appendChild(m);
|
||||
f.submit();
|
||||
return false;">Link</a>
|
||||
EOS
|
||||
|
||||
lambda {
|
||||
@session.click_link "Link"
|
||||
}.should raise_error
|
||||
end
|
||||
|
||||
it "should assert valid response" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page">Link text</a>
|
||||
EOS
|
||||
@session.response_code = 501
|
||||
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
|
||||
|
||||
it "should fail is the link doesn't exist" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page">Link text</a>
|
||||
EOS
|
||||
|
||||
lambda {
|
||||
@session.click_link "Missing link"
|
||||
}.should raise_error
|
||||
end
|
||||
|
||||
it "should not be case sensitive" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page">Link text</a>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page", {})
|
||||
@session.click_link "LINK TEXT"
|
||||
end
|
||||
|
||||
it "should match link substrings" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page">This is some cool link text, isn't it?</a>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page", {})
|
||||
@session.click_link "Link text"
|
||||
end
|
||||
|
||||
it "should work with elements in the link" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page"><span>Link text</span></a>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page", {})
|
||||
@session.click_link "Link text"
|
||||
end
|
||||
|
||||
it "should match the first matching link" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page1">Link text</a>
|
||||
<a href="/page2">Link text</a>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page1", {})
|
||||
@session.click_link "Link text"
|
||||
end
|
||||
|
||||
it "should choose the shortest link text match" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page1">Linkerama</a>
|
||||
<a href="/page2">Link</a>
|
||||
EOS
|
||||
|
||||
@session.should_receive(:get).with("/page2", {})
|
||||
@session.click_link "Link"
|
||||
end
|
||||
|
||||
it "should treat non-breaking spaces as spaces" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page1">This is a link</a>
|
||||
EOS
|
||||
|
||||
@session.should_receive(:get).with("/page1", {})
|
||||
@session.click_link "This is a link"
|
||||
end
|
||||
|
||||
it "should click link within a selector" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page1">Link</a>
|
||||
<div id="container">
|
||||
<a href="/page2">Link</a>
|
||||
</div>
|
||||
EOS
|
||||
|
||||
@session.should_receive(:get).with("/page2", {})
|
||||
@session.click_link_within "#container", "Link"
|
||||
end
|
||||
|
||||
it "should not make request when link is local anchor" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="#section-1">Jump to Section 1</a>
|
||||
EOS
|
||||
# Don't know why @session.should_receive(:get).never doesn't work here
|
||||
@session.should_receive(:send).with('get_via_redirect', '#section-1', {}).never
|
||||
@session.click_link "Jump to Section 1"
|
||||
end
|
||||
|
||||
it "should follow relative links" do
|
||||
@session.stub!(:current_url).and_return("/page")
|
||||
@session.response_body = <<-EOS
|
||||
<a href="sub">Jump to sub page</a>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page/sub", {})
|
||||
@session.click_link "Jump to sub page"
|
||||
end
|
||||
|
||||
it "should follow fully qualified local links" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="http://www.example.com/page/sub">Jump to sub page</a>
|
||||
EOS
|
||||
@session.should_receive(:get).with("http://www.example.com/page/sub", {})
|
||||
@session.click_link "Jump to sub page"
|
||||
end
|
||||
|
||||
it "should follow query parameters" do
|
||||
@session.stub!(:current_url).and_return("/page")
|
||||
@session.response_body = <<-EOS
|
||||
<a href="?foo=bar">Jump to foo bar</a>
|
||||
EOS
|
||||
@session.should_receive(:get).with("/page?foo=bar", {})
|
||||
@session.click_link "Jump to foo bar"
|
||||
end
|
||||
end
|
@ -1,35 +1,37 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
||||
|
||||
|
||||
describe "field_labeled" do
|
||||
|
||||
class << self
|
||||
def using_this_html html
|
||||
before(:each) do
|
||||
with_html(html)
|
||||
@session = Webrat::TestSession.new
|
||||
@session.response_body = html
|
||||
end
|
||||
end
|
||||
|
||||
def field_labeled(label)
|
||||
def field_labeled label
|
||||
@label = label
|
||||
yield
|
||||
end
|
||||
|
||||
def should_return_a type, opts
|
||||
it "should return a textfield" do
|
||||
field_labeled(opts[:for]).should be_an_instance_of(type)
|
||||
@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
|
||||
field_labeled(opts[:for]).should match_id(id)
|
||||
@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 {
|
||||
field_labeled(opts[:for])
|
||||
@session.field_labeled(opts[:for])
|
||||
}.should raise_error(regexp)
|
||||
end
|
||||
end
|
||||
@ -37,22 +39,16 @@ describe "field_labeled" do
|
||||
|
||||
def match_id(id)
|
||||
simple_matcher "element with id #{id.inspect}" do |element, matcher|
|
||||
if id.is_a?(Regexp)
|
||||
element.id =~ id
|
||||
else
|
||||
element.id == id.to_s
|
||||
end
|
||||
element.matches_id? id
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding a text field" do
|
||||
using_this_html <<-HTML
|
||||
<html>
|
||||
<form>
|
||||
<label for="element_42">The Label</label>
|
||||
<input type="text" id="element_42">
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
should_return_a Webrat::TextField, :for => "The Label"
|
||||
@ -62,12 +58,10 @@ describe "field_labeled" do
|
||||
|
||||
describe "finding a hidden field" do
|
||||
using_this_html <<-HTML
|
||||
<html>
|
||||
<form>
|
||||
<label for="element_42">The Label</label>
|
||||
<input type="hidden" id="element_42">
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
should_return_a Webrat::HiddenField, :for => "The Label"
|
||||
@ -77,12 +71,10 @@ describe "field_labeled" do
|
||||
|
||||
describe "finding a checkbox" do
|
||||
using_this_html <<-HTML
|
||||
<html>
|
||||
<form>
|
||||
<label for="element_42">The Label</label>
|
||||
<input type="checkbox" id="element_42">
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
should_return_a Webrat::CheckboxField, :for => "The Label"
|
||||
@ -92,12 +84,10 @@ describe "field_labeled" do
|
||||
|
||||
describe "finding a radio button" do
|
||||
using_this_html <<-HTML
|
||||
<html>
|
||||
<form>
|
||||
<label for="element_42">The Label</label>
|
||||
<input type="radio" id="element_42">
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
should_return_a Webrat::RadioField, :for => "The Label"
|
||||
@ -108,65 +98,14 @@ describe "field_labeled" do
|
||||
|
||||
describe "finding a text area" do
|
||||
using_this_html <<-HTML
|
||||
<html>
|
||||
<form>
|
||||
<label for="element_42">The Label</label>
|
||||
<textarea id="element_42"></textarea>
|
||||
</form>
|
||||
</html>
|
||||
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
|
||||
|
||||
describe "finding a field with it's label containing newlines" do
|
||||
using_this_html <<-HTML
|
||||
<html>
|
||||
<form>
|
||||
<label for="element_42">
|
||||
A label with
|
||||
<a>a link on it's own line</a>
|
||||
</label>
|
||||
<input type="text" id="element_42">
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
should_return_a Webrat::TextField, :for => "A label with a link on it's own line"
|
||||
with_an_id_of "element_42", :for => "A label with a link on it's own line"
|
||||
should_raise_error_matching /Could not find .* "Other Label"/, :for => "Other Label"
|
||||
end
|
||||
|
||||
describe "finding a field when labels without fields also match" do
|
||||
using_this_html <<-HTML
|
||||
<html>
|
||||
<label>The Label</label>
|
||||
<form>
|
||||
<label for="element_42">The Label</label>
|
||||
<input type="text" id="element_42">
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
should_return_a Webrat::TextField, :for => "The Label"
|
||||
with_an_id_of "element_42", :for => "The Label"
|
||||
end
|
||||
|
||||
describe "finding a field whose label ends with an non word character" do
|
||||
using_this_html <<-HTML
|
||||
<html>
|
||||
<form>
|
||||
<label for="element_42">License #</label>
|
||||
<input type="text" id="element_42">
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
should_return_a Webrat::TextField, :for => "License #"
|
||||
with_an_id_of "element_42", :for => "License #"
|
||||
should_raise_error_matching /Could not find .* "Other License #"/, :for => "Other License #"
|
||||
end
|
||||
|
||||
end
|
@ -1,93 +1,71 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
||||
|
||||
describe "fill_in" do
|
||||
it "should work with textareas" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
<form method="post" action="/login">
|
||||
<label for="user_text">User Text</label>
|
||||
<textarea id="user_text" name="user[text]"></textarea>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"text" => "filling text area"})
|
||||
fill_in "User Text", :with => "filling text area"
|
||||
click_button
|
||||
before do
|
||||
@session = Webrat::TestSession.new
|
||||
end
|
||||
|
||||
it "should support multiline values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
it "should work with textareas" do
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<label for="user_text">User Text</label>
|
||||
<textarea id="user_text" name="user[text]"></textarea>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"text" => "One\nTwo"})
|
||||
fill_in "User Text", :with => "One\nTwo"
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "user" => {"text" => "filling text area"})
|
||||
@session.fill_in "User Text", :with => "filling text area"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should work with password fields" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input id="user_text" name="user[text]" type="password" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"text" => "pass"})
|
||||
fill_in "user_text", :with => "pass"
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "user" => {"text" => "pass"})
|
||||
@session.fill_in "user_text", :with => "pass"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should fail if input not found" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="get" action="/login">
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
lambda { fill_in "Email", :with => "foo@example.com" }.should raise_error(Webrat::NotFoundError)
|
||||
lambda { @session.fill_in "Email", :with => "foo@example.com" }.should raise_error
|
||||
end
|
||||
|
||||
it "should fail if input is disabled" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@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>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
lambda { fill_in "Email", :with => "foo@example.com" }.should raise_error(Webrat::DisabledFieldError)
|
||||
lambda { @session.fill_in "Email", :with => "foo@example.com" }.should raise_error
|
||||
end
|
||||
|
||||
it "should allow overriding default form values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<label for="user_email">Email</label>
|
||||
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
|
||||
fill_in "user[email]", :with => "foo@example.com"
|
||||
click_button
|
||||
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
|
||||
|
||||
it "should choose the shortest label match" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<label for="user_mail1">Some other mail</label>
|
||||
<input id="user_mail1" name="user[mail1]" type="text" />
|
||||
@ -95,17 +73,15 @@ describe "fill_in" do
|
||||
<input id="user_mail2" name="user[mail2]" type="text" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"mail1" => "", "mail2" => "value"})
|
||||
fill_in "Some", :with => "value"
|
||||
click_button
|
||||
@session.should_receive(:post).with("/login", "user" => {"mail1" => "", "mail2" => "value"})
|
||||
@session.fill_in "Some", :with => "value"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should choose the first label match if closest is a tie" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<label for="user_mail1">Some mail one</label>
|
||||
<input id="user_mail1" name="user[mail1]" type="text" />
|
||||
@ -113,43 +89,37 @@ describe "fill_in" do
|
||||
<input id="user_mail2" name="user[mail2]" type="text" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"mail1" => "value", "mail2" => ""})
|
||||
fill_in "Some mail", :with => "value"
|
||||
click_button
|
||||
@session.should_receive(:post).with("/login", "user" => {"mail1" => "value", "mail2" => ""})
|
||||
@session.fill_in "Some mail", :with => "value"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should anchor label matches to start of label" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<label for="user_email">Some mail</label>
|
||||
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
lambda { fill_in "mail", :with => "value" }.should raise_error(Webrat::NotFoundError)
|
||||
lambda { @session.fill_in "mail", :with => "value" }.should raise_error
|
||||
end
|
||||
|
||||
it "should anchor label matches to word boundaries" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<label for="user_email">Emailtastic</label>
|
||||
<input id="user_email" name="user[email]" value="test@example.com" type="text" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
EOS
|
||||
|
||||
lambda { fill_in "Email", :with => "value" }.should raise_error(Webrat::NotFoundError)
|
||||
lambda { @session.fill_in "Email", :with => "value" }.should raise_error
|
||||
end
|
||||
|
||||
it "should work with inputs nested in labels" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<label>
|
||||
Email
|
||||
@ -157,68 +127,59 @@ describe "fill_in" do
|
||||
</label>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
|
||||
fill_in "Email", :with => "foo@example.com"
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
|
||||
@session.fill_in "Email", :with => "foo@example.com"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should work with full input names" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input id="user_email" name="user[email]" type="text" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
|
||||
fill_in "user[email]", :with => "foo@example.com"
|
||||
click_button
|
||||
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
|
||||
|
||||
it "should work if the input type is not set" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<input id="user_email" name="user[email]" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
|
||||
fill_in "user[email]", :with => "foo@example.com"
|
||||
click_button
|
||||
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
|
||||
|
||||
it "should work with symbols" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@session.response_body = <<-EOS
|
||||
<form method="post" action="/login">
|
||||
<label for="user_email">Email</label>
|
||||
<input id="user_email" name="user[email]" type="text" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
|
||||
fill_in :email, :with => "foo@example.com"
|
||||
click_button
|
||||
EOS
|
||||
@session.should_receive(:post).with("/login", "user" => {"email" => "foo@example.com"})
|
||||
@session.fill_in :email, :with => "foo@example.com"
|
||||
@session.click_button
|
||||
end
|
||||
|
||||
it "should escape field values" do
|
||||
with_html <<-HTML
|
||||
<html>
|
||||
@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>
|
||||
</html>
|
||||
HTML
|
||||
webrat_session.should_receive(:post).with("/users", "user" => {"phone" => "+1 22 33"})
|
||||
fill_in 'Phone', :with => "+1 22 33"
|
||||
click_button
|
||||
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
|
178
spec/api/matchers_spec.rb
Normal file
178
spec/api/matchers_spec.rb
Normal 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
|
15
spec/api/reload_spec.rb
Normal file
15
spec/api/reload_spec.rb
Normal file
@ -0,0 +1,15 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
||||
|
||||
describe "reloads" do
|
||||
before do
|
||||
@session = Webrat::TestSession.new
|
||||
@session.response_body = "Hello world"
|
||||
end
|
||||
|
||||
it "should reload the page with http referer" do
|
||||
@session.should_receive(:get).with("/", {})
|
||||
@session.should_receive(:get).with("/", {}, {"HTTP_REFERER"=>"/"})
|
||||
@session.visit("/")
|
||||
@session.reloads
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user