[DRE-commits] [ruby-capybara] 01/06: Imported Upstream version 2.2.1

Jérémy Bobbio lunar at moszumanska.debian.org
Sun May 4 11:59:17 UTC 2014


This is an automated email from the git hooks/post-receive script.

lunar pushed a commit to annotated tag debian/2.2.1-1
in repository ruby-capybara.

commit d2492711da0da6c80d99299fb7548e14760245ae
Author: Jérémy Bobbio <lunar at debian.org>
Date:   Sun May 4 13:18:53 2014 +0200

    Imported Upstream version 2.2.1
---
 History.md                                      |  49 +++++++-
 README.md                                       |  40 +++---
 checksums.yaml.gz                               | Bin 0 -> 268 bytes
 checksums.yaml.gz.sig                           | Bin 0 -> 256 bytes
 data.tar.gz.sig                                 | Bin 256 -> 256 bytes
 lib/capybara.rb                                 |  29 ++++-
 lib/capybara/cucumber.rb                        |   2 -
 lib/capybara/driver/base.rb                     |  10 +-
 lib/capybara/node/actions.rb                    |   2 +-
 lib/capybara/node/finders.rb                    |   6 +-
 lib/capybara/node/matchers.rb                   |  40 +++---
 lib/capybara/node/simple.rb                     |   8 +-
 lib/capybara/query.rb                           |   1 +
 lib/capybara/rack_test/browser.rb               |   9 +-
 lib/capybara/rack_test/form.rb                  |   7 +-
 lib/capybara/rack_test/node.rb                  |   3 +-
 lib/capybara/result.rb                          |   3 +-
 lib/capybara/rspec.rb                           |   7 ++
 lib/capybara/rspec/features.rb                  |   2 +
 lib/capybara/rspec/matchers.rb                  |  12 +-
 lib/capybara/selector.rb                        |   4 +-
 lib/capybara/selenium/driver.rb                 |  14 ++-
 lib/capybara/selenium/node.rb                   |  23 +++-
 lib/capybara/server.rb                          |  10 +-
 lib/capybara/session.rb                         |  76 +++++++++---
 lib/capybara/spec/public/test.js                |   2 +-
 lib/capybara/spec/session/assert_selector.rb    |  18 +++
 lib/capybara/spec/session/attach_file_spec.rb   |   7 +-
 lib/capybara/spec/session/check_spec.rb         |  14 +++
 lib/capybara/spec/session/choose_spec.rb        |  14 +++
 lib/capybara/spec/session/click_button_spec.rb  |  21 +++-
 lib/capybara/spec/session/fill_in_spec.rb       |  20 ++-
 lib/capybara/spec/session/go_back_spec.rb       |  10 ++
 lib/capybara/spec/session/go_forward_spec.rb    |  12 ++
 lib/capybara/spec/session/has_button_spec.rb    |  24 ++++
 lib/capybara/spec/session/has_field_spec.rb     |  48 ++++++++
 lib/capybara/spec/session/has_text_spec.rb      |  18 +++
 lib/capybara/spec/session/node_spec.rb          |  37 +++++-
 lib/capybara/spec/session/reset_session_spec.rb |  10 +-
 lib/capybara/spec/session/save_page_spec.rb     |  14 ++-
 lib/capybara/spec/session/visit_spec.rb         |  16 +++
 lib/capybara/spec/session/within_frame_spec.rb  |   7 ++
 lib/capybara/spec/session/within_window_spec.rb |   7 ++
 lib/capybara/spec/test_app.rb                   |   1 +
 lib/capybara/spec/views/form.erb                |  40 ++++++
 lib/capybara/spec/views/with_html.erb           |   5 +
 lib/capybara/spec/views/with_js.erb             |   8 ++
 lib/capybara/version.rb                         |   2 +-
 metadata.gz.sig                                 | Bin 256 -> 256 bytes
 metadata.yml                                    | 155 +++++++++---------------
 spec/capybara_spec.rb                           |   2 +-
 spec/result_spec.rb                             |  14 +++
 spec/rspec/features_spec.rb                     |  15 +++
 spec/rspec/matchers_spec.rb                     |  25 +++-
 spec/selenium_spec.rb                           |  11 +-
 spec/selenium_spec_chrome.rb                    |  21 ++++
 spec/server_spec.rb                             |  18 ++-
 57 files changed, 758 insertions(+), 215 deletions(-)

diff --git a/History.md b/History.md
index 8ee6b61..fbe9815 100644
--- a/History.md
+++ b/History.md
@@ -1,6 +1,53 @@
+# Version 2.2.0
+
+Release date: 2013-11-21
+
+### Added
+
+* Add `go_back` and `go_forward` methods. [Vasiliy Ermolovich]
+* Support RSpec 3 [Thomas Holmes]
+* `has_button?`, `has_checked_field?` and `has_unchecked_field?` accept
+  options, like other matchers. [Carol Nichols]
+* The `assert_selector` and `has_text?` methods now support the `:wait` option
+  [Vasiliy Ermolovich]
+* RackTest's visible? method now checks for the HTML5 `hidden` attribute.
+* Results from `#all` now delegate the `sample` method. [Phil Lee]
+* The `set` method now works for contenteditable attributes under Selenium.
+  [Jon Rowe]
+* radio buttons and check boxes can be filtered by option value, useful when
+  selecting by name [Jonas Nicklas]
+* feature blocks can be nested within other feature blocks in RSpec tests
+  [Travis Gaff]
+
+### Fixed
+
+* Fixed race conditions causing stale element errors when filtering by text.
+  [Jonas Nicklas]
+* Resetting the page is now synchronous and navigates to an empty HTML file,
+  instead of `about:blank`, fixing hanging issues in JRuby. [Jonas Nicklas]
+* Fixed cookies not being set when path is blank under RackTest [Thomas Walpole]
+* Clearing fields now correctly causes change events [Jonas Nicklas]
+* Navigating to an absolut URI without trailing slash now works as expected
+  under RackTest [Jonas Nicklas]
+* Checkboxes without assigned value default to `on` under RackTest [Nigel Sheridan-Smith]
+* Clicks on buttons with no form associated with them are ignored in RackTest
+  instead of raising an obscure exception. [Thomas Walpole]
+* execute_script is now a session method [Andrey Botalov]
+* Nesting `within_window` and `within_frame` inside `within` resets the scope
+  so that they behave like a user would expect [Thomas Walpole]
+* Improve handling of newlines in textareas [Thomas Walpole]
+* `Capybara::Result` delegates its inspect method, so as not to confuse users
+  [Sam Rawlins]
+* save_page always returns a full path, fixes problems with Launchy [Jonas Nicklas]
+* Selenium driver's `quit` method does nothing when browser hasn't been loaded
+  [randoum]
+* Capybara's WEBRick server now propertly respects the server_host option
+  [Dmitry Vorotilin]
+* gemspec now includes license information [Jonas Nicklas]
+
 # Version 2.1.0
 
-Release date: Unreleased
+Release date: 2013-04-09
 
 ### Changed
 
diff --git a/README.md b/README.md
index 0474122..e7485ce 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 [![Build Status](https://secure.travis-ci.org/jnicklas/capybara.png)](http://travis-ci.org/jnicklas/capybara)
 [![Dependency Status](https://gemnasium.com/jnicklas/capybara.png)](https://gemnasium.com/jnicklas/capybara)
-[![Code Quality](https://codeclimate.com/badge.png)](https://codeclimate.com/github/jnicklas/capybara)
+[![Code Climate](https://codeclimate.com/github/jnicklas/capybara.png)](https://codeclimate.com/github/jnicklas/capybara)
 
 Capybara helps you test web applications by simulating how a real user would
 interact with your app. It is agnostic about the driver running your tests and
@@ -96,7 +96,7 @@ Capybara with `:type => :feature`.
 You can now write your specs like so:
 
 ```ruby
-describe "the signup process", :type => :feature do
+describe "the signin process", :type => :feature do
   before :each do
     User.make(:email => 'user at example.com', :password => 'caplin')
   end
@@ -108,7 +108,7 @@ describe "the signup process", :type => :feature do
       fill_in 'Password', :with => 'password'
     end
     click_link 'Sign in'
-    page.should have_content 'Success'
+    expect(page).to have_content 'Success'
   end
 end
 ```
@@ -127,7 +127,7 @@ end
 Finally, Capybara also comes with a built in DSL for creating descriptive acceptance tests:
 
 ```ruby
-feature "Signing up" do
+feature "Signing in" do
   background do
     User.make(:email => 'user at example.com', :password => 'caplin')
   end
@@ -139,7 +139,7 @@ feature "Signing up" do
       fill_in 'Password', :with => 'caplin'
     end
     click_link 'Sign in'
-    page.should have_content 'Success'
+    expect(page).to have_content 'Success'
   end
 
   given(:other_user) { User.make(:email => 'other at example.com', :password => 'rous') }
@@ -151,7 +151,7 @@ feature "Signing up" do
       fill_in 'Password', :with => other_user.password
     end
     click_link 'Sign in'
-    page.should have_content 'Invalid email or password'
+    expect(page).to have_content 'Invalid email or password'
   end
 end
 ```
@@ -162,7 +162,7 @@ end
 
 ## Using Capybara with Test::Unit
 
-* If you are using Rails, add the following code in your `test_helper.rb` 
+* If you are using Rails, add the following code in your `test_helper.rb`
     file to make Capybara available in all test cases deriving from
     `ActionDispatch::IntegrationTest`:
 
@@ -209,7 +209,7 @@ end
 Set up your base class as with Test::Unit. (On Rails, the right base class
 could be something other than ActionDispatch::IntegrationTest.)
 
-The capybara_minitest_spec gem ([Github](https://github.com/ordinaryzelig/capybara_minitest_spec),
+The capybara_minitest_spec gem ([GitHub](https://github.com/ordinaryzelig/capybara_minitest_spec),
 [rubygems.org](https://rubygems.org/gems/capybara_minitest_spec)) provides MiniTest::Spec
 expectations for Capybara. For example:
 
@@ -271,7 +271,7 @@ RackTest can be configured with a set of headers like this:
 
 ```ruby
 Capybara.register_driver :rack_test do |app|
-  Capybara::RackTest::Driver.new(app, :browser => :chrome)
+  Capybara::RackTest::Driver.new(app, :headers => { 'HTTP_USER_AGENT' => 'Capybara' })
 end
 ```
 
@@ -281,10 +281,12 @@ See the section on adding and configuring drivers.
 
 At the moment, Capybara supports [Selenium 2.0
 (Webdriver)](http://seleniumhq.org/docs/01_introducing_selenium.html#selenium-2-aka-selenium-webdriver),
-*not* Selenium RC. Provided Firefox is installed, everything is set up for you,
-and you should be able to start using Selenium right away.
+*not* Selenium RC. In order to use Selenium, you'll need to install the
+`selenium-webdriver` gem, and add it to your Gemfile if you're using bundler.
+Provided Firefox is installed, everything is set up for you, and you should be
+able to start using Selenium right away.
 
-**Note**: drivers which run the server in a different thread may not work share the
+**Note**: drivers which run the server in a different thread may not share the
 same transaction as your tests, causing data not to be shared between your test
 and test server, see "Transactions and database setup" below.
 
@@ -325,7 +327,7 @@ Capybara heavily uses XPath, which doesn't support case insensitivity.
 ### Navigating
 
 You can use the
-[#visit](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#visit-instance_method)
+<tt>[visit](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#visit-instance_method)</tt>
 method to navigate to other pages:
 
 ```ruby
@@ -450,8 +452,6 @@ within(:xpath, "//li[@id='employee']") do
 end
 ```
 
-**Note**: `within` will scope the actions to the _first_ (not _any_) element that matches the selector.
-
 There are special methods for restricting the scope to a specific fieldset,
 identified by either an id or the text of the fieldset's legend tag, and to a
 specific table, identified by either id or text of the table's caption tag.
@@ -794,7 +794,7 @@ end
 
 Capybara makes it convenient to switch between different drivers. It also exposes
 an API to tweak those drivers with whatever settings you want, or to add your own
-drivers. This is how to switch the selenium driver to use chrome:
+drivers. This is how to override the selenium driver configuration to use chrome:
 
 ```ruby
 Capybara.register_driver :selenium do |app|
@@ -802,8 +802,7 @@ Capybara.register_driver :selenium do |app|
 end
 ```
 
-However, it's also possible to give this a different name, so tests can switch
-between using different browsers effortlessly:
+However, it's also possible to give this configuration a different name.
 
 ```ruby
 Capybara.register_driver :selenium_chrome do |app|
@@ -811,6 +810,11 @@ Capybara.register_driver :selenium_chrome do |app|
 end
 ```
 
+Then tests can switch between using different browsers effortlessly:
+```ruby
+Capybara.current_driver = :selenium_chrome
+```
+
 Whatever is returned from the block should conform to the API described by
 Capybara::Driver::Base, it does not however have to inherit from this class.
 Gems can use this API to add their own drivers to Capybara.
diff --git a/checksums.yaml.gz b/checksums.yaml.gz
new file mode 100644
index 0000000..b8fd3c6
Binary files /dev/null and b/checksums.yaml.gz differ
diff --git a/checksums.yaml.gz.sig b/checksums.yaml.gz.sig
new file mode 100644
index 0000000..61201be
Binary files /dev/null and b/checksums.yaml.gz.sig differ
diff --git a/data.tar.gz.sig b/data.tar.gz.sig
index e6c7bc3..979d6ce 100644
Binary files a/data.tar.gz.sig and b/data.tar.gz.sig differ
diff --git a/lib/capybara.rb b/lib/capybara.rb
index 5ec55ce..efa2545 100644
--- a/lib/capybara.rb
+++ b/lib/capybara.rb
@@ -16,10 +16,10 @@ module Capybara
 
   class << self
     attr_accessor :asset_host, :app_host, :run_server, :default_host, :always_include_port
-    attr_accessor :server_host, :server_port, :exact, :match, :exact_options, :visible_text_only
+    attr_accessor :server_port, :exact, :match, :exact_options, :visible_text_only
     attr_accessor :default_selector, :default_wait_time, :ignore_hidden_elements
     attr_accessor :save_and_open_page_path, :automatic_reload, :raise_server_errors
-    attr_writer :default_driver, :current_driver, :javascript_driver, :session_name
+    attr_writer :default_driver, :current_driver, :javascript_driver, :session_name, :server_host
     attr_accessor :app
 
     ##
@@ -166,7 +166,7 @@ module Capybara
     #
     def run_default_server(app, port)
       require 'rack/handler/webrick'
-      Rack::Handler::WEBrick.run(app, :Port => port, :AccessLog => [], :Logger => WEBrick::Log::new(nil, 0))
+      Rack::Handler::WEBrick.run(app, :Host => server_host, :Port => port, :AccessLog => [], :Logger => WEBrick::Log::new(nil, 0))
     end
 
     ##
@@ -216,6 +216,14 @@ module Capybara
 
     ##
     #
+    # @return [String]    The IP address bound by default server
+    #
+    def server_host
+      @server_host || '127.0.0.1'
+    end
+
+    ##
+    #
     # Yield a block using a specific wait time
     #
     def using_wait_time(seconds)
@@ -267,6 +275,21 @@ module Capybara
       self.session_name = :default
     end
 
+    ##
+    #
+    # Parse raw html into a document using Nokogiri, and adjust textarea contents as defined by the spec.
+    #
+    # @param [String] html              The raw html
+    # @return [Nokogiri::HTML::Document]      HTML document
+    #
+    def HTML(html)
+      Nokogiri::HTML(html).tap do |document|
+        document.xpath('//textarea').each do |textarea|
+          textarea.content=textarea.content.sub(/\A\n/,'')
+        end
+      end
+    end
+
     def included(base)
       base.send(:include, Capybara::DSL)
       warn "`include Capybara` is deprecated. Please use `include Capybara::DSL` instead."
diff --git a/lib/capybara/cucumber.rb b/lib/capybara/cucumber.rb
index c8c470d..7923d26 100644
--- a/lib/capybara/cucumber.rb
+++ b/lib/capybara/cucumber.rb
@@ -1,6 +1,4 @@
 require 'capybara'
-
-require 'capybara/dsl'
 require 'capybara/rspec/matchers'
 
 World(Capybara::DSL)
diff --git a/lib/capybara/driver/base.rb b/lib/capybara/driver/base.rb
index 414fc44..9fd20d0 100644
--- a/lib/capybara/driver/base.rb
+++ b/lib/capybara/driver/base.rb
@@ -10,7 +10,7 @@ class Capybara::Driver::Base
   def find_xpath(query)
     raise NotImplementedError
   end
-  
+
   def find_css(query)
     raise NotImplementedError
   end
@@ -19,6 +19,14 @@ class Capybara::Driver::Base
     raise NotImplementedError
   end
 
+  def go_back
+    raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#go_back'
+  end
+
+  def go_forward
+    raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#go_forward'
+  end
+
   def execute_script(script)
     raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#execute_script'
   end
diff --git a/lib/capybara/node/actions.rb b/lib/capybara/node/actions.rb
index 00a0bde..b29d3b2 100644
--- a/lib/capybara/node/actions.rb
+++ b/lib/capybara/node/actions.rb
@@ -19,7 +19,7 @@ module Capybara
       # Finds a link by id or text and clicks it. Also looks at image
       # alt text inside the link.
       #
-      # @param [String] locator      Text, id or text of link
+      # @param [String] locator      Text or id of link
       # @param options
       # @option options [String] :href    The value the href attribute must be
       #
diff --git a/lib/capybara/node/finders.rb b/lib/capybara/node/finders.rb
index 7eb22e7..a47b3e2 100644
--- a/lib/capybara/node/finders.rb
+++ b/lib/capybara/node/finders.rb
@@ -147,16 +147,16 @@ module Capybara
     private
 
       def resolve_query(query, exact=nil)
-        elements = synchronize do
-          if query.selector.format==:css
+        synchronize do
+          elements = if query.selector.format==:css
             base.find_css(query.css)
           else
             base.find_xpath(query.xpath(exact))
           end.map do |node|
             Capybara::Node::Element.new(session, node, self, query)
           end
+          Capybara::Result.new(elements, query)
         end
-        Capybara::Result.new(elements, query)
       end
     end
   end
diff --git a/lib/capybara/node/matchers.rb b/lib/capybara/node/matchers.rb
index 3a6c312..4975a2a 100644
--- a/lib/capybara/node/matchers.rb
+++ b/lib/capybara/node/matchers.rb
@@ -85,7 +85,8 @@ module Capybara
       # @raise [Capybara::ExpectationNotMet]      If the selector does not exist
       #
       def assert_selector(*args)
-        synchronize do
+        query = Capybara::Query.new(*args)
+        synchronize(query.wait) do
           result = all(*args)
           result.matches_count? or raise Capybara::ExpectationNotMet, result.failure_message
         end
@@ -101,7 +102,8 @@ module Capybara
       # @raise [Capybara::ExpectationNotMet]      If the selector exists
       #
       def assert_no_selector(*args)
-        synchronize do
+        query = Capybara::Query.new(*args)
+        synchronize(query.wait) do
           result = all(*args)
           result.matches_count? and raise Capybara::ExpectationNotMet, result.negative_failure_message
         end
@@ -215,7 +217,8 @@ module Capybara
       #   @return [Boolean]                          Whether it exists
       #
       def has_text?(*args)
-        synchronize do
+        query = Capybara::Query.new(*args)
+        synchronize(query.wait) do
           raise ExpectationNotMet unless text_found?(*args)
         end
         return true
@@ -233,7 +236,8 @@ module Capybara
       # @return [Boolean]  Whether it doesn't exist
       #
       def has_no_text?(*args)
-        synchronize do
+        query = Capybara::Query.new(*args)
+        synchronize(query.wait) do
           raise ExpectationNotMet if text_found?(*args)
         end
         return true
@@ -276,8 +280,8 @@ module Capybara
       # @param [String] locator      The text, value or id of a button to check for
       # @return [Boolean]            Whether it exists
       #
-      def has_button?(locator)
-        has_selector?(:button, locator)
+      def has_button?(locator, options={})
+        has_selector?(:button, locator, options)
       end
 
       ##
@@ -288,8 +292,8 @@ module Capybara
       # @param [String] locator      The text, value or id of a button to check for
       # @return [Boolean]            Whether it doesn't exist
       #
-      def has_no_button?(locator)
-        has_no_selector?(:button, locator)
+      def has_no_button?(locator, options={})
+        has_no_selector?(:button, locator, options)
       end
 
       ##
@@ -341,8 +345,8 @@ module Capybara
       # @param [String] locator           The label, name or id of a checked field
       # @return [Boolean]                 Whether it exists
       #
-      def has_checked_field?(locator)
-        has_selector?(:field, locator, :checked => true)
+      def has_checked_field?(locator, options={})
+        has_selector?(:field, locator, options.merge(:checked => true))
       end
 
       ##
@@ -352,10 +356,10 @@ module Capybara
       # checked.
       #
       # @param [String] locator           The label, name or id of a checked field
-      # @return [Boolean]                 Whether it doesn't exists
+      # @return [Boolean]                 Whether it doesn't exist
       #
-      def has_no_checked_field?(locator)
-        has_no_selector?(:field, locator, :checked => true)
+      def has_no_checked_field?(locator, options={})
+        has_no_selector?(:field, locator, options.merge(:checked => true))
       end
 
       ##
@@ -367,8 +371,8 @@ module Capybara
       # @param [String] locator           The label, name or id of an unchecked field
       # @return [Boolean]                 Whether it exists
       #
-      def has_unchecked_field?(locator)
-        has_selector?(:field, locator, :unchecked => true)
+      def has_unchecked_field?(locator, options={})
+        has_selector?(:field, locator, options.merge(:unchecked => true))
       end
 
       ##
@@ -378,10 +382,10 @@ module Capybara
       # unchecked.
       #
       # @param [String] locator           The label, name or id of an unchecked field
-      # @return [Boolean]                 Whether it doesn't exists
+      # @return [Boolean]                 Whether it doesn't exist
       #
-      def has_no_unchecked_field?(locator)
-        has_no_selector?(:field, locator, :unchecked => true)
+      def has_no_unchecked_field?(locator, options={})
+        has_no_selector?(:field, locator, options.merge(:unchecked => true))
       end
 
       ##
diff --git a/lib/capybara/node/simple.rb b/lib/capybara/node/simple.rb
index 4e4b6c9..d55b410 100644
--- a/lib/capybara/node/simple.rb
+++ b/lib/capybara/node/simple.rb
@@ -18,7 +18,7 @@ module Capybara
       attr_reader :native
 
       def initialize(native)
-        native = Nokogiri::HTML(native) if native.is_a?(String)
+        native = Capybara::HTML(native) if native.is_a?(String)
         @native = native
       end
 
@@ -74,7 +74,7 @@ module Capybara
       #
       def value
         if tag_name == 'textarea'
-          native.content.sub(/\A\n/, '')
+          native.content
         elsif tag_name == 'select'
           if native['multiple'] == 'multiple'
             native.xpath(".//option[@selected='selected']").map { |option| option[:value] || option.content  }
@@ -82,6 +82,8 @@ module Capybara
             option = native.xpath(".//option[@selected='selected']").first || native.xpath(".//option").first
             option[:value] || option.content if option
           end
+        elsif tag_name == 'input' && %w(radio checkbox).include?(native[:type])
+          native[:value] || 'on'
         else
           native[:value]
         end
@@ -95,7 +97,7 @@ module Capybara
       # @return [Boolean]     Whether the element is visible
       #
       def visible?
-        native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or name()='script' or name()='head']").size == 0
+        native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or @hidden or name()='script' or name()='head']").size == 0
       end
 
       ##
diff --git a/lib/capybara/query.rb b/lib/capybara/query.rb
index 17abd1c..21eb933 100644
--- a/lib/capybara/query.rb
+++ b/lib/capybara/query.rb
@@ -32,6 +32,7 @@ module Capybara
     def description
       @description = "#{label} #{locator.inspect}"
       @description << " with text #{options[:text].inspect}" if options[:text]
+      @description << " with value #{options[:with].inspect}" if options[:with]
       @description
     end
 
diff --git a/lib/capybara/rack_test/browser.rb b/lib/capybara/rack_test/browser.rb
index 5c92df8..128c353 100644
--- a/lib/capybara/rack_test/browser.rb
+++ b/lib/capybara/rack_test/browser.rb
@@ -46,6 +46,7 @@ class Capybara::RackTest::Browser
     method.downcase! unless method.is_a? Symbol
 
     new_uri.path = request_path if path.start_with?("?")
+    new_uri.path = "/" if new_uri.path.empty?
     new_uri.path = request_path.sub(%r(/[^/]*$), '/') + new_uri.path unless new_uri.path.start_with?('/')
     new_uri.scheme ||= @current_scheme
     new_uri.host ||= @current_host
@@ -77,7 +78,7 @@ class Capybara::RackTest::Browser
   end
 
   def dom
-    @dom ||= Nokogiri::HTML(html)
+    @dom ||= Capybara::HTML(html)
   end
 
   def find(format, selector)
@@ -93,11 +94,11 @@ class Capybara::RackTest::Browser
   rescue Rack::Test::Error
     ""
   end
-  
+
   def title
     dom.xpath("//title").text
   end
-  
+
 protected
 
   def build_rack_mock_session
@@ -108,6 +109,6 @@ protected
   def request_path
     last_request.path
   rescue Rack::Test::Error
-    ""
+    "/"
   end
 end
diff --git a/lib/capybara/rack_test/form.rb b/lib/capybara/rack_test/form.rb
index 5525493..31c55ae 100644
--- a/lib/capybara/rack_test/form.rb
+++ b/lib/capybara/rack_test/form.rb
@@ -28,7 +28,10 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
       case field.name
       when 'input'
         if %w(radio checkbox).include? field['type']
-          merge_param!(params, field['name'].to_s, field['value'].to_s) if field['checked']
+          if field['checked']
+            node=Capybara::RackTest::Node.new(self.driver, field)
+            merge_param!(params, field['name'].to_s, node.value.to_s)
+          end          
         elsif %w(submit image).include? field['type']
           # TO DO identify the click button here (in document order, rather
           # than leaving until the end of the params)
@@ -60,7 +63,7 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
           merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) if option
         end
       when 'textarea'
-        merge_param!(params, field['name'].to_s, field.text.to_s)
+        merge_param!(params, field['name'].to_s, field.text.to_s.gsub(/\n/, "\r\n"))
       end
     end
     merge_param!(params, button[:name], button[:value] || "") if button[:name]
diff --git a/lib/capybara/rack_test/node.rb b/lib/capybara/rack_test/node.rb
index ac4320e..37ea24a 100644
--- a/lib/capybara/rack_test/node.rb
+++ b/lib/capybara/rack_test/node.rb
@@ -52,7 +52,8 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
       driver.follow(method, self[:href].to_s)
     elsif (tag_name == 'input' and %w(submit image).include?(type)) or
         ((tag_name == 'button') and type.nil? or type == "submit")
-      Capybara::RackTest::Form.new(driver, form).submit(self)
+      associated_form = form
+      Capybara::RackTest::Form.new(driver, associated_form).submit(self) if associated_form
     end
   end
 
diff --git a/lib/capybara/result.rb b/lib/capybara/result.rb
index 0dc4340..bd4dac1 100644
--- a/lib/capybara/result.rb
+++ b/lib/capybara/result.rb
@@ -29,7 +29,8 @@ module Capybara
       @query = query
     end
 
-    def_delegators :@result, :each, :[], :at, :size, :count, :length, :first, :last, :empty?
+    def_delegators :@result, :each, :[], :at, :size, :count, :length,
+                   :first, :last, :values_at, :empty?, :inspect, :sample, :index
 
     def matches_count?
       Capybara::Helpers.matches_count?(@result.size, @query.options)
diff --git a/lib/capybara/rspec.rb b/lib/capybara/rspec.rb
index 1a91765..f3bc2ca 100644
--- a/lib/capybara/rspec.rb
+++ b/lib/capybara/rspec.rb
@@ -7,6 +7,12 @@ require 'capybara/rspec/features'
 RSpec.configure do |config|
   config.include Capybara::DSL, :type => :feature
   config.include Capybara::RSpecMatchers, :type => :feature
+
+  # A work-around to support accessing the current example that works in both
+  # RSpec 2 and RSpec 3.
+  fetch_current_example = RSpec.respond_to?(:current_example) ?
+    proc { RSpec.current_example } : proc { |context| context.example }
+
   # The before and after blocks must run instantaneously, because Capybara
   # might not actually be used in all examples where it's included.
   config.after do
@@ -17,6 +23,7 @@ RSpec.configure do |config|
   end
   config.before do
     if self.class.include?(Capybara::DSL)
+      example = fetch_current_example.call(self)
       Capybara.current_driver = Capybara.javascript_driver if example.metadata[:js]
       Capybara.current_driver = example.metadata[:driver] if example.metadata[:driver]
     end
diff --git a/lib/capybara/rspec/features.rb b/lib/capybara/rspec/features.rb
index 9b81aab..bb5e1e1 100644
--- a/lib/capybara/rspec/features.rb
+++ b/lib/capybara/rspec/features.rb
@@ -7,11 +7,13 @@ module Capybara
         alias :xscenario :xit
         alias :given :let
         alias :given! :let!
+        alias :feature :describe
       end
     end
   end
 end
 
+
 def self.feature(*args, &block)
   options = if args.last.is_a?(Hash) then args.pop else {} end
   options[:capybara_feature] = true
diff --git a/lib/capybara/rspec/matchers.rb b/lib/capybara/rspec/matchers.rb
index 4267acc..b6529cf 100644
--- a/lib/capybara/rspec/matchers.rb
+++ b/lib/capybara/rspec/matchers.rb
@@ -126,20 +126,20 @@ module Capybara
       HaveSelector.new(:link, locator, options)
     end
 
-    def have_button(locator)
-      HaveSelector.new(:button, locator)
+    def have_button(locator, options={})
+      HaveSelector.new(:button, locator, options)
     end
 
     def have_field(locator, options={})
       HaveSelector.new(:field, locator, options)
     end
 
-    def have_checked_field(locator)
-      HaveSelector.new(:field, locator, :checked => true)
+    def have_checked_field(locator, options={})
+      HaveSelector.new(:field, locator, options.merge(:checked => true))
     end
 
-    def have_unchecked_field(locator)
-      HaveSelector.new(:field, locator, :unchecked => true)
+    def have_unchecked_field(locator, options={})
+      HaveSelector.new(:field, locator, options.merge(:unchecked => true))
     end
 
     def have_select(locator, options={})
diff --git a/lib/capybara/selector.rb b/lib/capybara/selector.rb
index a1b2572..d6e51f5 100644
--- a/lib/capybara/selector.rb
+++ b/lib/capybara/selector.rb
@@ -103,7 +103,7 @@ Capybara.add_selector(:field) do
   filter(:checked) { |node, value| not(value ^ node.checked?) }
   filter(:unchecked) { |node, value| (value ^ node.checked?) }
   filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) }
-  filter(:with) { |node, with| node.value == with }
+  filter(:with) { |node, with| node.value == with.to_s }
   filter(:type) do |node, type|
     if ['textarea', 'select'].include?(type)
       node.tag_name == type
@@ -146,6 +146,7 @@ Capybara.add_selector(:radio_button) do
   xpath { |locator| XPath::HTML.radio_button(locator) }
   filter(:checked) { |node, value| not(value ^ node.checked?) }
   filter(:unchecked) { |node, value| (value ^ node.checked?) }
+  filter(:option)  { |node, value|  node.value == value.to_s }
   filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) }
 end
 
@@ -153,6 +154,7 @@ Capybara.add_selector(:checkbox) do
   xpath { |locator| XPath::HTML.checkbox(locator) }
   filter(:checked) { |node, value| not(value ^ node.checked?) }
   filter(:unchecked) { |node, value| (value ^ node.checked?) }
+  filter(:option)  { |node, value|  node.value == value.to_s }
   filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) }
 end
 
diff --git a/lib/capybara/selenium/driver.rb b/lib/capybara/selenium/driver.rb
index 9941eea..ddf3552 100644
--- a/lib/capybara/selenium/driver.rb
+++ b/lib/capybara/selenium/driver.rb
@@ -1,3 +1,5 @@
+require "uri"
+
 class Capybara::Selenium::Driver < Capybara::Driver::Base
   DEFAULT_OPTIONS = {
     :browser => :firefox
@@ -43,6 +45,14 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
     browser.navigate.to(path)
   end
 
+  def go_back
+    browser.navigate.back
+  end
+
+  def go_forward
+    browser.navigate.forward
+  end
+
   def html
     browser.page_source
   end
@@ -87,7 +97,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
         # to about:blank, so we rescue this error and do nothing
         # instead.
       end
-      @browser.navigate.to('about:blank')
+      @browser.navigate.to("about:blank")
     end
   end
 
@@ -137,7 +147,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
   end
 
   def quit
-    @browser.quit
+    @browser.quit if @browser
   rescue Errno::ECONNREFUSED
     # Browser must have already gone
   end
diff --git a/lib/capybara/selenium/node.rb b/lib/capybara/selenium/node.rb
index 1de5bbe..cb96774 100644
--- a/lib/capybara/selenium/node.rb
+++ b/lib/capybara/selenium/node.rb
@@ -37,8 +37,21 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
       path_names = value.to_s.empty? ? [] : value
       native.send_keys(*path_names)
     elsif tag_name == 'textarea' or tag_name == 'input'
-      #script can change a readonly element which user input cannot, so dont execute if readonly
-      driver.browser.execute_script "arguments[0].value = ''", native unless self[:readonly]
+      if value.to_s.empty?
+        native.clear
+      else
+        #script can change a readonly element which user input cannot, so dont execute if readonly
+        driver.browser.execute_script "arguments[0].value = ''", native unless self[:readonly]
+        native.send_keys(value.to_s)
+      end
+    elsif native.attribute('isContentEditable')
+      #ensure we are focused on the element
+      script = <<-JS
+        var range = document.createRange();
+        range.selectNodeContents(arguments[0]);
+        window.getSelection().addRange(range);
+      JS
+      driver.browser.execute_script script, native
       native.send_keys(value.to_s)
     end
   end
@@ -61,7 +74,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
   def hover
     driver.browser.action.move_to(native).perform
   end
-  
+
   def drag_to(element)
     driver.browser.action.drag_and_drop(native, element.native).perform
   end
@@ -89,11 +102,11 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
   def find_xpath(locator)
     native.find_elements(:xpath, locator).map { |n| self.class.new(driver, n) }
   end
-  
+
   def find_css(locator)
     native.find_elements(:css, locator).map { |n| self.class.new(driver, n) }
   end
-  
+
   def ==(other)
     native == other.native
   end
diff --git a/lib/capybara/server.rb b/lib/capybara/server.rb
index e5182e5..efd52f0 100644
--- a/lib/capybara/server.rb
+++ b/lib/capybara/server.rb
@@ -31,13 +31,13 @@ module Capybara
       end
     end
 
-    attr_reader :app, :port
+    attr_reader :app, :port, :host
 
-    def initialize(app, port=Capybara.server_port)
+    def initialize(app, port=Capybara.server_port, host=Capybara.server_host)
       @app = app
       @middleware = Middleware.new(@app)
       @server_thread = nil # supress warnings
-      @port = port
+      @host, @port = host, port
       @port ||= Capybara::Server.ports[@app.object_id]
       @port ||= find_available_port
     end
@@ -50,10 +50,6 @@ module Capybara
       @middleware.error
     end
 
-    def host
-      Capybara.server_host || "127.0.0.1"
-    end
-
     def responsive?
       return false if @server_thread && @server_thread.join(0)
 
diff --git a/lib/capybara/session.rb b/lib/capybara/session.rb
index 933addd..6860135 100644
--- a/lib/capybara/session.rb
+++ b/lib/capybara/session.rb
@@ -37,10 +37,11 @@ module Capybara
       :has_no_unchecked_field?, :query, :assert_selector, :assert_no_selector
     ]
     SESSION_METHODS = [
-      :body, :html, :current_url, :current_host, :evaluate_script, :source,
-      :visit, :within, :within_fieldset, :within_table, :within_frame,
-      :within_window, :current_path, :save_page, :save_and_open_page,
-      :save_screenshot, :reset_session!, :response_headers, :status_code,
+      :body, :html, :source, :current_url, :current_host, :current_path,
+      :execute_script, :evaluate_script, :visit, :go_back, :go_forward,
+      :within, :within_fieldset, :within_table, :within_frame, :within_window,
+      :save_page, :save_and_open_page, :save_screenshot,
+      :reset_session!, :response_headers, :status_code,
       :title, :has_title?, :has_no_title?, :current_scope
     ]
     DSL_METHODS = NODE_METHODS + SESSION_METHODS
@@ -74,8 +75,11 @@ module Capybara
     # Reset the session, removing all cookies.
     #
     def reset!
-      driver.reset! if @touched
-      @touched = false
+      if @touched
+        driver.reset!
+        @touched = false
+        assert_no_selector :xpath, "/html/body/*"
+      end
       raise @server.error if Capybara.raise_server_errors and @server and @server.error
     ensure
       @server.reset_error! if @server
@@ -195,27 +199,54 @@ module Capybara
 
     ##
     #
-    # Execute the given block for a particular scope on the page. Within will find the first
-    # element matching the given selector and execute the block scoped to that element:
+    # Move back a single entry in the browser's history.
+    #
+    def go_back
+      driver.go_back
+    end
+
+    ##
+    #
+    # Move forward a single entry in the browser's history.
+    #
+    def go_forward
+      driver.go_forward
+    end
+
+    ##
+    #
+    # Executes the given block within the context of a node. `within` takes the
+    # same options as `find`, as well as a block. For the duration of the
+    # block, any command to Capybara will be handled as though it were scoped
+    # to the given element.
     #
     #     within(:xpath, '//div[@id="delivery-address"]') do
     #       fill_in('Street', :with => '12 Main Street')
     #     end
     #
-    # It is possible to omit the first parameter, in that case, the selector is assumed to be
-    # of the type set in Capybara.default_selector.
+    # Just as with `find`, if multiple elements match the selector given to
+    # `within`, an error will be raised, and just as with `find`, this
+    # behaviour can be controlled through the `:match` and `:exact` options.
+    #
+    # It is possible to omit the first parameter, in that case, the selector is
+    # assumed to be of the type set in Capybara.default_selector.
     #
     #     within('div#delivery-address') do
     #       fill_in('Street', :with => '12 Main Street')
     #     end
     #
+    # Note that a lot of uses of `within` can be replaced more succinctly with
+    # chaining:
+    #
+    #     find('div#delivery-address').fill_in('Street', :with => '12 Main Street')
+    #
     # @overload within(*find_args)
     #   @param (see Capybara::Node::Finders#all)
     #
     # @overload within(a_node)
     #   @param [Capybara::Node::Base] a_node   The node in whose scope the block should be evaluated
     #
-    # @raise  [Capybara::ElementNotFound]   If the scope can't be found before time expires
+    # @raise  [Capybara::ElementNotFound]      If the scope can't be found before time expires
     #
     def within(*args)
       new_scope = if args.first.is_a?(Capybara::Node::Base) then args.first else find(*args) end
@@ -262,9 +293,12 @@ module Capybara
     #   @param [String] name           name of a frame
     #
     def within_frame(frame_handle)
+      scopes.push(nil)
       driver.within_frame(frame_handle) do
         yield
       end
+    ensure
+      scopes.pop
     end
 
     ##
@@ -275,7 +309,10 @@ module Capybara
     # @param [String] handle of the window
     #
     def within_window(handle, &blk)
+      scopes.push(nil)
       driver.within_window(handle, &blk)
+    ensure
+      scopes.pop
     end
 
     ##
@@ -313,7 +350,7 @@ module Capybara
     #
     def save_page(path=nil)
       path ||= "capybara-#{Time.new.strftime("%Y%m%d%H%M%S")}#{rand(10**10)}.html"
-      path = File.expand_path(path, Capybara.save_and_open_page_path) if Capybara.save_and_open_page_path
+      path = File.expand_path(path, Capybara.save_and_open_page_path)
 
       FileUtils.mkdir_p(File.dirname(path))
 
@@ -328,10 +365,15 @@ module Capybara
     # @param  [String] file_name  The path to where it should be saved [optional]
     #
     def save_and_open_page(file_name=nil)
-      require "launchy"
-      Launchy.open(save_page(file_name))
-    rescue LoadError
-      warn "Please install the launchy gem to open page with save_and_open_page"
+      file_name = save_page(file_name)
+
+      begin
+        require "launchy"
+        Launchy.open(file_name)
+      rescue LoadError
+        warn "Page saved to #{file_name} with save_and_open_page."
+        warn "Please install the launchy gem to open page automatically."
+      end
     end
 
     ##
@@ -382,7 +424,7 @@ module Capybara
     end
 
     def current_scope
-      scopes.last
+      scopes.last || document
     end
 
   private
diff --git a/lib/capybara/spec/public/test.js b/lib/capybara/spec/public/test.js
index 5980e6d..b55b8c9 100644
--- a/lib/capybara/spec/public/test.js
+++ b/lib/capybara/spec/public/test.js
@@ -35,7 +35,7 @@ $(function() {
     $('body').append('<p id="focus_event_triggered">Focus Event triggered</p>');
   });
   $('#with_change_event').change(function() {
-    if($(this).val() == '') $(this).val("Can't be empty");
+    $('body').append($('<p class="change_event_triggered"></p>').text(this.value));
   });
   $('#checkbox_with_event').click(function() {
     $('body').append('<p id="checkbox_event_triggered">Checkbox event triggered</p>');
diff --git a/lib/capybara/spec/session/assert_selector.rb b/lib/capybara/spec/session/assert_selector.rb
index f34d04b..4274d5a 100644
--- a/lib/capybara/spec/session/assert_selector.rb
+++ b/lib/capybara/spec/session/assert_selector.rb
@@ -58,6 +58,16 @@ Capybara::SpecHelper.spec '#assert_selector' do
       expect { @session.assert_selector("//p//a", :text => /Red$/) }.to raise_error(Capybara::ElementNotFound)
     end
   end
+
+  context "with wait", :requires => [:js] do
+    it "should find element if it appears before given wait duration" do
+      Capybara.using_wait_time(0.1) do
+        @session.visit('/with_js')
+        @session.click_link('Click me')
+        @session.assert_selector(:css, "a#has-been-clicked", :text => "Has been clicked", :wait => 0.9)
+      end
+    end
+  end
 end
 
 Capybara::SpecHelper.spec '#assert_no_selector' do
@@ -120,4 +130,12 @@ Capybara::SpecHelper.spec '#assert_no_selector' do
       @session.assert_no_selector("//p//a", :text => /Red$/)
     end
   end
+
+  context "with wait", :requires => [:js] do
+    it "should not find element if it appears after given wait duration" do
+      @session.visit('/with_js')
+      @session.click_link('Click me')
+      @session.assert_no_selector(:css, "a#has-been-clicked", :text => "Has been clicked", :wait => 0.1)
+    end
+  end
 end
diff --git a/lib/capybara/spec/session/attach_file_spec.rb b/lib/capybara/spec/session/attach_file_spec.rb
index 4aa5841..ab8bb34 100644
--- a/lib/capybara/spec/session/attach_file_spec.rb
+++ b/lib/capybara/spec/session/attach_file_spec.rb
@@ -64,13 +64,18 @@ Capybara::SpecHelper.spec "#attach_file" do
     end
 
     it  "should not break when using HTML5 multiple file input uploading multiple files" do
-      pending "Selenium is buggy on this, see http://code.google.com/p/selenium/issues/detail?id=2239" if @session.respond_to?(:mode) && @session.mode == :selenium
+      pending "Selenium is buggy on this, see http://code.google.com/p/selenium/issues/detail?id=2239" if @session.respond_to?(:mode) && @session.mode.to_s =~ /^selenium/
       @session.attach_file "Multiple Documents", [@test_file_path, @another_test_file_path]
       @session.click_button('Upload Multiple')
       @session.body.should include("2 | ")#number of files
       @session.body.should include(File.read(@test_file_path))
       @session.body.should include(File.read(@another_test_file_path))
     end
+
+    it "should not send anything when attaching no files to a multiple upload field" do
+      @session.click_button('Upload Empty Multiple')
+      @session.body.should include("Successfully ignored empty file field")
+    end
   end
 
   context "with a locator that doesn't exist" do
diff --git a/lib/capybara/spec/session/check_spec.rb b/lib/capybara/spec/session/check_spec.rb
index 18b2cc6..30d38fb 100644
--- a/lib/capybara/spec/session/check_spec.rb
+++ b/lib/capybara/spec/session/check_spec.rb
@@ -96,4 +96,18 @@ Capybara::SpecHelper.spec "#check" do
       end.to raise_error(Capybara::ElementNotFound)
     end
   end
+
+  context "with `option` option" do
+    it "can check boxes by their value" do
+      @session.check('form[pets][]', :option => "cat")
+      @session.click_button('awesome')
+      extract_results(@session)['pets'].should include('cat')
+    end
+
+    it "should raise an error if option not found" do
+      expect do
+        @session.check('form[pets][]', :option => "elephant")
+      end.to raise_error(Capybara::ElementNotFound)
+    end
+  end
 end
diff --git a/lib/capybara/spec/session/choose_spec.rb b/lib/capybara/spec/session/choose_spec.rb
index ce471c3..8cbf77d 100644
--- a/lib/capybara/spec/session/choose_spec.rb
+++ b/lib/capybara/spec/session/choose_spec.rb
@@ -51,4 +51,18 @@ Capybara::SpecHelper.spec "#choose" do
       end.to raise_error(Capybara::ElementNotFound)
     end
   end
+
+  context "with `option` option" do
+    it "can check radio buttons by their value" do
+      @session.choose('form[gender]', :option => "male")
+      @session.click_button('awesome')
+      extract_results(@session)['gender'].should == "male"
+    end
+
+    it "should raise an error if option not found" do
+      expect do
+        @session.choose('form[gender]', :option => "hermaphrodite")
+      end.to raise_error(Capybara::ElementNotFound)
+    end
+  end
 end
diff --git a/lib/capybara/spec/session/click_button_spec.rb b/lib/capybara/spec/session/click_button_spec.rb
index 5b6c13e..bc979a7 100644
--- a/lib/capybara/spec/session/click_button_spec.rb
+++ b/lib/capybara/spec/session/click_button_spec.rb
@@ -102,10 +102,18 @@ Capybara::SpecHelper.spec '#click_button' do
         @results['gender'].should == 'female'
       end
 
+      it "should default radio value to 'on' if none specified" do
+        @results['valueless_radio'].should == 'on'
+      end
+
       it "should serialize check boxes" do
         @results['pets'].should include('dog', 'hamster')
         @results['pets'].should_not include('cat')
       end
+      
+      it "should default checkbox value to 'on' if none specififed" do
+        @results['valueless_checkbox'].should == 'on'
+      end
 
       it "should serialize text areas" do
         @results['description'].should == 'Descriptive text goes here'
@@ -126,7 +134,11 @@ Capybara::SpecHelper.spec '#click_button' do
       it "should not serialize a select tag without options" do
         @results['tendency'].should be_nil
       end
-
+      
+      it "should convert lf to cr/lf in submitted textareas" do
+        @results['newline'].should == "\r\nNew line after and before textarea tag\r\n"
+      end
+      
       it "should not submit disabled fields" do
         @results['disabled_text_field'].should be_nil
         @results['disabled_textarea'].should be_nil
@@ -225,6 +237,12 @@ Capybara::SpecHelper.spec '#click_button' do
     end
   end
 
+  context "with submit button not associated with any form" do
+    it "should not error when clicked" do
+      lambda { @session.click_button('no_form_button') }.should_not raise_error
+    end
+  end
+
   context "with alt given on an image button" do
     it "should submit the associated form" do
       @session.click_button('oh hai thar')
@@ -236,6 +254,7 @@ Capybara::SpecHelper.spec '#click_button' do
       extract_results(@session)['first_name'].should == 'John'
     end
   end
+  
 
   context "with value given on an image button" do
     it "should submit the associated form" do
diff --git a/lib/capybara/spec/session/fill_in_spec.rb b/lib/capybara/spec/session/fill_in_spec.rb
index 4b8eda8..5b2daab 100644
--- a/lib/capybara/spec/session/fill_in_spec.rb
+++ b/lib/capybara/spec/session/fill_in_spec.rb
@@ -57,6 +57,12 @@ Capybara::SpecHelper.spec "#fill_in" do
     extract_results(@session)['description'].should == 'is <strong>very</strong> secret!'
   end
 
+  it "should handle newlines in a textarea" do
+    @session.fill_in('form_description', :with => "\nSome text\n")
+    @session.click_button('awesome')
+    extract_results(@session)['description'].should == "\r\nSome text\r\n"
+  end
+
   it "should fill in a field with a custom type" do
     @session.fill_in('Schmooo', :with => 'Schmooo is the game')
     @session.click_button('awesome')
@@ -109,7 +115,7 @@ Capybara::SpecHelper.spec "#fill_in" do
     extract_results(@session)['first_name'].should == 'Harry'
   end
 
-  it "casts to string if field has maxlength", :focus => true do
+  it "casts to string if field has maxlength" do
     @session.fill_in(:'form_zipcode', :with => 1234567)
     @session.click_button('awesome')
     extract_results(@session)['zipcode'].should == '12345'
@@ -119,7 +125,17 @@ Capybara::SpecHelper.spec "#fill_in" do
     it 'should only trigger onchange once' do
       @session.visit('/with_js')
       @session.fill_in('with_change_event', :with => 'some value')
-      @session.find(:css, '#with_change_event').value.should == 'some value'
+      # click outside the field to trigger the change event
+      @session.find(:css, 'body').click
+      @session.find(:css, '.change_event_triggered', :match => :one).should have_text 'some value'
+    end
+
+    it 'should trigger change when clearing field' do
+      @session.visit('/with_js')
+      @session.fill_in('with_change_event', :with => '')
+      # click outside the field to trigger the change event
+      @session.find(:css, 'body').click
+      @session.should have_selector(:css, '.change_event_triggered', :match => :one)
     end
   end
 
diff --git a/lib/capybara/spec/session/go_back_spec.rb b/lib/capybara/spec/session/go_back_spec.rb
new file mode 100644
index 0000000..1debd40
--- /dev/null
+++ b/lib/capybara/spec/session/go_back_spec.rb
@@ -0,0 +1,10 @@
+Capybara::SpecHelper.spec '#go_back', :requires => [:js] do
+  it "should fetch a response from the driver from the previous page" do
+    @session.visit('/')
+    @session.should have_content('Hello world!')
+    @session.visit('/foo')
+    @session.should have_content('Another World')
+    @session.go_back
+    @session.should have_content('Hello world!')
+  end
+end
diff --git a/lib/capybara/spec/session/go_forward_spec.rb b/lib/capybara/spec/session/go_forward_spec.rb
new file mode 100644
index 0000000..2314ef4
--- /dev/null
+++ b/lib/capybara/spec/session/go_forward_spec.rb
@@ -0,0 +1,12 @@
+Capybara::SpecHelper.spec '#go_forward', :requires => [:js] do
+  it "should fetch a response from the driver from the previous page" do
+    @session.visit('/')
+    @session.should have_content('Hello world!')
+    @session.visit('/foo')
+    @session.should have_content('Another World')
+    @session.go_back
+    @session.should have_content('Hello world!')
+    @session.go_forward
+    @session.should have_content('Another World')
+  end
+end
diff --git a/lib/capybara/spec/session/has_button_spec.rb b/lib/capybara/spec/session/has_button_spec.rb
index d1ba42b..8c5338e 100644
--- a/lib/capybara/spec/session/has_button_spec.rb
+++ b/lib/capybara/spec/session/has_button_spec.rb
@@ -9,9 +9,21 @@ Capybara::SpecHelper.spec '#has_button?' do
     @session.should have_button(:'crap321')
   end
 
+  it "should be true for disabled buttons if :disabled => true" do
+    @session.should have_button('Disabled button', :disabled => true)
+  end
+
   it "should be false if the given button is not on the page" do
     @session.should_not have_button('monkey')
   end
+
+  it "should be false for disabled buttons by default" do
+    @session.should_not have_button('Disabled button')
+  end
+
+  it "should be false for disabled buttons if :disabled => false" do
+    @session.should_not have_button('Disabled button', :disabled => false)
+  end
 end
 
 Capybara::SpecHelper.spec '#has_no_button?' do
@@ -24,7 +36,19 @@ Capybara::SpecHelper.spec '#has_no_button?' do
     @session.should_not have_no_button('crap321')
   end
 
+  it "should be true for disabled buttons if :disabled => true" do
+    @session.should_not have_no_button('Disabled button', :disabled => true)
+  end
+
   it "should be false if the given button is not on the page" do
     @session.should have_no_button('monkey')
   end
+
+  it "should be false for disabled buttons by default" do
+    @session.should have_no_button('Disabled button')
+  end
+
+  it "should be false for disabled buttons if :disabled => false" do
+    @session.should have_no_button('Disabled button', :disabled => false)
+  end
 end
diff --git a/lib/capybara/spec/session/has_field_spec.rb b/lib/capybara/spec/session/has_field_spec.rb
index abc1df0..619856b 100644
--- a/lib/capybara/spec/session/has_field_spec.rb
+++ b/lib/capybara/spec/session/has_field_spec.rb
@@ -121,6 +121,10 @@ Capybara::SpecHelper.spec '#has_checked_field?' do
     @session.should have_checked_field('Hamster')
   end
 
+  it "should be true for disabled checkboxes if :disabled => true" do
+    @session.should have_checked_field('Disabled Checkbox', :disabled => true)
+  end
+
   it "should be false if an unchecked field is on the page" do
     @session.should_not have_checked_field('form_pets_cat')
     @session.should_not have_checked_field('Male')
@@ -130,6 +134,14 @@ Capybara::SpecHelper.spec '#has_checked_field?' do
     @session.should_not have_checked_field('Does Not Exist')
   end
 
+  it "should be false for disabled checkboxes by default" do
+    @session.should_not have_checked_field('Disabled Checkbox')
+  end
+
+  it "should be false for disabled checkboxes if :disabled => false" do
+    @session.should_not have_checked_field('Disabled Checkbox', :disabled => false)
+  end
+
   it "should be true after an unchecked checkbox is checked" do
     @session.check('form_pets_cat')
     @session.should have_checked_field('form_pets_cat')
@@ -159,6 +171,10 @@ Capybara::SpecHelper.spec '#has_no_checked_field?' do
     @session.should_not have_no_checked_field('Hamster')
   end
 
+  it "should be false for disabled checkboxes if :disabled => true" do
+    @session.should_not have_no_checked_field('Disabled Checkbox', :disabled => true)
+  end
+
   it "should be true if an unchecked field is on the page" do
     @session.should have_no_checked_field('form_pets_cat')
     @session.should have_no_checked_field('Male')
@@ -167,6 +183,14 @@ Capybara::SpecHelper.spec '#has_no_checked_field?' do
   it "should be true if no field is on the page" do
     @session.should have_no_checked_field('Does Not Exist')
   end
+
+  it "should be true for disabled checkboxes by default" do
+    @session.should have_no_checked_field('Disabled Checkbox')
+  end
+
+  it "should be true for disabled checkboxes if :disabled => false" do
+    @session.should have_no_checked_field('Disabled Checkbox', :disabled => false)
+  end
 end
 
 Capybara::SpecHelper.spec '#has_unchecked_field?' do
@@ -182,10 +206,22 @@ Capybara::SpecHelper.spec '#has_unchecked_field?' do
     @session.should have_unchecked_field('Male')
   end
 
+  it "should be true for disabled unchecked fields if :disabled => true" do
+    @session.should have_unchecked_field('Disabled Unchecked Checkbox', :disabled => true)
+  end
+
   it "should be false if no field is on the page" do
     @session.should_not have_unchecked_field('Does Not Exist')
   end
 
+  it "should be false for disabled unchecked fields by default" do
+    @session.should_not have_unchecked_field('Disabled Unchecked Checkbox')
+  end
+
+  it "should be false for disabled unchecked fields if :disabled => false" do
+    @session.should_not have_unchecked_field('Disabled Unchecked Checkbox', :disabled => false)
+  end
+
   it "should be false after an unchecked checkbox is checked" do
     @session.check('form_pets_cat')
     @session.should_not have_unchecked_field('form_pets_cat')
@@ -220,7 +256,19 @@ Capybara::SpecHelper.spec '#has_no_unchecked_field?' do
     @session.should_not have_no_unchecked_field('Male')
   end
 
+  it "should be false for disabled unchecked fields if :disabled => true" do
+    @session.should_not have_no_unchecked_field('Disabled Unchecked Checkbox', :disabled => true)
+  end
+
   it "should be true if no field is on the page" do
     @session.should have_no_unchecked_field('Does Not Exist')
   end
+
+  it "should be true for disabled unchecked fields by default" do
+    @session.should have_no_unchecked_field('Disabled Unchecked Checkbox')
+  end
+
+  it "should be true for disabled unchecked fields if :disabled => false" do
+    @session.should have_no_unchecked_field('Disabled Unchecked Checkbox', :disabled => false)
+  end
 end
diff --git a/lib/capybara/spec/session/has_text_spec.rb b/lib/capybara/spec/session/has_text_spec.rb
index 7bd46d3..b71febb 100644
--- a/lib/capybara/spec/session/has_text_spec.rb
+++ b/lib/capybara/spec/session/has_text_spec.rb
@@ -190,6 +190,16 @@ Capybara::SpecHelper.spec '#has_text?' do
       @session.should_not have_text('count', minimum: '3')
     end
   end
+
+  context "with wait", :requires => [:js] do
+    it "should find element if it appears before given wait duration" do
+      Capybara.using_wait_time(0.1) do
+        @session.visit('/with_js')
+        @session.click_link('Click me')
+        @session.should have_text('Has been clicked', :wait => 0.9)
+      end
+    end
+  end
 end
 
 Capybara::SpecHelper.spec '#has_no_text?' do
@@ -288,4 +298,12 @@ Capybara::SpecHelper.spec '#has_no_text?' do
     @session.click_link('Click me')
     @session.should have_no_text("I changed it")
   end
+
+  context "with wait", :requires => [:js] do
+    it "should not find element if it appears after given wait duration" do
+      @session.visit('/with_js')
+      @session.click_link('Click me')
+      @session.should have_no_text('Has been clicked', :wait => 0.1)
+    end
+  end
 end
diff --git a/lib/capybara/spec/session/node_spec.rb b/lib/capybara/spec/session/node_spec.rb
index c015c8e..e576fe7 100644
--- a/lib/capybara/spec/session/node_spec.rb
+++ b/lib/capybara/spec/session/node_spec.rb
@@ -58,10 +58,25 @@ Capybara::SpecHelper.spec "node" do
       @session.find('//textarea[@id="additional_newline"]').value.should == "\nbanana"
     end
 
+    it "should not swallow leading newlines for set content in textarea" do
+      @session.find('//textarea[@id="normal"]').set("\nbanana")
+      @session.find('//textarea[@id="normal"]').value.should == "\nbanana"
+    end
+
     it "return any HTML content in textarea" do
       @session.find('//textarea[1]').set("some <em>html</em> here")
       @session.find('//textarea[1]').value.should == "some <em>html</em> here"
     end
+    
+    it "defaults to 'on' for checkbox" do
+      @session.visit('/form')
+      @session.find('//input[@id="valueless_checkbox"]').value.should == 'on'
+    end
+
+    it "defaults to 'on' for radio buttons" do
+      @session.visit('/form')
+      @session.find('//input[@id="valueless_radio"]').value.should == 'on'
+    end    
   end
 
   describe "#set" do
@@ -88,6 +103,25 @@ Capybara::SpecHelper.spec "node" do
       @session.first('//textarea[@readonly]').set('changed')
       @session.first('//textarea[@readonly]').value.should == 'textarea should not change'
     end
+
+    it 'should allow me to change the contents of a contenteditable element', :requires => [:js] do
+      @session.visit('/with_js')
+      @session.find(:css,'#existing_content_editable').set('WYSIWYG')
+      @session.find(:css,'#existing_content_editable').text.should == 'WYSIWYG'
+    end
+
+    it 'should allow me to set the contents of a contenteditable element', :requires => [:js] do
+      @session.visit('/with_js')
+      @session.find(:css,'#blank_content_editable').set('WYSIWYG')
+      @session.find(:css,'#blank_content_editable').text.should == 'WYSIWYG'
+    end
+
+    it 'should allow me to change the contents of a contenteditable elements child', :requires => [:js] do
+      pending "Selenium doesn't like editing nested contents"
+      @session.visit('/with_js')
+      @session.find(:css,'#existing_content_editable_child').set('WYSIWYG')
+      @session.find(:css,'#existing_content_editable_child').text.should == 'WYSIWYG'
+    end
   end
 
   describe "#tag_name" do
@@ -125,6 +159,8 @@ Capybara::SpecHelper.spec "node" do
 
       @session.find('//div[@id="hidden"]').should_not be_visible
       @session.find('//div[@id="hidden_via_ancestor"]').should_not be_visible
+      @session.find('//div[@id="hidden_attr"]').should_not be_visible
+      @session.find('//a[@id="hidden_attr_via_ancestor"]').should_not be_visible
     end
   end
 
@@ -178,7 +214,6 @@ Capybara::SpecHelper.spec "node" do
 
   describe '#hover', :requires => [:hover] do
     it "should allow hovering on an element" do
-      pending "Selenium with firefox doesn't currently work with this (selenium with chrome does)" if @session.respond_to?(:mode) && @session.mode == :selenium && @session.driver.browser.browser == :firefox
       @session.visit('/with_hover')
       @session.find(:css,'.hidden_until_hover', :visible => false).should_not be_visible
       @session.find(:css,'.wrapper').hover
diff --git a/lib/capybara/spec/session/reset_session_spec.rb b/lib/capybara/spec/session/reset_session_spec.rb
index 95bd672..98345be 100644
--- a/lib/capybara/spec/session/reset_session_spec.rb
+++ b/lib/capybara/spec/session/reset_session_spec.rb
@@ -16,9 +16,9 @@ Capybara::SpecHelper.spec '#reset_session!' do
     @session.current_path.should == '/foo'
 
     @session.reset_session!
-    [nil, '', 'about:blank'].should include @session.current_url
+    [nil, '', 'about:blank'].should include(@session.current_url)
+    ['', nil].should include(@session.current_path)
     @session.current_host.should be_nil
-    @session.current_path.should be_nil
   end
 
   it "resets page body" do
@@ -31,6 +31,12 @@ Capybara::SpecHelper.spec '#reset_session!' do
     @session.should have_no_selector('.//h1')
   end
 
+  it "is synchronous" do
+    @session.visit("/with_html")
+    @session.reset_session!
+    @session.should have_no_selector :xpath, "/html/body/*", wait: false
+  end
+
   it "raises any errors caught inside the server", :requires => [:server] do
     quietly { @session.visit("/error") }
     expect do
diff --git a/lib/capybara/spec/session/save_page_spec.rb b/lib/capybara/spec/session/save_page_spec.rb
index 2ee2544..a68984b 100644
--- a/lib/capybara/spec/session/save_page_spec.rb
+++ b/lib/capybara/spec/session/save_page_spec.rb
@@ -37,11 +37,17 @@ Capybara::SpecHelper.spec '#save_page' do
     File.read("capybara-001122.html").should include("Another World")
   end
 
-  it "returns the filename" do
+  it "returns an absolute path in pwd" do
     result = @session.save_page
-    path = Dir.glob("capybara-*.html").first
-    filename = path.split("/").last
-    result.should == filename
+    path = File.expand_path(Dir.glob("capybara-*.html").first, Dir.pwd)
+    result.should == path
+  end
+
+  it "returns an absolute path in given directory" do
+    Capybara.save_and_open_page_path = alternative_path
+    result = @session.save_page
+    path = File.expand_path(Dir.glob(alternative_path + "/capybara-*.html").first, alternative_path)
+    result.should == path
   end
 
   context "asset_host contains a string" do
diff --git a/lib/capybara/spec/session/visit_spec.rb b/lib/capybara/spec/session/visit_spec.rb
index 34e0c98..82ae7a1 100644
--- a/lib/capybara/spec/session/visit_spec.rb
+++ b/lib/capybara/spec/session/visit_spec.rb
@@ -17,6 +17,15 @@ Capybara::SpecHelper.spec '#visit' do
     @session.should have_content('Another World')
   end
 
+  it "should fetch a response when absolute URI doesn't have a trailing slash" do
+    # Preparation
+    @session.visit('/foo/bar')
+    root_uri = URI.parse(@session.current_url)
+
+    @session.visit("http://localhost:#{root_uri.port}")
+    @session.should have_content('Hello world!')
+  end
+
   context "when Capybara.always_include_port is true" do
 
     let(:root_uri) do
@@ -86,4 +95,11 @@ Capybara::SpecHelper.spec '#visit' do
     @session.find('//input').click
     @session.should have_content %r{http://.*/referer_base}
   end
+
+  it "can set cookie if a blank path is specified" do
+    @session.visit("")
+    @session.visit('/get_cookie')
+    @session.should have_content('root cookie')
+  end
+
 end
diff --git a/lib/capybara/spec/session/within_frame_spec.rb b/lib/capybara/spec/session/within_frame_spec.rb
index bca668c..c64fabc 100644
--- a/lib/capybara/spec/session/within_frame_spec.rb
+++ b/lib/capybara/spec/session/within_frame_spec.rb
@@ -42,4 +42,11 @@ Capybara::SpecHelper.spec '#within_frame', :requires => [:frames] do
       end    
     end
   end
+  it "should reset scope when changing frames" do
+    @session.within(:css, '#divInMainWindow') do
+      @session.within_frame 'parentFrame' do
+        @session.has_selector?(:css, "iframe#childFrame").should be_true
+      end
+    end
+  end
 end
diff --git a/lib/capybara/spec/session/within_window_spec.rb b/lib/capybara/spec/session/within_window_spec.rb
index b031371..d5f2fce 100644
--- a/lib/capybara/spec/session/within_window_spec.rb
+++ b/lib/capybara/spec/session/within_window_spec.rb
@@ -35,4 +35,11 @@ Capybara::SpecHelper.spec '#within_window', :requires => [:windows] do
     end
     @session.find("//*[@id='divInMainWindow']").text.should eql 'This is the text for divInMainWindow'
   end
+  it "should reset scope when switching windows" do
+    @session.within(:css, '#divInMainWindow') do
+      @session.within_window("secondPopup") do
+        @session.find("//*[@id='divInPopupTwo']").text.should eql 'This is the text of divInPopupTwo'
+      end
+    end
+  end
 end
diff --git a/lib/capybara/spec/test_app.rb b/lib/capybara/spec/test_app.rb
index 0f3e7d3..4c2df3f 100644
--- a/lib/capybara/spec/test_app.rb
+++ b/lib/capybara/spec/test_app.rb
@@ -13,6 +13,7 @@ class TestApp < Sinatra::Base
   # Also check lib/capybara/spec/views/*.erb for pages not listed here
 
   get '/' do
+    response.set_cookie('capybara', { value: 'root cookie', domain: request.host, path: request.path} )
     'Hello world! <a href="with_html">Relative</a>'
   end
 
diff --git a/lib/capybara/spec/views/form.erb b/lib/capybara/spec/views/form.erb
index fb9b186..e67f94f 100644
--- a/lib/capybara/spec/views/form.erb
+++ b/lib/capybara/spec/views/form.erb
@@ -137,6 +137,14 @@
   <p>
 
   <p>
+    <label for="form_newline">NewLine</label></br>
+    <textarea name="form[newline]" id="form_newline">
+
+New line after and before textarea tag
+</textarea>
+  </p>
+
+  <p>
     <input type="radio" name="form[gender]" value="male" id="gender_male"/>
     <label for="gender_male">Male</label>
     <input type="radio" name="form[gender]" value="female" id="gender_female" checked="checked"/>
@@ -153,6 +161,13 @@
     <input type="checkbox" value="hamster" name="form[pets][]" id="form_pets_hamster" checked="checked"/>
     <label for="form_pets_hamster">Hamster</label>
   </p>
+  
+  <p>
+    <input type="checkbox" name="form[valueless_checkbox]" id="valueless_checkbox" checked="checked"/>
+    <label for="valueless_checkbox">Valueless Checkbox</label>
+    <input type="radio" name="form[valueless_radio]" id="valueless_radio" checked="checked"/>
+    <label for="valueless_radio">Valueless Radio</label>
+  </p>
 
   <p>
     <label for="form_languages">Languages</label>
@@ -235,6 +250,13 @@
   </p>
 
   <p>
+    <label for="form_disabled_unchecked_checkbox">
+      Disabled Unchecked Checkbox
+      <input type="checkbox" name="form[disabled_unchecked_checkbox]" value="Should not see me" id="form_disabled_unchecked_checkbox" disabled="disabled" />
+    </label>
+  </p>
+
+  <p>
     <label for="form_disabled_radio">
       Disabled Radio
       <input type="radio" name="form[disabled_radio]" value="Should not see me" id="form_disabled_radio" checked="checked" disabled="disabled" />
@@ -283,6 +305,8 @@
   <button type="submit" name="form[other_form_button]" value="other_form_button" form="form1">Form1</button>
 </form>
 
+<button type="submit" name="form[no_form_button]" value="no_form_button">No Form</button>
+
 <textarea name="form[outside_textarea]" form="form1">Some text here</textarea>
 <select name="form[outside_select]" form="form1">
   <option>Lisp</option>
@@ -317,6 +341,20 @@
   <p>
 </form>
 
+<form action="/upload_empty" method="post" enctype="multipart/form-data">
+  <p>
+    <label>
+      <input type="file" name="form[file]" multiple="multiple"/>
+      Multiple empty files
+    </label>
+  </p>
+
+  <p>
+    <input type="hidden" name="form[dummy]" value="ensure params[:form] exists"/>
+    <input type="submit" value="Upload Empty Multiple"/>
+  <p>
+</form>
+
 <form action="/upload" method="post" enctype="multipart/form-data">
   <p>
     <label for="form_file_name">File Name</label>
@@ -402,3 +440,5 @@
     <input type="submit" name="form[no_action]" value="No Action" />
   </p>
 </form>
+
+
diff --git a/lib/capybara/spec/views/with_html.erb b/lib/capybara/spec/views/with_html.erb
index d68a54b..0bb9cc4 100644
--- a/lib/capybara/spec/views/with_html.erb
+++ b/lib/capybara/spec/views/with_html.erb
@@ -66,6 +66,11 @@ banana</textarea>
   <a href="/with_simple_html" title="hidden link" class="simple">hidden link</a>
 </div>
 
+<div id="hidden_attr" hidden="hidden">
+  <a id="hidden_attr_via_ancestor">hidden attribute ancestor link</a>
+</div>
+
+
 <div id="hidden-text">
   Some of this text is <em style="display:none">hidden!</em>
 </div>
diff --git a/lib/capybara/spec/views/with_js.erb b/lib/capybara/spec/views/with_js.erb
index 1fdb228..47ffcd1 100644
--- a/lib/capybara/spec/views/with_js.erb
+++ b/lib/capybara/spec/views/with_js.erb
@@ -37,6 +37,14 @@
     </p>
 
     <p>
+      <div contenteditable='true' id='existing_content_editable'>Editable content</div>
+      <div contenteditable='true' id='blank_content_editable' style='height: 1em;'></div>
+      <div contenteditable='true' style='height: 1em;'>
+        <div id='existing_content_editable_child' style='height: 1em;'>Content</div>
+      </div>
+    </p>
+
+    <p>
       <input type="checkbox" id="checkbox_with_event"/>
     </p>
 
diff --git a/lib/capybara/version.rb b/lib/capybara/version.rb
index 03a4595..560cc3d 100644
--- a/lib/capybara/version.rb
+++ b/lib/capybara/version.rb
@@ -1,3 +1,3 @@
 module Capybara
-  VERSION = '2.1.0'
+  VERSION = '2.2.1'
 end
diff --git a/metadata.gz.sig b/metadata.gz.sig
index 972dcef..806383c 100644
Binary files a/metadata.gz.sig and b/metadata.gz.sig differ
diff --git a/metadata.yml b/metadata.yml
index 9fae951..3a4282c 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,112 +1,95 @@
 --- !ruby/object:Gem::Specification
 name: capybara
 version: !ruby/object:Gem::Version
-  version: 2.1.0
-  prerelease: 
+  version: 2.2.1
 platform: ruby
 authors:
 - Jonas Nicklas
 autorequire: 
 bindir: bin
 cert_chain:
-- !binary |-
-  LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURQRENDQWlTZ0F3SUJB
-  Z0lCQURBTkJna3Foa2lHOXcwQkFRVUZBREJFTVJZd0ZBWURWUVFEREExcWIy
-  NWgKY3k1dWFXTnJiR0Z6TVJVd0V3WUtDWkltaVpQeUxHUUJHUllGWjIxaGFX
-  d3hFekFSQmdvSmtpYUprL0lzWkFFWgpGZ05qYjIwd0hoY05NVE13TWpFMU1q
-  RTFOVE0yV2hjTk1UUXdNakUxTWpFMU5UTTJXakJFTVJZd0ZBWURWUVFECkRB
-  MXFiMjVoY3k1dWFXTnJiR0Z6TVJVd0V3WUtDWkltaVpQeUxHUUJHUllGWjIx
-  aGFXd3hFekFSQmdvSmtpYUoKay9Jc1pBRVpGZ05qYjIwd2dnRWlNQTBHQ1Nx
-  R1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURiOUFaagpnTmRVS0lF
-  Rmt0blJUZXJmWXNDcXBBRlk5N3F0VGJydWo0dUVLSmV5SFJMUjRGTTNzVWU0
-  TjZZYjQ4YTNKTHBBCkhRMUVMaDVjU2RKZHl4OFRFWG1Lc2NycUVjYzJsWFNn
-  YmtvRnB5bzZJQWNFT1NwQzl2bEFleUdwd2tLSS8rYlAKYld3M2pWMjM2cTBD
-  cjdhRk1INm5tVXZKSnNhZE93TnlVWVpXQVRxT3Q2WDNRb0xpRXBoZjdTd2hM
-  ekFaSnI2ZgpIaHZqSjBYbzJ5L0xpSmo5TjBnb09oVUw2dEM1d3M1ajR3eFA4
-  WitZRlkwUTd4N1E2UlFCV2NDVWhjL0dBV2V4CjBlWFJqMlFPVHpWcnJJT25Q
-  TjFqcWlmbnFxVTMwWW9NRk1oL2U2bzN4L3ppWU1uN3pBYkZYU2J0WERLQ0s0
-  QlQKM3pHWmdDaXVlY3NwSHk5L0FnTUJBQUdqT1RBM01Ba0dBMVVkRXdRQ01B
-  QXdIUVlEVlIwT0JCWUVGUGI4K0RZMApmbTlCWmxkYy9lYUtaeGZJNlh1Y01B
-  c0dBMVVkRHdRRUF3SUVzREFOQmdrcWhraUc5dzBCQVFVRkFBT0NBUUVBCkp0
-  WnJqZDlEczVyY0JWUDJMOXZFYTZGMm9zZXE3eWU4YmF2UW85VWg4MWZEQ2JW
-  ZG5hWlBoeU10aDVRaGRJQkwKcEcrdWFmQ01BZmdVMHZRZU5YbkF6SXhtbHRu
-  UDQrZTNJd1IwT2UyMWVVRDZsU1BTdkNvSWFRMmVEVnhvSFBQSgo1TnJKS3hq
-  MnV1TlYxeUdMbVZoWFVGRVQwT2tWdkJnZHhObXRiRTJyUmJ4WGp2NXhxVzZu
-  QnNnVkF6MHFTeEIzCjl5RFRaS1c3KytFbSt5RnVmTWxEcjcrMXJsOGNUeHYx
-  S2o0M0dldTVMVno3bi9sSFlLQWRqZTR1SjNlQnRhZ0kKZHdDSTZtbGVYT3I0
-  TVNSZXpmMTlaVUZyMENxbEZjcnBCU3lPYWtTdFFMTThMYTNFQW1oT0VVYTJV
-  RTJGSWdxNQpSMVNIMW5pKzNiSDdCNHRBa2JXc2tnPT0KLS0tLS1FTkQgQ0VS
-  VElGSUNBVEUtLS0tLQo=
-date: 2013-04-09 00:00:00.000000000 Z
+- |
+  -----BEGIN CERTIFICATE-----
+  MIIDPDCCAiSgAwIBAgIBADANBgkqhkiG9w0BAQUFADBEMRYwFAYDVQQDDA1qb25h
+  cy5uaWNrbGFzMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZ
+  FgNjb20wHhcNMTMwMjE1MjE1NTM2WhcNMTQwMjE1MjE1NTM2WjBEMRYwFAYDVQQD
+  DA1qb25hcy5uaWNrbGFzMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJ
+  k/IsZAEZFgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDb9AZj
+  gNdUKIEFktnRTerfYsCqpAFY97qtTbruj4uEKJeyHRLR4FM3sUe4N6Yb48a3JLpA
+  HQ1ELh5cSdJdyx8TEXmKscrqEcc2lXSgbkoFpyo6IAcEOSpC9vlAeyGpwkKI/+bP
+  bWw3jV236q0Cr7aFMH6nmUvJJsadOwNyUYZWATqOt6X3QoLiEphf7SwhLzAZJr6f
+  HhvjJ0Xo2y/LiJj9N0goOhUL6tC5ws5j4wxP8Z+YFY0Q7x7Q6RQBWcCUhc/GAWex
+  0eXRj2QOTzVrrIOnPN1jqifnqqU30YoMFMh/e6o3x/ziYMn7zAbFXSbtXDKCK4BT
+  3zGZgCiuecspHy9/AgMBAAGjOTA3MAkGA1UdEwQCMAAwHQYDVR0OBBYEFPb8+DY0
+  fm9BZldc/eaKZxfI6XucMAsGA1UdDwQEAwIEsDANBgkqhkiG9w0BAQUFAAOCAQEA
+  JtZrjd9Ds5rcBVP2L9vEa6F2oseq7ye8bavQo9Uh81fDCbVdnaZPhyMth5QhdIBL
+  pG+uafCMAfgU0vQeNXnAzIxmltnP4+e3IwR0Oe21eUD6lSPSvCoIaQ2eDVxoHPPJ
+  5NrJKxj2uuNV1yGLmVhXUFET0OkVvBgdxNmtbE2rRbxXjv5xqW6nBsgVAz0qSxB3
+  9yDTZKW7++Em+yFufMlDr7+1rl8cTxv1Kj43Geu5LVz7n/lHYKAdje4uJ3eBtagI
+  dwCI6mleXOr4MSRezf19ZUFr0CqlFcrpBSyOakStQLM8La3EAmhOEUa2UE2FIgq5
+  R1SH1ni+3bH7B4tAkbWskg==
+  -----END CERTIFICATE-----
+date: 2014-01-06 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
   name: nokogiri
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 1.3.3
   type: :runtime
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 1.3.3
 - !ruby/object:Gem::Dependency
   name: mime-types
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: '1.16'
   type: :runtime
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: '1.16'
 - !ruby/object:Gem::Dependency
   name: rack
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 1.0.0
   type: :runtime
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 1.0.0
 - !ruby/object:Gem::Dependency
   name: rack-test
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 0.5.4
   type: :runtime
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 0.5.4
 - !ruby/object:Gem::Dependency
   name: xpath
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
     - - ~>
       - !ruby/object:Gem::Version
@@ -114,7 +97,6 @@ dependencies:
   type: :runtime
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
     - - ~>
       - !ruby/object:Gem::Version
@@ -122,7 +104,6 @@ dependencies:
 - !ruby/object:Gem::Dependency
   name: selenium-webdriver
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
     - - ~>
       - !ruby/object:Gem::Version
@@ -130,7 +111,6 @@ dependencies:
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
     - - ~>
       - !ruby/object:Gem::Version
@@ -138,129 +118,113 @@ dependencies:
 - !ruby/object:Gem::Dependency
   name: sinatra
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 0.9.4
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 0.9.4
 - !ruby/object:Gem::Dependency
   name: rspec
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 2.2.0
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 2.2.0
 - !ruby/object:Gem::Dependency
   name: launchy
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 2.0.4
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 2.0.4
 - !ruby/object:Gem::Dependency
   name: yard
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 0.5.8
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 0.5.8
 - !ruby/object:Gem::Dependency
   name: fuubar
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 0.0.1
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 0.0.1
 - !ruby/object:Gem::Dependency
   name: cucumber
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 0.10.5
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: 0.10.5
 - !ruby/object:Gem::Dependency
   name: rake
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: '0'
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: '0'
 - !ruby/object:Gem::Dependency
   name: pry
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: '0'
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - '>='
       - !ruby/object:Gem::Version
         version: '0'
 description: Capybara is an integration testing tool for rack based web applications.
@@ -325,6 +289,8 @@ files:
 - lib/capybara/spec/session/find_link_spec.rb
 - lib/capybara/spec/session/find_spec.rb
 - lib/capybara/spec/session/first_spec.rb
+- lib/capybara/spec/session/go_back_spec.rb
+- lib/capybara/spec/session/go_forward_spec.rb
 - lib/capybara/spec/session/has_button_spec.rb
 - lib/capybara/spec/session/has_css_spec.rb
 - lib/capybara/spec/session/has_field_spec.rb
@@ -391,40 +357,35 @@ files:
 - spec/rspec/matchers_spec.rb
 - spec/rspec_spec.rb
 - spec/selenium_spec.rb
+- spec/selenium_spec_chrome.rb
 - spec/server_spec.rb
 - spec/spec_helper.rb
 - README.md
 - History.md
 - License.txt
 homepage: http://github.com/jnicklas/capybara
-licenses: []
-post_install_message: ! "IMPORTANT! Some of the defaults have changed in Capybara
-  2.1. If you're experiencing failures,\nplease revert to the old behaviour by setting:\n\n
-  \   Capybara.configure do |config|\n      config.match = :one\n      config.exact_options
-  = true\n      config.ignore_hidden_elements = true\n      config.visible_text_only
-  = true\n    end\n\nIf you're migrating from Capybara 1.x, try:\n\n    Capybara.configure
-  do |config|\n      config.match = :prefer_exact\n      config.ignore_hidden_elements
-  = false\n    end\n\nDetails here: http://www.elabs.se/blog/60-introducing-capybara-2-1\n\n"
+licenses:
+- MIT
+metadata: {}
+post_install_message: 
 rdoc_options: []
 require_paths:
 - lib
 required_ruby_version: !ruby/object:Gem::Requirement
-  none: false
   requirements:
-  - - ! '>='
+  - - '>='
     - !ruby/object:Gem::Version
       version: 1.9.3
 required_rubygems_version: !ruby/object:Gem::Requirement
-  none: false
   requirements:
-  - - ! '>='
+  - - '>='
     - !ruby/object:Gem::Version
       version: '0'
 requirements: []
 rubyforge_project: capybara
-rubygems_version: 1.8.25
+rubygems_version: 2.0.6
 signing_key: 
-specification_version: 3
+specification_version: 4
 summary: Capybara aims to simplify the process of integration testing Rack applications,
   such as Rails, Sinatra or Merb
 test_files: []
diff --git a/spec/capybara_spec.rb b/spec/capybara_spec.rb
index d147c7b..548de2b 100644
--- a/spec/capybara_spec.rb
+++ b/spec/capybara_spec.rb
@@ -31,7 +31,7 @@ describe Capybara do
     end
 
     it "should default to a proc that calls run_default_server" do
-      mock_app = mock('app')
+      mock_app = double('app')
       Capybara.should_receive(:run_default_server).with(mock_app, 8000)
       Capybara.server.call(mock_app, 8000)
     end
diff --git a/spec/result_spec.rb b/spec/result_spec.rb
index 82de3a6..f0d0cd9 100644
--- a/spec/result_spec.rb
+++ b/spec/result_spec.rb
@@ -28,6 +28,10 @@ describe Capybara::Result do
     result.last.text == 'Delta'
   end
 
+  it 'can supports values_at method' do
+    result.values_at(0, 2).map(&:text).should == %w(Alpha Gamma)
+  end
+
   it "can return an element by its index" do
     result.at(1).text.should == 'Beta'
     result[2].text.should == 'Gamma'
@@ -48,4 +52,14 @@ describe Capybara::Result do
       memo += element.text[0]
     end.should == 'ABGD'
   end
+
+  it 'can be sampled' do
+    result.should include(result.sample)
+  end
+
+  it 'can be indexed' do
+    result.index do |el|
+      el.text == 'Gamma'
+    end.should == 2
+  end
 end
diff --git a/spec/rspec/features_spec.rb b/spec/rspec/features_spec.rb
index a277795..ee23bff 100644
--- a/spec/rspec/features_spec.rb
+++ b/spec/rspec/features_spec.rb
@@ -34,6 +34,21 @@ feature "Capybara's feature DSL" do
   scenario "doesn't pollute the Object namespace" do
     Object.new.respond_to?(:feature, true).should be_false
   end
+
+  feature 'nested features' do
+    scenario 'work as expected' do
+      visit '/'
+      page.should have_content 'Hello world!'
+    end
+
+    scenario 'are marked in the metadata as capybara_feature' do
+      example.metadata[:capybara_feature].should be_true
+    end
+
+    scenario 'have a type of :feature' do
+      example.metadata[:type].should eq :feature
+    end
+  end
 end
 
 feature "given and given! aliases to let and let!" do
diff --git a/spec/rspec/matchers_spec.rb b/spec/rspec/matchers_spec.rb
index cb6a977..2914bc6 100644
--- a/spec/rspec/matchers_spec.rb
+++ b/spec/rspec/matchers_spec.rb
@@ -519,21 +519,44 @@ describe Capybara::RSpecMatchers do
   end
 
   describe "have_field matcher" do
-    let(:html) { '<p><label>Text field<input type="text"/></label></p>' }
+    let(:html) { '<p><label>Text field<input type="text" value="some value"/></label></p>' }
 
     it "gives proper description" do
       have_field('Text field').description.should == "have field \"Text field\""
     end
 
+    it "gives proper description for a given value" do
+      have_field('Text field', with: 'some value').description.should == "have field \"Text field\" with value \"some value\""
+    end
+
     it "passes if there is such a field" do
       html.should have_field('Text field')
     end
 
+    it "passes if there is such a field with value" do
+      html.should have_field('Text field', with: 'some value')
+    end
+
     it "fails if there is no such field" do
       expect do
         html.should have_field('No such Field')
       end.to raise_error(/expected to find field "No such Field"/)
     end
+
+    it "fails if there is such field but with false value" do
+      expect do
+        html.should have_field('Text field', with: 'false value')
+      end.to raise_error(/expected to find field "Text field"/)
+    end
+
+    it "treats a given value as a string" do
+      class Foo
+        def to_s
+          "some value"
+        end
+      end
+      html.should have_field('Text field', with: Foo.new)
+    end
   end
 
   describe "have_checked_field matcher" do
diff --git a/spec/selenium_spec.rb b/spec/selenium_spec.rb
index 7de2545..6b94d59 100644
--- a/spec/selenium_spec.rb
+++ b/spec/selenium_spec.rb
@@ -1,7 +1,14 @@
 require 'spec_helper'
+require "selenium-webdriver"
+
+Capybara.register_driver :selenium_focus do |app|
+  profile = Selenium::WebDriver::Firefox::Profile.new
+  profile["focusmanager.testmode"] = true
+  Capybara::Selenium::Driver.new(app, browser: :firefox, profile: profile)
+end
 
 module TestSessions
-  Selenium = Capybara::Session.new(:selenium, TestApp)
+  Selenium = Capybara::Session.new(:selenium_focus, TestApp)
 end
 
 Capybara::SpecHelper.run_specs TestSessions::Selenium, "selenium", :skip => [
@@ -24,7 +31,7 @@ describe Capybara::Session do
 
     describe '#mode' do
       it "should remember the mode" do
-        @session.mode.should == :selenium
+        @session.mode.should == :selenium_focus
       end
     end
 
diff --git a/spec/selenium_spec_chrome.rb b/spec/selenium_spec_chrome.rb
new file mode 100644
index 0000000..3729008
--- /dev/null
+++ b/spec/selenium_spec_chrome.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+Capybara.register_driver :selenium_chrome do |app|
+  args = ENV['TRAVIS'] ? ['no-sandbox' ] : []
+  Capybara::Selenium::Driver.new(app, :browser => :chrome, :args => args)
+end
+
+class ChromeTestApp < TestApp
+  # Object.id is different from the TestApp used in firefox session so 
+  # a new Capybar::Server instance will get launched for chrome testing
+end
+
+module TestSessions
+  Chrome = Capybara::Session.new(:selenium_chrome, ChromeTestApp)
+end
+
+Capybara::SpecHelper.run_specs TestSessions::Chrome, "selenium_chrome", :skip => [
+  :response_headers,
+  :status_code,
+  :trigger  
+]
diff --git a/spec/server_spec.rb b/spec/server_spec.rb
index 13e4124..9012edd 100644
--- a/spec/server_spec.rb
+++ b/spec/server_spec.rb
@@ -18,13 +18,21 @@ describe Capybara::Server do
   end
 
   it "should bind to the specified host" do
-    Capybara.server_host = '0.0.0.0'
+    begin
+      app = proc { |env| [200, {}, ['Hello Server!']] }
 
-    app = proc { |env| [200, {}, ["Hello Server!"]]}
-    server = Capybara::Server.new(app).boot
-    server.host.should == '0.0.0.0'
+      Capybara.server_host = '127.0.0.1'
+      server = Capybara::Server.new(app).boot
+      res = Net::HTTP.get(URI("http://127.0.0.1:#{server.port}"))
+      expect(res).to eq('Hello Server!')
 
-    Capybara.server_host = nil
+      Capybara.server_host = '0.0.0.0'
+      server = Capybara::Server.new(app).boot
+      res = Net::HTTP.get(URI("http://127.0.0.1:#{server.port}"))
+      expect(res).to eq('Hello Server!')
+    ensure
+      Capybara.server_host = nil
+    end
   end
 
   it "should use specified port" do

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-capybara.git



More information about the Pkg-ruby-extras-commits mailing list