Merge branch 'master' of github.com:jnicklas/capybara

This commit is contained in:
Jonas Nicklas 2011-01-17 09:00:15 +01:00
commit 282ffa48d4
30 changed files with 499 additions and 70 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "xpath"]
path = xpath
url = git://github.com/jnicklas/xpath.git

View File

@ -1,5 +1,7 @@
source :rubygems
gem 'bundler', '~> 1.0'
gem 'xpath', :path => '../xpath' if ENV['XPATH_LOCAL']
gemspec
@dependencies.delete_if {|d| d.name == "xpath" }
gem 'xpath', :path => 'xpath'

View File

@ -1,7 +1,7 @@
PATH
remote: .
specs:
capybara (0.4.0)
capybara (0.4.1.rc)
celerity (>= 0.7.9)
culerity (>= 0.2.4)
mime-types (>= 1.16)
@ -9,7 +9,13 @@ PATH
rack (>= 1.0.0)
rack-test (>= 0.5.4)
selenium-webdriver (>= 0.0.27)
xpath (~> 0.1.2)
xpath (~> 0.1.3)
PATH
remote: xpath
specs:
xpath (0.1.3)
nokogiri (~> 1.3)
GEM
remote: http://rubygems.org/
@ -58,8 +64,6 @@ GEM
sinatra (1.0)
rack (>= 1.0)
weakling (0.0.4-java)
xpath (0.1.2)
nokogiri (~> 1.3)
yard (0.6.1)
PLATFORMS
@ -80,5 +84,5 @@ DEPENDENCIES
rspec (>= 2.0.0)
selenium-webdriver (>= 0.0.27)
sinatra (>= 0.9.4)
xpath (~> 0.1.2)
xpath!
yard (>= 0.5.8)

View File

@ -4,7 +4,34 @@ Release date:
### Added
* New click_on alias for click_link_or_button, shorter yet unambiguous.
* New click_on alias for click_link_or_button, shorter yet unambiguous. [Jonas Nicklas]
* Finders now accept :visible => false which will find all elements regardless of Capybara.ignore_hidden_elements [Jonas Nicklas]
* Configure how the server is started via Capybara.server { |app, port| ... }. [John Firebough]
* Added :between, :maximum and :minimum options to has_selector and friends [James B. Byrne]
* New Capybara.string util function which allows matchers on arbitrary strings, mostly for helper and view specs [David Chelimsky and Jonas Nicklas]
* Server boot timeout is now configurable, via Capybara.server_boot_timeout [Adam Cigánek]
* Built in support for RSpec [Jonas Nicklas]
* Capybara.using_driver to switch to a different driver temporarily [Jeff Kreeftmeijer]
* Added Session#first which is somewhat speedier than Session#all, use it internally for speed boost [John Firebaugh]
### Changed
* Session#within now accepts the same arguments as other finders, like Session#all and Session#find [Jonas Nicklas]
### Removed
* All deprecations from 0.4.0 have been removed. [Jonas Nicklas]
### Fixed
* Don't mangle URLs in save_and_open_page when using self-closing tags [Adam Spiers]
* Catch correct error when server boot times out [Jonas Nicklas]
* Celerity driver now properly passes through options, making it configurable [Jonas Nicklas]
* Better implementation of attributes in C[ue]lerity, should fix issues with attributes with strange names [Jonas Nicklas]
* Session#find no longer swallows errors [Jonas Nicklas]
* Fix problems with multiple file inputs [Philip Arndt]
* Submit multipart forms as multipart under rack-test even if they contain no files [Ryan Kinderman]
* Matchers like has_select? and has_checked_field? now work with dynamically changed values [John Firebaugh]
# Version 0.4.0

View File

@ -90,6 +90,7 @@ If you prefer RSpec to using Cucumber, you can use the built in RSpec support:
You can now use it in your examples:
describe "the signup process", :type => :acceptance do
it "signs me in" do
within("#session") do
fill_in 'Login', :with => 'user@example.com'
@ -97,8 +98,12 @@ You can now use it in your examples:
end
click_link 'Sign in'
end
end
RSpec's metadata feature can be used to switch to a different driver. Use the
Capybara is only included for examples which have the type
<tt>:acceptance</tt>.
RSpec's metadata feature can be used to switch to a different driver. Use
<tt>:js => true</tt> to switch to the javascript driver, or provide a
<tt>:driver</tt> option to switch to one specific driver. For example:
@ -483,6 +488,9 @@ 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.
The {Selenium wiki}[http://code.google.com/p/selenium/wiki/RubyBindings] has
additional info about how the underlying driver can be configured.
== Gotchas:
* Access to session and request is not possible from the test, Access to

View File

@ -29,7 +29,7 @@ Gem::Specification.new do |s|
s.add_runtime_dependency("selenium-webdriver", [">= 0.0.27"])
s.add_runtime_dependency("rack", [">= 1.0.0"])
s.add_runtime_dependency("rack-test", [">= 0.5.4"])
s.add_runtime_dependency("xpath", ["~> 0.1.2"]) unless ENV['XPATH_LOCAL']
s.add_runtime_dependency("xpath", ["~> 0.1.3"])
s.add_development_dependency("sinatra", [">= 0.9.4"])
s.add_development_dependency("rspec", [">= 2.0.0"])

View File

@ -11,7 +11,7 @@ class Capybara::Driver::Celerity < Capybara::Driver::Base
def value
if tag_name == "select" and native.multiple?
find(".//option[@selected]").map { |n| n.value || n.text }
find(".//option[@selected]").map { |n| if n.has_value? then n.value else n.text end }
else
native.value
end
@ -56,6 +56,18 @@ class Capybara::Driver::Celerity < Capybara::Driver::Base
native.visible?
end
def checked?
native.checked?
rescue # https://github.com/langalex/culerity/issues/issue/33
false
end
def selected?
native.selected?
rescue # https://github.com/langalex/culerity/issues/issue/33
false
end
def path
native.xpath
end
@ -77,7 +89,9 @@ class Capybara::Driver::Celerity < Capybara::Driver::Base
find('./ancestor::select').first
end
def has_value?
native.object.hasAttribute('value')
end
end
attr_reader :app, :rack_server, :options

View File

@ -48,6 +48,14 @@ module Capybara
raise NotImplementedError
end
def checked?
raise NotImplementedError
end
def selected?
raise NotImplementedError
end
def path
raise NotSupportedByDriverError
end

View File

@ -68,6 +68,14 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
string_node.visible?
end
def checked?
self[:checked]
end
def selected?
self[:selected]
end
def path
native.path
end
@ -97,6 +105,21 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
end
class Form < Node
# This only needs to inherit from Rack::Test::UploadedFile because Rack::Test checks for
# the class specifically when determing whether to consturct the request as multipart.
# That check should be based solely on the form element's 'enctype' attribute value,
# which should probably be provided to Rack::Test in its non-GET request methods.
class NilUploadedFile < Rack::Test::UploadedFile
def initialize
@empty_file = Tempfile.new("nil_uploaded_file")
@empty_file.close
end
def original_filename; ""; end
def content_type; "application/octet-stream"; end
def path; @empty_file.path; end
end
def params(button)
params = {}
@ -122,16 +145,19 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
end
end
native.xpath(".//input[not(@disabled) and @type='file']").map do |input|
unless input['value'].to_s.empty?
if multipart?
content_type = MIME::Types.type_for(input['value'].to_s).first.to_s
file = Rack::Test::UploadedFile.new(input['value'].to_s, content_type)
file = \
if (value = input['value']).to_s.empty?
NilUploadedFile.new
else
content_type = MIME::Types.type_for(value).first.to_s
Rack::Test::UploadedFile.new(value, content_type)
end
merge_param!(params, input['name'].to_s, file)
else
merge_param!(params, input['name'].to_s, File.basename(input['value'].to_s))
end
end
end
merge_param!(params, button[:name], button[:value] || "") if button[:name]
params
end

View File

@ -43,7 +43,7 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
if select_node['multiple'] != 'multiple' and select_node['multiple'] != 'true'
raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
end
native.clear
native.toggle if selected?
end
def click
@ -59,9 +59,17 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
end
def visible?
native.displayed? and native.displayed? != "false"
displayed = native.displayed?
displayed and displayed != "false"
end
def selected?
selected = native.selected?
selected and selected != "false"
end
alias :checked? :selected?
def find(locator)
native.find_elements(:xpath, locator).map { |n| self.class.new(driver, n) }
end
@ -83,7 +91,7 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
def browser
unless @browser
@browser = Selenium::WebDriver.for(options.delete(:browser) || :firefox, options)
@browser = Selenium::WebDriver.for(options[:browser] || :firefox, options)
at_exit do
@browser.quit
end

View File

@ -112,6 +112,26 @@ module Capybara
base.visible?
end
##
#
# Whether or not the element is checked.
#
# @return [Boolean] Whether the element is checked
#
def checked?
base.checked?
end
##
#
# Whether or not the element is selected.
#
# @return [Boolean] Whether the element is selected
#
def selected?
base.selected?
end
##
#
# An XPath expression describing where on the page the element can be found

View File

@ -24,7 +24,10 @@ module Capybara
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
#
def find(*args)
node = wait_conditionally_until { all(*args).first }
begin
node = wait_conditionally_until { first(*args) }
rescue TimeoutError
end
unless node
options = if args.last.is_a?(Hash) then args.last else {} end
raise Capybara::ElementNotFound, options[:message] || "Unable to find '#{args[1] || args[0]}'"
@ -112,23 +115,39 @@ module Capybara
# @return [Capybara::Element] The found elements
#
def all(*args)
options = if args.last.is_a?(Hash) then args.pop else {} end
options = extract_normalized_options(args)
results = Capybara::Selector.normalize(*args).map do |path|
find_in_base(path)
end.flatten
if text = options[:text]
text = Regexp.escape(text) unless text.kind_of?(Regexp)
results = results.select { |node| node.text.match(text) }
Capybara::Selector.normalize(*args).
map { |path| find_in_base(path) }.flatten.
select { |node| matches_options(node, options) }.
map { |node| convert_element(node) }
end
if options[:visible] or Capybara.ignore_hidden_elements
results = results.select { |node| node.visible? }
##
#
# Find the first element on the page matching the given selector
# and options, or nil if no element matches.
#
# When only the first matching element is needed, this method can
# be faster than all(*args).first.
#
# @param [:css, :xpath, String] kind_or_locator Either the kind of selector or the selector itself
# @param [String] locator The selector
# @param [Hash{Symbol => Object}] options Additional options; see {all}
# @return Capybara::Element The found element
#
def first(*args)
options = extract_normalized_options(args)
Capybara::Selector.normalize(*args).each do |path|
find_in_base(path).each do |node|
if matches_options(node, options)
return convert_element(node)
end
end
end
convert_elements(results)
nil
end
protected
@ -137,14 +156,46 @@ module Capybara
base.find(xpath)
end
def convert_elements(elements)
elements.map { |element| Capybara::Node::Element.new(session, element) }
def convert_element(element)
Capybara::Node::Element.new(session, element)
end
def wait_conditionally_until
if wait? then session.wait_until { yield } else yield end
end
def extract_normalized_options(args)
options = if args.last.is_a?(Hash) then args.pop.dup else {} end
if text = options[:text]
options[:text] = Regexp.escape(text) unless text.kind_of?(Regexp)
end
if !options.has_key?(:visible)
options[:visible] = Capybara.ignore_hidden_elements
end
if selected = options[:selected]
options[:selected] = [selected].flatten
end
options
end
def matches_options(node, options)
return false if options[:text] and not node.text.match(options[:text])
return false if options[:visible] and not node.visible?
return false if options[:with] and not node.value == options[:with]
return false if options[:checked] and not node.checked?
return false if options[:unchecked] and node.checked?
return false if options[:selected] and not has_selected_options?(node, options[:selected])
true
end
def has_selected_options?(node, expected)
actual = node.find('.//option').select { |option| option.selected? }.map { |option| option.text }
(expected - actual).empty?
end
end
end
end

View File

@ -262,7 +262,8 @@ module Capybara
# @return [Boolean] Whether it exists
#
def has_field?(locator, options={})
has_xpath?(XPath::HTML.field(locator, options))
options, with = split_options(options, :with)
has_xpath?(XPath::HTML.field(locator, options), with)
end
##
@ -275,7 +276,8 @@ module Capybara
# @return [Boolean] Whether it doesn't exist
#
def has_no_field?(locator, options={})
has_no_xpath?(XPath::HTML.field(locator, options))
options, with = split_options(options, :with)
has_no_xpath?(XPath::HTML.field(locator, options), with)
end
##
@ -288,7 +290,7 @@ module Capybara
# @return [Boolean] Whether it exists
#
def has_checked_field?(locator)
has_xpath?(XPath::HTML.field(locator, :checked => true))
has_xpath?(XPath::HTML.field(locator), :checked => true)
end
##
@ -301,7 +303,7 @@ module Capybara
# @return [Boolean] Whether it exists
#
def has_unchecked_field?(locator)
has_xpath?(XPath::HTML.field(locator, :unchecked => true))
has_xpath?(XPath::HTML.field(locator), :unchecked => true)
end
##
@ -328,7 +330,8 @@ module Capybara
# @return [Boolean] Whether it exists
#
def has_select?(locator, options={})
has_xpath?(XPath::HTML.select(locator, options))
options, selected = split_options(options, :selected)
has_xpath?(XPath::HTML.select(locator, options), selected)
end
##
@ -340,7 +343,8 @@ module Capybara
# @return [Boolean] Whether it doesn't exist
#
def has_no_select?(locator, options={})
has_no_xpath?(XPath::HTML.select(locator, options))
options, selected = split_options(options, :selected)
has_no_xpath?(XPath::HTML.select(locator, options), selected)
end
##
@ -375,6 +379,13 @@ module Capybara
def has_no_table?(locator, options={})
has_no_xpath?(XPath::HTML.table(locator, options))
end
protected
def split_options(options, key)
options = options.dup
[options, if options.has_key?(key) then {key => options.delete(key)} else {} end]
end
end
end
end

View File

@ -104,8 +104,8 @@ module Capybara
native.xpath(xpath).map { |node| self.class.new(node) }
end
def convert_elements(elements)
elements
def convert_element(element)
element
end
def wait?

View File

@ -2,13 +2,17 @@ require 'capybara'
require 'capybara/dsl'
RSpec.configure do |config|
config.include Capybara
config.include Capybara, :type => :acceptance
config.after do
if example.metadata[:type] == :acceptance
Capybara.reset_sessions!
Capybara.use_default_driver
end
end
config.before do
if example.metadata[:type] == :acceptance
Capybara.current_driver = Capybara.javascript_driver if example.metadata[:js]
Capybara.current_driver = example.metadata[:driver] if example.metadata[:driver]
end
end
end

View File

@ -27,7 +27,7 @@ module Capybara
#
class Session
DSL_METHODS = [
:all, :attach_file, :body, :check, :choose, :click_link_or_button, :click_button, :click_link, :current_url, :drag, :evaluate_script,
:all, :first, :attach_file, :body, :check, :choose, :click_link_or_button, :click_button, :click_link, :current_url, :drag, :evaluate_script,
:field_labeled, :fill_in, :find, :find_button, :find_by_id, :find_field, :find_link, :has_content?, :has_css?,
:has_no_content?, :has_no_css?, :has_no_xpath?, :has_xpath?, :locate, :save_and_open_page, :select, :source, :uncheck,
:visit, :wait_until, :within, :within_fieldset, :within_table, :within_frame, :within_window, :has_link?, :has_no_link?, :has_button?,
@ -151,11 +151,11 @@ module Capybara
# fill_in('Street', :with => '12 Main Street')
# end
#
# @param [:css, :xpath, String] kind The type of selector or the selector if the second argument is blank
# @param [String] selector The selector within which to execute the given block
# @param (see Capybara::Node::Finders#all)
# @raise [Capybara::ElementNotFound] If the scope can't be found before time expires
#
def within(kind, selector=nil)
new_scope = find(kind, selector, :message => "scope '#{selector || kind}' not found on page")
def within(*args)
new_scope = find(*args)
begin
scopes.push(new_scope)
yield

View File

@ -71,6 +71,20 @@ shared_examples_for 'driver' do
@driver.find('//div[@id="hidden"]')[0].should_not be_visible
@driver.find('//div[@id="hidden_via_ancestor"]')[0].should_not be_visible
end
it "should extract node checked state" do
@driver.visit('/form')
@driver.find('//input[@id="gender_female"]')[0].should be_checked
@driver.find('//input[@id="gender_male"]')[0].should_not be_checked
@driver.find('//h1')[0].should_not be_checked
end
it "should extract node selected state" do
@driver.visit('/form')
@driver.find('//option[@value="en"]')[0].should be_selected
@driver.find('//option[@value="sv"]')[0].should_not be_selected
@driver.find('//h1')[0].should_not be_selected
end
end
end
end
@ -104,7 +118,7 @@ end
shared_examples_for "driver with header support" do
it "should make headers available through response_headers" do
@driver.visit('/with_simple_html')
@driver.response_headers['Content-Type'].should == 'text/html'
@driver.response_headers['Content-Type'].should =~ /text\/html/
end
end

View File

@ -42,6 +42,7 @@ shared_examples_for "session" do
end
it_should_behave_like "all"
it_should_behave_like "first"
it_should_behave_like "attach_file"
it_should_behave_like "check"
it_should_behave_like "choose"

View File

@ -56,6 +56,11 @@ shared_examples_for "all" do
Capybara.ignore_hidden_elements = true
@session.all("//a[@title='awesome title']").should have(1).elements
end
it "should only find invisible nodes" do
Capybara.ignore_hidden_elements = true
@session.all("//a[@title='awesome title']", :visible => false).should have(2).elements
end
end
context "within a scope" do

View File

@ -0,0 +1,72 @@
shared_examples_for "first" do
describe '#first' do
before do
@session.visit('/with_html')
end
it "should find the first element using the given locator" do
@session.first('//h1').text.should == 'This is a test'
@session.first("//input[@id='test_field']")[:value].should == 'monkey'
end
it "should return nil when nothing was found" do
@session.first('//div[@id="nosuchthing"]').should be_nil
end
it "should accept an XPath instance" do
@session.visit('/form')
@xpath = XPath::HTML.fillable_field('Name')
@session.first(@xpath).value.should == 'John Smith'
end
context "with css selectors" do
it "should find the first element using the given selector" do
@session.first(:css, 'h1').text.should == 'This is a test'
@session.first(:css, "input[id='test_field']")[:value].should == 'monkey'
end
end
context "with xpath selectors" do
it "should find the first element using the given locator" do
@session.first(:xpath, '//h1').text.should == 'This is a test'
@session.first(:xpath, "//input[@id='test_field']")[:value].should == 'monkey'
end
end
context "with css as default selector" do
before { Capybara.default_selector = :css }
it "should find the first element using the given locator" do
@session.first('h1').text.should == 'This is a test'
@session.first("input[id='test_field']")[:value].should == 'monkey'
end
after { Capybara.default_selector = :xpath }
end
context "with visible filter" do
after { Capybara.ignore_hidden_elements = false }
it "should only find visible nodes" do
@session.first(:css, "a.visibility").should_not be_visible
@session.first(:css, "a.visibility", :visible => true).should be_visible
Capybara.ignore_hidden_elements = true
@session.first(:css, "a.visibility").should be_visible
end
it "should only find invisible nodes" do
Capybara.ignore_hidden_elements = true
@session.first(:css, "a.visibility", :visible => false).should_not be_visible
end
end
context "within a scope" do
before do
@session.visit('/with_scope')
end
it "should find the first element using the given locator" do
@session.within(:xpath, "//div[@id='for_bar']") do
@session.first('.//form').should_not be_nil
end
end
end
end
end

View File

@ -25,6 +25,16 @@ shared_examples_for "has_field" do
@session.should_not have_field('Wrong Name', :with => 'John')
@session.should_not have_field('Description', :with => 'Monkey')
end
it "should be true after the field has been filled in with the given value" do
@session.fill_in('First Name', :with => 'Jonas')
@session.should have_field('First Name', :with => 'Jonas')
end
it "should be false after the field has been filled in with a different value" do
@session.fill_in('First Name', :with => 'Jonas')
@session.should_not have_field('First Name', :with => 'John')
end
end
end
@ -54,6 +64,16 @@ shared_examples_for "has_field" do
@session.should have_no_field('Wrong Name', :with => 'John')
@session.should have_no_field('Description', :with => 'Monkey')
end
it "should be false after the field has been filled in with the given value" do
@session.fill_in('First Name', :with => 'Jonas')
@session.should_not have_no_field('First Name', :with => 'Jonas')
end
it "should be true after the field has been filled in with a different value" do
@session.fill_in('First Name', :with => 'Jonas')
@session.should have_no_field('First Name', :with => 'John')
end
end
end
@ -73,6 +93,26 @@ shared_examples_for "has_field" do
it "should be false if no field is on the page" do
@session.should_not have_checked_field('Does Not Exist')
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')
end
it "should be false after a checked checkbox is unchecked" do
@session.uncheck('form_pets_dog')
@session.should_not have_checked_field('form_pets_dog')
end
it "should be true after an unchecked radio button is chosen" do
@session.choose('gender_male')
@session.should have_checked_field('gender_male')
end
it "should be false after another radio button in the group is chosen" do
@session.choose('gender_male')
@session.should_not have_checked_field('gender_female')
end
end
describe '#has_unchecked_field?' do
@ -91,6 +131,26 @@ shared_examples_for "has_field" do
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 after an unchecked checkbox is checked" do
@session.check('form_pets_cat')
@session.should_not have_unchecked_field('form_pets_cat')
end
it "should be true after a checked checkbox is unchecked" do
@session.uncheck('form_pets_dog')
@session.should have_unchecked_field('form_pets_dog')
end
it "should be false after an unchecked radio button is chosen" do
@session.choose('gender_male')
@session.should_not have_unchecked_field('gender_male')
end
it "should be true after another radio button in the group is chosen" do
@session.choose('gender_male')
@session.should have_unchecked_field('gender_female')
end
end
end

View File

@ -26,6 +26,26 @@ shared_examples_for "has_select" do
@session.should_not have_select('Underwear', :selected => ['Briefs', 'Nonexistant'])
@session.should_not have_select('Underwear', :selected => ['Briefs', 'Boxers'])
end
it "should be true after the given value is selected" do
@session.select('Swedish', :from => 'Locale')
@session.should have_select('Locale', :selected => 'Swedish')
end
it "should be false after a different value is selected" do
@session.select('Swedish', :from => 'Locale')
@session.should_not have_select('Locale', :selected => 'English')
end
it "should be true after the given values are selected" do
@session.select('Boxers', :from => 'Underwear')
@session.should have_select('Underwear', :selected => ['Briefs', 'Boxers', 'Commando'])
end
it "should be false after one of the values is unselected" do
@session.unselect('Briefs', :from => 'Underwear')
@session.should_not have_select('Underwear', :selected => ['Briefs', 'Commando'])
end
end
context 'with options' do
@ -69,6 +89,26 @@ shared_examples_for "has_select" do
@session.should have_no_select('Underwear', :selected => ['Briefs', 'Nonexistant'])
@session.should have_no_select('Underwear', :selected => ['Briefs', 'Boxers'])
end
it "should be false after the given value is selected" do
@session.select('Swedish', :from => 'Locale')
@session.should_not have_no_select('Locale', :selected => 'Swedish')
end
it "should be true after a different value is selected" do
@session.select('Swedish', :from => 'Locale')
@session.should have_no_select('Locale', :selected => 'English')
end
it "should be false after the given values are selected" do
@session.select('Boxers', :from => 'Underwear')
@session.should_not have_no_select('Underwear', :selected => ['Briefs', 'Boxers', 'Commando'])
end
it "should be true after one of the values is unselected" do
@session.unselect('Briefs', :from => 'Underwear')
@session.should have_no_select('Underwear', :selected => ['Briefs', 'Commando'])
end
end
context 'with options' do

View File

@ -11,6 +11,13 @@ shared_examples_for "within" do
end
@session.body.should include('Bar')
end
it "should accept additional options" do
@session.within(:css, "ul li", :text => 'With Simple HTML') do
@session.click_link('Go')
end
@session.body.should include('Bar')
end
end
context "with XPath selector" do

View File

@ -77,6 +77,14 @@ class TestApp < Sinatra::Base
'<pre id="results">' + params[:form].to_yaml + '</pre>'
end
post '/upload_empty' do
if params[:form][:file].nil?
'Successfully ignored empty file field.'
else
'Something went wrong.'
end
end
post '/upload' do
begin
buffer = []

View File

@ -250,6 +250,17 @@
<p>
</form>
<form action="/upload_empty" method="post" enctype="multipart/form-data">
<p>
<label for="form_file_name">File Name</label>
<input type="file" name="form[file]" id="form_file"/>
</p>
<p>
<input type="submit" value="Upload Empty"/>
<p>
</form>
<form action="/upload" method="post" enctype="multipart/form-data">
<p>
<label for="form_file_name">File Name</label>

View File

@ -14,7 +14,7 @@
et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation <a href="/foo" id="foo">ullamco</a> laboris nisi
ut aliquip ex ea commodo consequat.
<a href="/with_simple_html"><img src="http://www.foobar.sun/dummy_image.jpg" width="20" height="20" alt="awesome image" /></a>
<a href="/with_simple_html"><img width="20" height="20" alt="awesome image" /></a>
</p>
<p class="para" id="second">
@ -41,8 +41,8 @@
<a href="/with_html#anchor">Anchor on same page</a>
<input type="text" value="" id="test_field">
<input type="text" checked="checked" id="checked_field">
<a href="/redirect"><img src="http://www.foobar.sun/dummy_image.jpg" width="20" height="20" alt="very fine image" /></a>
<a href="/with_simple_html"><img src="http://www.foobar.sun/dummy_image.jpg" width="20" height="20" alt="fine image" /></a>
<a href="/redirect"><img width="20" height="20" alt="very fine image" /></a>
<a href="/with_simple_html"><img width="20" height="20" alt="fine image" /></a>
<a href="?query_string=true">Naked Query String</a>
<% if params[:query_string] %>
@ -55,6 +55,14 @@
<a href="/with_simple_html" title="awesome title" class="simple">hidden link</a>
</div>
<div style="display: none;">
<a class="visibility">hidden link</a>
</div>
<div>
<a class="visibility">visible link</a>
</div>
<ul>
<li id="john_monkey">Monkey John</li>
<li id="paul_monkey">Monkey Paul</li>

View File

@ -1,3 +1,3 @@
module Capybara
VERSION = '0.4.0'
VERSION = '0.4.1.rc'
end

View File

@ -3,7 +3,7 @@ require 'capybara/rspec'
Capybara.app = TestApp
describe 'capybara/rspec' do
describe 'capybara/rspec', :type => :acceptance do
it "should include Capybara in rpsec" do
visit('/foo')
page.body.should include('Another World')
@ -32,10 +32,16 @@ describe 'capybara/rspec' do
end
it "switches to the javascript driver when giving it as metadata", :js => true do
Capybara.current_driver.should == :selenium
Capybara.current_driver.should == Capybara.javascript_driver
end
it "switches to the given driver when giving it as metadata", :driver => :culerity do
Capybara.current_driver.should == :culerity
end
end
describe 'capybara/rspec', :type => :other do
it "should not include Capybara" do
expect { visit('/') }.to raise_error(NoMethodError)
end
end

View File

@ -26,6 +26,16 @@ describe Capybara::Session do
end
end
describe "#attach_file" do
context "with multipart form" do
it "should submit an empty form-data section if no file is submitted" do
@session.visit("/form")
@session.click_button("Upload Empty")
@session.body.should include('Successfully ignored empty file field.')
end
end
end
it_should_behave_like "session"
it_should_behave_like "session without javascript support"
it_should_behave_like "session with headers support"

1
xpath Submodule

@ -0,0 +1 @@
Subproject commit c0beb95150f7b6d4cf28d0df40019f68da5ad741