Merge remote branch 'trammel/master'
This commit is contained in:
commit
46962e1278
|
@ -1,3 +1,4 @@
|
|||
.idea/
|
||||
.DS_Store
|
||||
pkg
|
||||
*~
|
||||
|
|
89
History.txt
89
History.txt
|
@ -1,4 +1,87 @@
|
|||
=== 0.0.1 2009-11-04
|
||||
# Version 0.3.8
|
||||
|
||||
Release date: 2010-05-12
|
||||
|
||||
### Added
|
||||
|
||||
* Within_frame method to execute a block of code within a particular iframe (Selenium only!)
|
||||
|
||||
### Fixed
|
||||
|
||||
* Single quotes are properly escaped with `select` under rack-test and Selenium.
|
||||
* The :text option for searches now escapes regexp special characters when a string is given.
|
||||
* Selenium now correctly checks already checked checkboxes (same with uncheck)
|
||||
* Timing issue which caused Selenium to hang under certain circumstances.
|
||||
* Selenium now resolves attributes even if they are given as a Symbol
|
||||
|
||||
# Version 0.3.7
|
||||
|
||||
Release date: 2010-04-09
|
||||
|
||||
This is a drop in compatible maintainance release. It's mostly
|
||||
important for driver authors.
|
||||
|
||||
### Added
|
||||
|
||||
* RackTest scans for data-method which rails3 uses to change the request method
|
||||
|
||||
### Fixed
|
||||
|
||||
* Don't hang when starting server on Windoze
|
||||
|
||||
### Changed
|
||||
|
||||
* The driver and session specs are now located inside lib! Driver authors can simply require them.
|
||||
|
||||
# Version 0.3.6
|
||||
|
||||
Release date: 2010-03-22
|
||||
|
||||
This is a maintainance release with minor bug fixes, should be
|
||||
drop in compatible.
|
||||
|
||||
### Added
|
||||
|
||||
* It's now possible to load in external drivers
|
||||
|
||||
### Fixed
|
||||
|
||||
* has_content? ignores whitespace
|
||||
* Trigger events when choosing radios and checking checkboxes under Selenium
|
||||
* Make Capybara.app totally optional when running without server
|
||||
* Changed fallback host so it matches the one set up by Rails' integration tests
|
||||
|
||||
# Version 0.3.5
|
||||
|
||||
Release date: 2010-02-26
|
||||
|
||||
This is a mostly backwards compatible release, it does break
|
||||
the API in some minor places, which should hopefully not affect
|
||||
too many users, please read the release notes carefully!
|
||||
|
||||
### Breaking
|
||||
|
||||
* Relative searching in a node (e.g. find('//p').all('//a')) will now follow XPath standard
|
||||
this means that if you want to find descendant nodes only, you'll need to prefix a dot!
|
||||
* `visit` now accepts fully qualified URLs for drivers that support it.
|
||||
* Capybara will always try to run a rack server, unless you set Capybara.run_sever = false
|
||||
|
||||
### Changed
|
||||
|
||||
* thin is preferred over mongrel and webrick, since it is Ruby 1.9 compatible
|
||||
* click_button and click will find <input type="button">, clicking them does nothing in RackTest
|
||||
|
||||
### Added
|
||||
|
||||
* Much improved error messages in a multitude of places
|
||||
* More semantic page querying with has_link?, has_button?, etc...
|
||||
* Option to ignore hidden elements when querying and interacting with the page
|
||||
* Support for multiple selects
|
||||
|
||||
### Fixed
|
||||
|
||||
* find_by_id is no longer broken
|
||||
* clicking links where the image's alt attribute contains the text is now possible
|
||||
* within_fieldset and within_table work when the default selector is CSS
|
||||
* boolean attributes work the same across drivers (return true/false)
|
||||
|
||||
* 1 major enhancement:
|
||||
* Initial release
|
||||
|
|
87
Manifest.txt
87
Manifest.txt
|
@ -1,87 +0,0 @@
|
|||
History.txt
|
||||
Manifest.txt
|
||||
README.rdoc
|
||||
Rakefile
|
||||
config.ru
|
||||
lib/capybara.rb
|
||||
lib/capybara/cucumber.rb
|
||||
lib/capybara/driver/base.rb
|
||||
lib/capybara/driver/celerity_driver.rb
|
||||
lib/capybara/driver/culerity_driver.rb
|
||||
lib/capybara/driver/rack_test_driver.rb
|
||||
lib/capybara/driver/selenium_driver.rb
|
||||
lib/capybara/dsl.rb
|
||||
lib/capybara/node.rb
|
||||
lib/capybara/rails.rb
|
||||
lib/capybara/save_and_open_page.rb
|
||||
lib/capybara/searchable.rb
|
||||
lib/capybara/server.rb
|
||||
lib/capybara/session.rb
|
||||
lib/capybara/wait_until.rb
|
||||
lib/capybara/xpath.rb
|
||||
script/console
|
||||
script/destroy
|
||||
script/generate
|
||||
spec/capybara_spec.rb
|
||||
spec/driver/celerity_driver_spec.rb
|
||||
spec/driver/culerity_driver_spec.rb
|
||||
spec/driver/rack_test_driver_spec.rb
|
||||
spec/driver/remote_culerity_driver_spec.rb
|
||||
spec/driver/remote_selenium_driver_spec.rb
|
||||
spec/driver/selenium_driver_spec.rb
|
||||
spec/drivers_spec.rb
|
||||
spec/dsl/all_spec.rb
|
||||
spec/dsl/attach_file_spec.rb
|
||||
spec/dsl/check_spec.rb
|
||||
spec/dsl/choose_spec.rb
|
||||
spec/dsl/click_button_spec.rb
|
||||
spec/dsl/click_link_spec.rb
|
||||
spec/dsl/click_spec.rb
|
||||
spec/dsl/current_url_spec.rb
|
||||
spec/dsl/fill_in_spec.rb
|
||||
spec/dsl/find_button_spec.rb
|
||||
spec/dsl/find_by_id_spec.rb
|
||||
spec/dsl/find_field_spec.rb
|
||||
spec/dsl/find_link_spec.rb
|
||||
spec/dsl/find_spec.rb
|
||||
spec/dsl/has_button_spec.rb
|
||||
spec/dsl/has_content_spec.rb
|
||||
spec/dsl/has_css_spec.rb
|
||||
spec/dsl/has_field_spec.rb
|
||||
spec/dsl/has_link_spec.rb
|
||||
spec/dsl/has_xpath_spec.rb
|
||||
spec/dsl/locate_spec.rb
|
||||
spec/dsl/select_spec.rb
|
||||
spec/dsl/uncheck_spec.rb
|
||||
spec/dsl/within_spec.rb
|
||||
spec/dsl_spec.rb
|
||||
spec/fixtures/capybara.jpg
|
||||
spec/fixtures/test_file.txt
|
||||
spec/public/jquery-ui.js
|
||||
spec/public/jquery.js
|
||||
spec/public/test.js
|
||||
spec/save_and_open_page_spec.rb
|
||||
spec/searchable_spec.rb
|
||||
spec/server_spec.rb
|
||||
spec/session/celerity_session_spec.rb
|
||||
spec/session/culerity_session_spec.rb
|
||||
spec/session/rack_test_session_spec.rb
|
||||
spec/session/selenium_session_spec.rb
|
||||
spec/session_spec.rb
|
||||
spec/session_with_headers_support_spec.rb
|
||||
spec/session_with_javascript_support_spec.rb
|
||||
spec/session_without_headers_support_spec.rb
|
||||
spec/session_without_javascript_support_spec.rb
|
||||
spec/spec_helper.rb
|
||||
spec/test_app.rb
|
||||
spec/views/buttons.erb
|
||||
spec/views/fieldsets.erb
|
||||
spec/views/form.erb
|
||||
spec/views/postback.erb
|
||||
spec/views/tables.erb
|
||||
spec/views/with_html.erb
|
||||
spec/views/with_js.erb
|
||||
spec/views/with_scope.erb
|
||||
spec/views/with_simple_html.erb
|
||||
spec/wait_until_spec.rb
|
||||
spec/xpath_spec.rb
|
69
README.rdoc
69
README.rdoc
|
@ -27,7 +27,8 @@ On OSX you may have to install libffi, you can install it via MacPorts with:
|
|||
* Report issues on {GitHub Issues}[http://github.com/jnicklas/capybara/issues]
|
||||
|
||||
Pull requests are very welcome! Make sure your patches are well tested, Capybara is
|
||||
a testing tool after all.
|
||||
a testing tool after all. Please create a topic branch for every separate change
|
||||
you make.
|
||||
|
||||
== Using Capybara with Cucumber
|
||||
|
||||
|
@ -55,6 +56,9 @@ Now you can use it in your steps:
|
|||
click_link 'Sign in'
|
||||
end
|
||||
|
||||
Please note that while Capybara uses XPath selectors by default, Cucumber explicitly
|
||||
changes this to CSS in `env.rb`. See "XPath and CSS" below.
|
||||
|
||||
== Default and current driver
|
||||
|
||||
You can set up a default driver for your features. For example if you'd prefer
|
||||
|
@ -98,6 +102,11 @@ At the moment, Capybara supports Webdriver, also called Selenium 2.0, *not*
|
|||
Selenium RC. Provided Firefox is installed, everything is set up for you, and
|
||||
you should be able to start using Selenium right away.
|
||||
|
||||
If desired, you can change Selenium browser to :chrome or :ie:
|
||||
|
||||
require "selenium-webdriver"
|
||||
Selenium::WebDriver.for :chrome
|
||||
|
||||
== Celerity
|
||||
|
||||
Celerity only runs on JRuby, so you'll need to install the celerity gem under
|
||||
|
@ -151,7 +160,7 @@ with the various form elements:
|
|||
fill_in('First Name', :with => 'John')
|
||||
fill_in('Password', :with => 'Seekrit')
|
||||
fill_in('Description', :with => 'Really Long Text…')
|
||||
choose('An Option')
|
||||
choose('A Radio Button')
|
||||
check('A Checkbox')
|
||||
uncheck('A Checkbox')
|
||||
attach_file('Image', '/path/to/image.jpg')
|
||||
|
@ -177,7 +186,7 @@ You can choose which kind of selector Capybara uses by default, by setting
|
|||
|
||||
There are special methods for restricting the scope to a specific fieldset,
|
||||
identified by either an id or the text of the fieldet's legend tag, and to a
|
||||
specific table, identified by either idea or text of the table's caption tag.
|
||||
specific table, identified by either id or text of the table's caption tag.
|
||||
|
||||
within_fieldset('Employee') do
|
||||
fill_in 'Name', :with => 'Jimmy'
|
||||
|
@ -214,7 +223,7 @@ You can also find specific elements, in order to manipulate them:
|
|||
find_button('Send').click
|
||||
|
||||
find('//table/tr').click
|
||||
wait_for("//*[@id='overlay'").find("//h1").click
|
||||
locate("//*[@id='overlay'").find("//h1").click
|
||||
all('a').each { |a| a[:href] }
|
||||
|
||||
=== Scripting
|
||||
|
@ -255,7 +264,7 @@ is (the default is 2 seconds):
|
|||
Capybara.default_wait_time = 5
|
||||
|
||||
Be aware that because of this behaviour, the following two statements are *not*
|
||||
identical, and you should *always* use the latter!
|
||||
equivalent, and you should *always* use the latter!
|
||||
|
||||
page.should_not have_xpath('//a')
|
||||
page.should have_no_xpath('//a')
|
||||
|
@ -263,36 +272,37 @@ identical, and you should *always* use the latter!
|
|||
The former would incorrectly wait for the content to appear, since the
|
||||
asynchronous process has not yet removed the element from the page, it would
|
||||
therefore fail, even though the code might be working correctly. The latter
|
||||
correctly wait for the element to disappear from the page.
|
||||
correctly waits for the element to disappear from the page.
|
||||
|
||||
== Using the DSL outside cucumber
|
||||
|
||||
You can mix the DSL into any context, for example you could use it in RSpec
|
||||
examples. Just load the dsl and include it anywhere:
|
||||
examples. Just load the DSL and include it anywhere:
|
||||
|
||||
require 'capybara'
|
||||
require 'capybara/dsl'
|
||||
|
||||
include Capybara
|
||||
Capybara.default_driver = :culerity
|
||||
|
||||
within("//form[@id='session']") do
|
||||
fill_in 'Login', :with => 'user@example.com'
|
||||
fill_in 'Password', :with => 'password'
|
||||
module MyModule
|
||||
include Capybara
|
||||
|
||||
def login!
|
||||
within("//form[@id='session']") do
|
||||
fill_in 'Login', :with => 'user@example.com'
|
||||
fill_in 'Password', :with => 'password'
|
||||
end
|
||||
click_link 'Sign in'
|
||||
end
|
||||
end
|
||||
click_link 'Sign in'
|
||||
|
||||
== Calling remote servers
|
||||
|
||||
Normally Capybara expects to be testing an in-process Rack application, but you can also use it to talk to a web server running anywhere on the internets, by setting app_host:
|
||||
|
||||
require 'capybara'
|
||||
require 'capybara/dsl'
|
||||
|
||||
include Capybara
|
||||
Capybara.current_driver = :selenium
|
||||
Capybara.app_host = 'http://www.google.com'
|
||||
|
||||
...
|
||||
visit('/')
|
||||
|
||||
Note that rack-test does not support running against a remote server. With drivers that support it, you can also visit any URL directly:
|
||||
|
@ -353,31 +363,6 @@ moving from Webrat and used CSS a lot, or simply generally prefer CSS:
|
|||
<tt><a href="/same/url#"></tt> instead. You can achieve this in Rails with
|
||||
<tt>link_to('foo', :anchor => '')</tt>
|
||||
|
||||
== Contributors:
|
||||
|
||||
The following people have dedicated their time and effort to Capybara:
|
||||
|
||||
* Jonas Nicklas
|
||||
* Dennis Rogenius
|
||||
* Rob Holland
|
||||
* Wincent Colaiuta
|
||||
* Andrea Fazzi
|
||||
* Aslak Hellesøy
|
||||
* Andrew Brown
|
||||
* Lenny Marks
|
||||
* Aaron Patterson
|
||||
* Dan Dofter
|
||||
* Thorbjørn Hermansen
|
||||
* Louis T.
|
||||
* Stephan Hagemann
|
||||
* Graham Ashton
|
||||
* Joseph Wilk
|
||||
* Matt Wynne
|
||||
* Piotr Sarnacki
|
||||
* Pavel Gabriel
|
||||
* Bodaniel Jeanes
|
||||
* Carl Porth
|
||||
|
||||
== License:
|
||||
|
||||
(The MIT License)
|
||||
|
|
32
Rakefile
32
Rakefile
|
@ -1,29 +1,9 @@
|
|||
require 'rubygems'
|
||||
require 'spec/rake/spectask'
|
||||
|
||||
gem 'hoe', '>= 2.1.0'
|
||||
require 'hoe'
|
||||
|
||||
Hoe.plugin :newgem
|
||||
|
||||
# Generate all the Rake tasks
|
||||
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
||||
Hoe.spec 'capybara' do
|
||||
developer 'Jonas Nicklas', 'jonas.nicklas@gmail.com'
|
||||
|
||||
self.readme_file = 'README.rdoc'
|
||||
self.extra_rdoc_files = Dir['*.rdoc']
|
||||
|
||||
self.extra_deps = [
|
||||
['nokogiri', '>= 1.3.3'],
|
||||
['mime-types', '>= 1.16'],
|
||||
['culerity', '>= 0.2.4'],
|
||||
['selenium-webdriver', '>= 0.0.3'],
|
||||
['rack', '>= 1.0.0'],
|
||||
['rack-test', '>= 0.5.2'],
|
||||
]
|
||||
|
||||
self.extra_dev_deps = [
|
||||
['sinatra', '>= 0.9.4'],
|
||||
['rspec', '>= 1.2.9']
|
||||
]
|
||||
desc "Run all examples"
|
||||
Spec::Rake::SpecTask.new('spec') do |t|
|
||||
t.spec_files = FileList['spec/**/*.rb']
|
||||
end
|
||||
|
||||
task :default => :spec
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
lib = File.expand_path('../lib/', __FILE__)
|
||||
$:.unshift lib unless $:.include?(lib)
|
||||
|
||||
require 'capybara/version'
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "capybara"
|
||||
s.rubyforge_project = "capybara"
|
||||
s.version = Capybara::VERSION
|
||||
|
||||
s.authors = ["Jonas Nicklas"]
|
||||
s.email = ["jonas.nicklas@gmail.com"]
|
||||
s.description = "Capybara is an integration testing tool for rack based web applications. It simulates how a user would interact with a website"
|
||||
|
||||
s.files = Dir.glob("{lib,spec}/**/*") + %w(README.rdoc History.txt)
|
||||
s.extra_rdoc_files = ["README.rdoc"]
|
||||
|
||||
s.homepage = "http://github.com/jnicklas/capybara"
|
||||
s.rdoc_options = ["--main", "README.rdoc"]
|
||||
s.require_paths = ["lib"]
|
||||
s.rubygems_version = "1.3.6"
|
||||
s.summary = "Capybara aims to simplify the process of integration testing Rack applications, such as Rails, Sinatra or Merb"
|
||||
|
||||
s.add_runtime_dependency("nokogiri", [">= 1.3.3"])
|
||||
s.add_runtime_dependency("mime-types", [">= 1.16"])
|
||||
s.add_runtime_dependency("culerity", [">= 0.2.4"])
|
||||
s.add_runtime_dependency("selenium-webdriver", [">= 0.0.3"])
|
||||
s.add_runtime_dependency("rack", [">= 1.0.0"])
|
||||
s.add_runtime_dependency("rack-test", [">= 0.5.2"])
|
||||
|
||||
s.add_development_dependency("sinatra", [">= 0.9.4"])
|
||||
s.add_development_dependency("rspec", [">= 1.2.9"])
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
## This is not needed for Thin > 1.0.0
|
||||
ENV['RACK_ENV'] = "production"
|
||||
|
||||
require File.expand_path('spec/test_app', File.dirname(__FILE__))
|
||||
require File.expand_path('lib/capybara/spec/test_app', File.dirname(__FILE__))
|
||||
|
||||
run TestApp
|
|
@ -2,8 +2,6 @@ require 'timeout'
|
|||
require 'nokogiri'
|
||||
|
||||
module Capybara
|
||||
VERSION = '0.3.0'
|
||||
|
||||
class CapybaraError < StandardError; end
|
||||
class DriverNotFoundError < CapybaraError; end
|
||||
class ElementNotFound < CapybaraError; end
|
||||
|
@ -15,7 +13,7 @@ module Capybara
|
|||
class InfiniteRedirectError < TimeoutError; end
|
||||
|
||||
class << self
|
||||
attr_accessor :debug, :asset_root, :app_host, :run_server
|
||||
attr_accessor :debug, :asset_root, :app_host, :run_server, :default_host
|
||||
attr_accessor :default_selector, :default_wait_time, :ignore_hidden_elements
|
||||
|
||||
def default_selector
|
||||
|
@ -37,6 +35,7 @@ module Capybara
|
|||
autoload :Node, 'capybara/node'
|
||||
autoload :XPath, 'capybara/xpath'
|
||||
autoload :Searchable, 'capybara/searchable'
|
||||
autoload :VERSION, 'capybara/version'
|
||||
|
||||
module Driver
|
||||
autoload :Base, 'capybara/driver/base'
|
||||
|
|
|
@ -19,6 +19,9 @@ class Capybara::Driver::Base
|
|||
false
|
||||
end
|
||||
|
||||
def wait_until *args
|
||||
end
|
||||
|
||||
def response_headers
|
||||
raise Capybara::NotSupportedByDriverError
|
||||
end
|
||||
|
@ -27,6 +30,10 @@ class Capybara::Driver::Base
|
|||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def within_frame(frame_id)
|
||||
raise Capybara::NotSupportedByDriverError
|
||||
end
|
||||
|
||||
def source
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
@ -34,4 +41,8 @@ class Capybara::Driver::Base
|
|||
def cleanup!
|
||||
end
|
||||
|
||||
def has_shortcircuit_timeout?
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -14,7 +14,7 @@ class Capybara::Driver::Celerity < Capybara::Driver::Base
|
|||
end
|
||||
|
||||
def value
|
||||
if node.type == 'select-multiple'
|
||||
if tag_name == "select" and node.multiple?
|
||||
node.selected_options
|
||||
else
|
||||
super
|
||||
|
@ -77,6 +77,14 @@ class Capybara::Driver::Celerity < Capybara::Driver::Base
|
|||
node.fire_event(event.to_s)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def all_unfiltered(locator)
|
||||
noko_node = Nokogiri::HTML(driver.body).xpath(node.xpath).first
|
||||
all_nodes = noko_node.xpath(locator).map { |n| n.path }.join(' | ')
|
||||
driver.find(all_nodes)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
attr_reader :app, :rack_server
|
||||
|
|
|
@ -28,17 +28,17 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|||
|
||||
|
||||
def set(value)
|
||||
if tag_name == 'input' and %w(text password hidden file).include?(type)
|
||||
node['value'] = value.to_s
|
||||
elsif tag_name == 'input' and type == 'radio'
|
||||
driver.html.xpath("//input[@name='#{self[:name]}']").each { |node| node.remove_attribute("checked") }
|
||||
if tag_name == 'input' and type == 'radio'
|
||||
driver.html.xpath("//input[@name=#{Capybara::XPath.escape(self[:name])}]").each { |node| node.remove_attribute("checked") }
|
||||
node['checked'] = 'checked'
|
||||
elsif tag_name == 'input' and type == 'checkbox'
|
||||
if value
|
||||
if value && !node['checked']
|
||||
node['checked'] = 'checked'
|
||||
else
|
||||
elsif !value && node['checked']
|
||||
node.remove_attribute('checked')
|
||||
end
|
||||
elsif tag_name == 'input'
|
||||
node['value'] = value.to_s
|
||||
elsif tag_name == "textarea"
|
||||
node.content = value.to_s
|
||||
end
|
||||
|
@ -49,8 +49,8 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|||
node.xpath(".//option[@selected]").each { |node| node.remove_attribute("selected") }
|
||||
end
|
||||
|
||||
if option_node = node.xpath(".//option[text()='#{option}']").first ||
|
||||
node.xpath(".//option[contains(.,'#{option}')]").first
|
||||
if option_node = node.xpath(".//option[text()=#{Capybara::XPath.escape(option)}]").first ||
|
||||
node.xpath(".//option[contains(.,#{Capybara::XPath.escape(option)})]").first
|
||||
option_node["selected"] = 'selected'
|
||||
else
|
||||
options = node.xpath(".//option").map { |o| "'#{o.text}'" }.join(', ')
|
||||
|
@ -63,8 +63,8 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|||
raise Capybara::UnselectNotAllowed, "Cannot unselect option '#{option}' from single select box."
|
||||
end
|
||||
|
||||
if option_node = node.xpath(".//option[text()='#{option}']").first ||
|
||||
node.xpath(".//option[contains(.,'#{option}')]").first
|
||||
if option_node = node.xpath(".//option[text()=#{Capybara::XPath.escape(option)}]").first ||
|
||||
node.xpath(".//option[contains(.,#{Capybara::XPath.escape(option)})]").first
|
||||
option_node.remove_attribute('selected')
|
||||
else
|
||||
options = node.xpath(".//option").map { |o| "'#{o.text}'" }.join(', ')
|
||||
|
@ -74,7 +74,8 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|||
|
||||
def click
|
||||
if tag_name == 'a'
|
||||
driver.visit(self[:href].to_s)
|
||||
method = self["data-method"] || :get
|
||||
driver.process(method, self[:href].to_s)
|
||||
elsif (tag_name == 'input' or tag_name == 'button') and %w(submit image).include?(type)
|
||||
Form.new(driver, form).submit(self)
|
||||
end
|
||||
|
@ -94,6 +95,10 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|||
|
||||
private
|
||||
|
||||
def all_unfiltered(locator)
|
||||
node.xpath(locator).map { |n| self.class.new(driver, n) }
|
||||
end
|
||||
|
||||
def type
|
||||
node[:type]
|
||||
end
|
||||
|
@ -107,9 +112,7 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|||
def params(button)
|
||||
params = {}
|
||||
|
||||
text_fields = %w[text hidden password url color tel email search].map{|f| "@type='#{f}'"}.join(' or ')
|
||||
|
||||
node.xpath(".//input[#{text_fields}]").map do |input|
|
||||
node.xpath(".//input[@type!='radio' and @type!='checkbox' and @type!='submit']").map do |input|
|
||||
merge_param!(params, input['name'].to_s, input['value'].to_s)
|
||||
end
|
||||
node.xpath(".//textarea").map do |textarea|
|
||||
|
@ -141,7 +144,7 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|||
end
|
||||
end
|
||||
end
|
||||
merge_param!(params, button[:name], button[:value]) if button[:name]
|
||||
merge_param!(params, button[:name], button[:value] || "") if button[:name]
|
||||
params
|
||||
end
|
||||
|
||||
|
@ -174,21 +177,24 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|||
end
|
||||
|
||||
include ::Rack::Test::Methods
|
||||
attr_reader :app, :html, :body
|
||||
attr_reader :app
|
||||
|
||||
alias_method :response, :last_response
|
||||
alias_method :request, :last_request
|
||||
alias_method :source, :body
|
||||
|
||||
def initialize(app)
|
||||
raise ArgumentError, "rack-test requires a rack application, but none was given" unless app
|
||||
@app = app
|
||||
end
|
||||
|
||||
def visit(path, attributes = {})
|
||||
process(:get, path, attributes)
|
||||
end
|
||||
|
||||
def process(method, path, attributes = {})
|
||||
return if path.gsub(/^#{current_path}/, '') =~ /^#/
|
||||
get(path, attributes, env)
|
||||
send(method, path, attributes, env)
|
||||
follow_redirects!
|
||||
cache_body
|
||||
end
|
||||
|
||||
def current_url
|
||||
|
@ -203,15 +209,37 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|||
path = current_path if not path or path.empty?
|
||||
send(method, path, attributes, env)
|
||||
follow_redirects!
|
||||
cache_body
|
||||
end
|
||||
|
||||
def find(selector)
|
||||
html.xpath(selector).map { |node| Node.new(self, node) }
|
||||
end
|
||||
|
||||
def body
|
||||
@body ||= response.body
|
||||
end
|
||||
|
||||
def html
|
||||
@html ||= Nokogiri::HTML(body)
|
||||
end
|
||||
alias_method :source, :body
|
||||
|
||||
def get(*args, &block); reset_cache; super; end
|
||||
def post(*args, &block); reset_cache; super; end
|
||||
def put(*args, &block); reset_cache; super; end
|
||||
def delete(*args, &block); reset_cache; super; end
|
||||
|
||||
private
|
||||
|
||||
def reset_cache
|
||||
@body = nil
|
||||
@html = nil
|
||||
end
|
||||
|
||||
def build_rack_mock_session # :nodoc:
|
||||
Rack::MockSession.new(app, Capybara.default_host || "www.example.com")
|
||||
end
|
||||
|
||||
def current_path
|
||||
request.path rescue ""
|
||||
end
|
||||
|
@ -236,9 +264,9 @@ private
|
|||
env
|
||||
end
|
||||
|
||||
def cache_body
|
||||
@body = response.body
|
||||
@html = Nokogiri::HTML(body)
|
||||
def reset_cache
|
||||
@body = nil
|
||||
@html = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -10,25 +10,33 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|||
if name == :value
|
||||
node.value
|
||||
else
|
||||
node.attribute(name)
|
||||
node.attribute(name.to_s)
|
||||
end
|
||||
rescue Selenium::WebDriver::Error::WebDriverError
|
||||
nil
|
||||
end
|
||||
|
||||
def value
|
||||
if tag_name == "select" and self[:multiple]
|
||||
node.find_elements(:xpath, ".//option").select { |n| n.selected? }.map { |n| n.text }
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def set(value)
|
||||
if tag_name == 'textarea' or (tag_name == 'input' and %w(text password hidden file).include?(type))
|
||||
node.clear
|
||||
node.send_keys(value.to_s)
|
||||
elsif tag_name == 'input' and type == 'radio'
|
||||
node.select
|
||||
node.click
|
||||
elsif tag_name == 'input' and type == 'checkbox'
|
||||
node.toggle
|
||||
node.click if node.attribute('checked') != value
|
||||
end
|
||||
end
|
||||
|
||||
def select(option)
|
||||
option_node = node.find_element(:xpath, ".//option[text()='#{option}']") || node.find_element(:xpath, ".//option[contains(.,'#{option}')]")
|
||||
option_node = node.find_element(:xpath, ".//option[normalize-space(text())=#{Capybara::XPath.escape(option)}]") || node.find_element(:xpath, ".//option[contains(.,#{Capybara::XPath.escape(option)})]")
|
||||
option_node.select
|
||||
rescue
|
||||
options = node.find_elements(:xpath, "//option").map { |o| "'#{o.text}'" }.join(', ')
|
||||
|
@ -41,7 +49,7 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|||
end
|
||||
|
||||
begin
|
||||
option_node = node.find_element(:xpath, ".//option[text()='#{option}']") || node.find_element(:xpath, ".//option[contains(.,'#{option}')]")
|
||||
option_node = node.find_element(:xpath, ".//option[normalize-space(text())=#{Capybara::XPath.escape(option)}]") || node.find_element(:xpath, ".//option[contains(.,#{Capybara::XPath.escape(option)})]")
|
||||
option_node.clear
|
||||
rescue
|
||||
options = node.find_elements(:xpath, "//option").map { |o| "'#{o.text}'" }.join(', ')
|
||||
|
@ -70,6 +78,10 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|||
|
||||
private
|
||||
|
||||
def all_unfiltered(locator)
|
||||
node.find_elements(:xpath, locator).map { |n| self.class.new(driver, n) }
|
||||
end
|
||||
|
||||
def type
|
||||
self[:type]
|
||||
end
|
||||
|
@ -128,6 +140,13 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|||
browser.manage.delete_all_cookies
|
||||
end
|
||||
|
||||
def within_frame(frame_id)
|
||||
old_window = browser.window_handle
|
||||
browser.switch_to.frame(frame_id)
|
||||
yield
|
||||
browser.switch_to.window old_window
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def url(path)
|
||||
|
|
|
@ -56,14 +56,5 @@ module Capybara
|
|||
def trigger(event)
|
||||
raise NotSupportedByDriverError
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def all_unfiltered(locator)
|
||||
nodes = XPath.wrap(locator).scope(path).paths.map do |path|
|
||||
driver.find(path)
|
||||
end.flatten
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,9 +3,15 @@ require 'capybara/dsl'
|
|||
|
||||
Capybara.app = Rack::Builder.new do
|
||||
map "/" do
|
||||
use Rails::Rack::Static
|
||||
run ActionController::Dispatcher.new
|
||||
if Rails.version.to_f >= 3.0
|
||||
ActionDispatch::Static
|
||||
run Rails.application
|
||||
else # Rails 2
|
||||
use Rails::Rack::Static
|
||||
run ActionController::Dispatcher.new
|
||||
end
|
||||
end
|
||||
end.to_app
|
||||
|
||||
Capybara.asset_root = Rails.root.join('public')
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ module Capybara
|
|||
results = all_unfiltered(locator)
|
||||
|
||||
if options[:text]
|
||||
options[:text] = Regexp.escape(options[:text]) unless options[:text].kind_of?(Regexp)
|
||||
results = results.select { |n| n.text.match(options[:text]) }
|
||||
end
|
||||
|
||||
|
|
|
@ -55,20 +55,23 @@ class Capybara::Server
|
|||
end
|
||||
|
||||
def boot
|
||||
return self unless @app
|
||||
find_available_port
|
||||
Capybara.log "application has already booted" and return self if responsive?
|
||||
Capybara.log "booting Rack applicartion on port #{port}"
|
||||
|
||||
Timeout.timeout(10) do
|
||||
Thread.new do
|
||||
handler.run(Identify.new(@app), :Port => port, :AccessLog => [])
|
||||
end
|
||||
Capybara.log "checking if application has booted"
|
||||
Thread.new do
|
||||
handler.run(Identify.new(@app), :Port => port, :AccessLog => [])
|
||||
end
|
||||
Capybara.log "checking if application has booted"
|
||||
|
||||
loop do
|
||||
Capybara.log("application has booted") and break if responsive?
|
||||
Capybara.log("waiting for application to boot...")
|
||||
Capybara::WaitUntil.timeout(10) do
|
||||
if responsive?
|
||||
Capybara.log("application has booted")
|
||||
true
|
||||
else
|
||||
sleep 0.5
|
||||
false
|
||||
end
|
||||
end
|
||||
self
|
||||
|
@ -90,7 +93,7 @@ private
|
|||
if res.is_a?(Net::HTTPSuccess) or res.is_a?(Net::HTTPRedirection)
|
||||
return res.body == @app.object_id.to_s
|
||||
end
|
||||
rescue Errno::ECONNREFUSED
|
||||
rescue Errno::ECONNREFUSED, Errno::EBADF
|
||||
return false
|
||||
end
|
||||
|
||||
|
|
|
@ -1,54 +1,43 @@
|
|||
require 'forwardable'
|
||||
require 'capybara/wait_until'
|
||||
|
||||
module Capybara
|
||||
class Session
|
||||
extend Forwardable
|
||||
include Searchable
|
||||
|
||||
DSL_METHODS = [
|
||||
:all, :attach_file, :body, :check, :choose, :click, :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, :has_link?, :has_no_link?, :has_button?, :has_no_button?,
|
||||
:has_field?, :has_no_field?, :has_checked_field?, :has_unchecked_field?
|
||||
:visit, :wait_until, :within, :within_fieldset, :within_table, :within_frame, :has_link?, :has_no_link?, :has_button?,
|
||||
:has_no_button?, :has_field?, :has_no_field?, :has_checked_field?, :has_unchecked_field?, :has_no_table?, :has_table?,
|
||||
:unselect, :has_select?, :has_no_select?
|
||||
]
|
||||
|
||||
attr_reader :mode, :app
|
||||
|
||||
def initialize(mode, app)
|
||||
def initialize(mode, app=nil)
|
||||
@mode = mode
|
||||
@app = app
|
||||
end
|
||||
|
||||
def driver
|
||||
@driver ||= case mode
|
||||
when :rack_test
|
||||
Capybara::Driver::RackTest.new(app)
|
||||
when :selenium
|
||||
Capybara::Driver::Selenium.new(app)
|
||||
when :celerity
|
||||
Capybara::Driver::Celerity.new(app)
|
||||
when :culerity
|
||||
Capybara::Driver::Culerity.new(app)
|
||||
else
|
||||
@driver ||= begin
|
||||
string = mode.to_s
|
||||
string.gsub!(%r{(^.)|(_.)}) { |m| m[m.length-1,1].upcase }
|
||||
Capybara::Driver.const_get(string.to_sym).new(app)
|
||||
rescue NameError
|
||||
raise Capybara::DriverNotFoundError, "no driver called #{mode} was found"
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup!
|
||||
driver.cleanup!
|
||||
end
|
||||
|
||||
def current_url
|
||||
driver.current_url
|
||||
end
|
||||
|
||||
def response_headers
|
||||
driver.response_headers
|
||||
end
|
||||
|
||||
def visit(path)
|
||||
driver.visit(path)
|
||||
end
|
||||
def_delegator :driver, :cleanup!
|
||||
def_delegator :driver, :current_url
|
||||
def_delegator :driver, :response_headers
|
||||
def_delegator :driver, :visit
|
||||
def_delegator :driver, :body
|
||||
def_delegator :driver, :source
|
||||
|
||||
def click(locator)
|
||||
msg = "no link or button '#{locator}' found"
|
||||
|
@ -73,6 +62,7 @@ module Capybara
|
|||
|
||||
def fill_in(locator, options={})
|
||||
msg = "cannot fill in, no text field, text area or password field with id, name, or label '#{locator}' found"
|
||||
raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
|
||||
locate(:xpath, XPath.fillable_field(locator), msg).set(options[:with])
|
||||
end
|
||||
|
||||
|
@ -106,14 +96,6 @@ module Capybara
|
|||
locate(:xpath, XPath.file_field(locator), msg).set(path)
|
||||
end
|
||||
|
||||
def body
|
||||
driver.body
|
||||
end
|
||||
|
||||
def source
|
||||
driver.source
|
||||
end
|
||||
|
||||
def within(kind, scope=nil)
|
||||
kind, scope = Capybara.default_selector, kind unless scope
|
||||
scope = XPath.from_css(scope) if kind == :css
|
||||
|
@ -138,6 +120,12 @@ module Capybara
|
|||
end
|
||||
end
|
||||
|
||||
def within_frame(frame_id)
|
||||
driver.within_frame(frame_id) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
def has_xpath?(path, options={})
|
||||
wait_conditionally_until do
|
||||
results = all(:xpath, path, options)
|
||||
|
@ -244,7 +232,7 @@ module Capybara
|
|||
end
|
||||
|
||||
def wait_until(timeout = Capybara.default_wait_time)
|
||||
WaitUntil.timeout(timeout) { yield }
|
||||
WaitUntil.timeout(timeout,driver) { yield }
|
||||
end
|
||||
|
||||
def evaluate_script(script)
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
||||
require 'capybara/spec/test_app'
|
||||
|
||||
Dir[File.dirname(__FILE__)+'/driver/*'].each { |group|
|
||||
require group
|
||||
}
|
||||
|
||||
shared_examples_for 'driver' do
|
||||
|
||||
|
@ -72,6 +76,26 @@ shared_examples_for 'driver' do
|
|||
end
|
||||
end
|
||||
|
||||
describe "node relative searching" do
|
||||
before do
|
||||
@driver.visit('/tables')
|
||||
@node = @driver.find('//body').first
|
||||
end
|
||||
|
||||
it "should be able to navigate/search child node" do
|
||||
@node.all('//table').size.should == 5
|
||||
@node.find('//form').all('.//table').size.should == 1
|
||||
@node.find('//form').find('.//table//caption').text.should == 'Agent'
|
||||
if @driver.class == Capybara::Driver::Selenium
|
||||
pending("Selenium gets this wrong, see http://code.google.com/p/selenium/issues/detail?id=403") do
|
||||
@node.find('//form').all('//table').size.should == 5
|
||||
end
|
||||
else
|
||||
@node.find('//form').all('//table').size.should == 5
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
shared_examples_for "driver with javascript support" do
|
||||
|
@ -97,7 +121,6 @@ shared_examples_for "driver with javascript support" do
|
|||
@driver.evaluate_script('1+1').should == 2
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
shared_examples_for "driver with header support" do
|
||||
|
@ -107,33 +130,33 @@ shared_examples_for "driver with header support" do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples_for "driver with node path support" do
|
||||
describe "node relative searching" do
|
||||
before do
|
||||
@driver.visit('/tables')
|
||||
@node = @driver.find('//body').first
|
||||
shared_examples_for "driver with frame support" do
|
||||
describe '#within_frame' do
|
||||
before(:each) do
|
||||
@driver.visit('/within_frames')
|
||||
end
|
||||
|
||||
it "should be able to navigate/search child nodes" do
|
||||
@node.all('//table').size.should == 3
|
||||
@node.find('//form').all('//table').size.should == 1
|
||||
@node.find('//form').find('//table//caption').text.should == 'Agent'
|
||||
it "should find the div in frameOne" do
|
||||
@driver.within_frame("frameOne") do
|
||||
@driver.find("//*[@id='divInFrameOne']")[0].text.should eql 'This is the text of divInFrameOne'
|
||||
end
|
||||
end
|
||||
it "should find the div in FrameTwo" do
|
||||
@driver.within_frame("frameTwo") do
|
||||
@driver.find("//*[@id='divInFrameTwo']")[0].text.should eql 'This is the text of divInFrameTwo'
|
||||
end
|
||||
end
|
||||
it "should find the text div in the main window after finding text in frameOne" do
|
||||
@driver.within_frame("frameOne") do
|
||||
@driver.find("//*[@id='divInFrameOne']")[0].text.should eql 'This is the text of divInFrameOne'
|
||||
end
|
||||
@driver.find("//*[@id='divInMainWindow']")[0].text.should eql 'This is the text for divInMainWindow'
|
||||
end
|
||||
it "should find the text div in the main window after finding text in frameTwo" do
|
||||
@driver.within_frame("frameTwo") do
|
||||
@driver.find("//*[@id='divInFrameTwo']")[0].text.should eql 'This is the text of divInFrameTwo'
|
||||
end
|
||||
@driver.find("//*[@id='divInMainWindow']")[0].text.should eql 'This is the text for divInMainWindow'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for "driver without node path support" do
|
||||
describe "node relative searching" do
|
||||
before do
|
||||
@driver.visit('/tables')
|
||||
@node = @driver.find('//body').first
|
||||
end
|
||||
|
||||
it "should get NotSupportedByDriverError" do
|
||||
running do
|
||||
@node.all('//form')
|
||||
end.should raise_error(Capybara::NotSupportedByDriverError)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
Before Width: | Height: | Size: 332 B After Width: | Height: | Size: 332 B |
|
@ -27,4 +27,7 @@ $(function() {
|
|||
$('#with_focus_event').focus(function() {
|
||||
$('body').append('<p id="focus_event_triggered">Focus Event triggered</p>')
|
||||
});
|
||||
$('#checkbox_with_event').click(function() {
|
||||
$('body').append('<p id="checkbox_event_triggered">Checkbox event triggered</p>')
|
||||
});
|
||||
});
|
|
@ -1,6 +1,10 @@
|
|||
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
||||
require 'capybara/spec/test_app'
|
||||
require 'nokogiri'
|
||||
|
||||
Dir[File.dirname(__FILE__)+'/session/*'].each { |group|
|
||||
require group
|
||||
}
|
||||
|
||||
shared_examples_for "session" do
|
||||
def extract_results(session)
|
||||
YAML.load Nokogiri::HTML(session.body).xpath("//pre[@id='results']").first.text
|
|
@ -0,0 +1,67 @@
|
|||
module CheckSpec
|
||||
shared_examples_for "check" do
|
||||
|
||||
describe "#check" do
|
||||
before do
|
||||
@session.visit('/form')
|
||||
end
|
||||
|
||||
describe "'checked' attribute" do
|
||||
it "should be true if checked" do
|
||||
@session.check("Terms of Use")
|
||||
@session.find(:xpath, "//input[@id='form_terms_of_use']")['checked'].should be_true
|
||||
end
|
||||
|
||||
it "should be false if unchecked" do
|
||||
@session.find(:xpath, "//input[@id='form_terms_of_use']")['checked'].should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "checking" do
|
||||
it "should not change an already checked checkbox" do
|
||||
@session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
|
||||
@session.check('form_pets_dog')
|
||||
@session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
|
||||
end
|
||||
|
||||
it "should check an unchecked checkbox" do
|
||||
@session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
|
||||
@session.check('form_pets_cat')
|
||||
@session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "unchecking" do
|
||||
it "should not change an already unchecked checkbox" do
|
||||
@session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
|
||||
@session.uncheck('form_pets_cat')
|
||||
@session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
|
||||
end
|
||||
|
||||
it "should uncheck a checked checkbox" do
|
||||
@session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
|
||||
@session.uncheck('form_pets_dog')
|
||||
@session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_false
|
||||
end
|
||||
end
|
||||
|
||||
it "should check a checkbox by id" do
|
||||
@session.check("form_pets_cat")
|
||||
@session.click_button('awesome')
|
||||
extract_results(@session)['pets'].should include('dog', 'cat', 'hamster')
|
||||
end
|
||||
|
||||
it "should check a checkbox by label" do
|
||||
@session.check("Cat")
|
||||
@session.click_button('awesome')
|
||||
extract_results(@session)['pets'].should include('dog', 'cat', 'hamster')
|
||||
end
|
||||
|
||||
context "with a locator that doesn't exist" do
|
||||
it "should raise an error" do
|
||||
running { @session.check('does not exist') }.should raise_error(Capybara::ElementNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -114,6 +114,18 @@ shared_examples_for "click_button" do
|
|||
end
|
||||
end
|
||||
|
||||
context "with alt given on an image button" do
|
||||
it "should submit the associated form" do
|
||||
@session.click_button('oh hai thar')
|
||||
extract_results(@session)['first_name'].should == 'John'
|
||||
end
|
||||
|
||||
it "should work with partial matches" do
|
||||
@session.click_button('hai')
|
||||
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
|
||||
@session.click_button('okay')
|
||||
|
@ -190,6 +202,12 @@ shared_examples_for "click_button" do
|
|||
end
|
||||
end
|
||||
|
||||
it "should serialize and send valueless buttons that were clicked" do
|
||||
@session.click_button('No Value!')
|
||||
@results = extract_results(@session)
|
||||
@results['no_value'].should_not be_nil
|
||||
end
|
||||
|
||||
it "should serialize and send GET forms" do
|
||||
@session.visit('/form')
|
||||
@session.click_button('med')
|
|
@ -52,6 +52,19 @@ shared_examples_for "fill_in" do
|
|||
extract_results(@session)['password'].should == 'supasikrit'
|
||||
end
|
||||
|
||||
it "should fill in a field with a custom type" do
|
||||
pending "selenium doesn't seem to find custom fields" if @session.mode == :selenium
|
||||
@session.fill_in('Schmooo', :with => 'Schmooo is the game')
|
||||
@session.click_button('awesome')
|
||||
extract_results(@session)['schmooo'].should == 'Schmooo is the game'
|
||||
end
|
||||
|
||||
it "should fill in a password field by name" do
|
||||
@session.fill_in('form[password]', :with => 'supasikrit')
|
||||
@session.click_button('awesome')
|
||||
extract_results(@session)['password'].should == 'supasikrit'
|
||||
end
|
||||
|
||||
it "should fill in a password field by label" do
|
||||
@session.fill_in('Password', :with => 'supasikrit')
|
||||
@session.click_button('awesome')
|
||||
|
@ -70,6 +83,10 @@ shared_examples_for "fill_in" do
|
|||
extract_results(@session)['name'].should == 'Ford Prefect'
|
||||
end
|
||||
|
||||
it "should throw an exception if a hash containing 'with' is not provided" do
|
||||
lambda{@session.fill_in 'Name', 'ignu'}.should raise_error
|
||||
end
|
||||
|
||||
context "with ignore_hidden_fields" do
|
||||
before { Capybara.ignore_hidden_elements = true }
|
||||
after { Capybara.ignore_hidden_elements = false }
|
|
@ -27,6 +27,11 @@ shared_examples_for "has_content" do
|
|||
@session.should have_content('exercitation ullamco laboris')
|
||||
end
|
||||
|
||||
it "should ignore extra whitespace and newlines" do
|
||||
@session.visit('/with_html')
|
||||
@session.should have_content('text with whitespace')
|
||||
end
|
||||
|
||||
it "should be false if the given content is not on the page" do
|
||||
@session.visit('/with_html')
|
||||
@session.should_not have_content('xxxxyzzz')
|
|
@ -0,0 +1,19 @@
|
|||
shared_examples_for "session with headers support" do
|
||||
describe '#response_headers' do
|
||||
it "should return response headers" do
|
||||
@session.visit('/with_simple_html')
|
||||
@session.response_headers['Content-Type'].should == 'text/html'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for "session without headers support" do
|
||||
describe "#response_headers" do
|
||||
before{ @session.visit('/with_simple_html') }
|
||||
it "should raise an error" do
|
||||
running {
|
||||
@session.response_headers
|
||||
}.should raise_error(Capybara::NotSupportedByDriverError)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,204 @@
|
|||
shared_examples_for "session with javascript support" do
|
||||
describe 'all JS specs' do
|
||||
before do
|
||||
Capybara.default_wait_time = 1
|
||||
end
|
||||
|
||||
after do
|
||||
Capybara.default_wait_time = 0
|
||||
end
|
||||
|
||||
describe '#find' do
|
||||
it "should allow triggering of custom JS events" do
|
||||
pending "cannot figure out how to do this with selenium" if @session.mode == :selenium
|
||||
@session.visit('/with_js')
|
||||
@session.find(:css, '#with_focus_event').trigger(:focus)
|
||||
@session.should have_css('#focus_event_triggered')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#body' do
|
||||
it "should return the current state of the page" do
|
||||
@session.visit('/with_js')
|
||||
@session.body.should include('I changed it')
|
||||
@session.body.should_not include('This is text')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#source' do
|
||||
it "should return the original, unmodified source of the page" do
|
||||
pending "cannot figure out how to do this with selenium" if @session.mode == :selenium
|
||||
@session.visit('/with_js')
|
||||
@session.source.should include('This is text')
|
||||
@session.source.should_not include('I changed it')
|
||||
end
|
||||
end
|
||||
|
||||
describe "#evaluate_script" do
|
||||
it "should return the evaluated script" do
|
||||
@session.visit('/with_js')
|
||||
@session.evaluate_script("1+3").should == 4
|
||||
end
|
||||
end
|
||||
|
||||
describe '#locate' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.locate("//a[contains(.,'Has been clicked')]")[:href].should == '#'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#wait_until' do
|
||||
before do
|
||||
@default_timeout = Capybara.default_wait_time
|
||||
end
|
||||
|
||||
after do
|
||||
Capybara.default_wait_time = @default_wait_time
|
||||
end
|
||||
|
||||
it "should wait for block to return true" do
|
||||
@session.visit('/with_js')
|
||||
@session.select('My Waiting Option', :from => 'waiter')
|
||||
@session.evaluate_script('activeRequests == 1').should be_true
|
||||
@session.wait_until do
|
||||
@session.evaluate_script('activeRequests == 0')
|
||||
end
|
||||
@session.evaluate_script('activeRequests == 0').should be_true
|
||||
end
|
||||
|
||||
it "should raise Capybara::TimeoutError if block doesn't return true within timeout" do
|
||||
@session.visit('/with_html')
|
||||
Proc.new do
|
||||
@session.wait_until(0.1) do
|
||||
@session.find('//div[@id="nosuchthing"]')
|
||||
end
|
||||
end.should raise_error(::Capybara::TimeoutError)
|
||||
end
|
||||
|
||||
it "should accept custom timeout in seconds" do
|
||||
start = Time.now
|
||||
Capybara.default_wait_time = 5
|
||||
begin
|
||||
@session.wait_until(0.1) { false }
|
||||
rescue Capybara::TimeoutError; end
|
||||
(Time.now - start).should be_close(0.1, 0.1)
|
||||
end
|
||||
|
||||
it "should default to Capybara.default_wait_time before timeout" do
|
||||
@session.driver # init the driver to exclude init timing from test
|
||||
start = Time.now
|
||||
Capybara.default_wait_time = 0.2
|
||||
begin
|
||||
@session.wait_until { false }
|
||||
rescue Capybara::TimeoutError; end
|
||||
if @session.driver.has_shortcircuit_timeout?
|
||||
(Time.now - start).should be_close(0, 0.1)
|
||||
else
|
||||
(Time.now - start).should be_close(0.2, 0.1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#click' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.click('Has been clicked')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#click_link' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.click_link('Has been clicked')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#click_button' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.click_button('New Here')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#fill_in' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.fill_in('new_field', :with => 'Testing...')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#check' do
|
||||
it "should trigger associated events" do
|
||||
@session.visit('/with_js')
|
||||
@session.check('checkbox_with_event')
|
||||
@session.should have_css('#checkbox_event_triggered');
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_xpath?' do
|
||||
it "should wait for content to appear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_xpath("//input[@type='submit' and @value='New Here']")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_no_xpath?' do
|
||||
it "should wait for content to disappear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_no_xpath("//p[@id='change']")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_css?' do
|
||||
it "should wait for content to appear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_css("input[type='submit'][value='New Here']")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_no_xpath?' do
|
||||
it "should wait for content to disappear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_no_css("p#change")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_content?' do
|
||||
it "should wait for content to appear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_content("Has been clicked")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_no_content?' do
|
||||
it "should wait for content to disappear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_no_content("I changed it")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for "session without javascript support" do
|
||||
describe "#evaluate_script" do
|
||||
before{ @session.visit('/with_simple_html') }
|
||||
it "should raise an error" do
|
||||
running {
|
||||
@session.evaluate_script('3 + 3')
|
||||
}.should raise_error(Capybara::NotSupportedByDriverError)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -31,6 +31,18 @@ shared_examples_for "select" do
|
|||
extract_results(@session)['title'].should == 'Mr'
|
||||
end
|
||||
|
||||
it "should escape quotes" do
|
||||
@session.select("John's made-up language", :from => 'Locale')
|
||||
@session.click_button('awesome')
|
||||
extract_results(@session)['locale'].should == 'jo'
|
||||
end
|
||||
|
||||
it "match labels with preceding or trailing whitespace" do
|
||||
@session.select("Lojban", :from => 'Locale')
|
||||
@session.click_button('awesome')
|
||||
extract_results(@session)['locale'].should == 'jbo'
|
||||
end
|
||||
|
||||
context "with a locator that doesn't exist" do
|
||||
it "should raise an error" do
|
||||
running { @session.select('foo', :from => 'does not exist') }.should raise_error(Capybara::ElementNotFound)
|
|
@ -25,6 +25,12 @@ shared_examples_for "unselect" do
|
|||
extract_results(@session)['underwear'].should include('Commando', 'Boxer Briefs')
|
||||
extract_results(@session)['underwear'].should_not include('Briefs')
|
||||
end
|
||||
|
||||
it "should escape quotes" do
|
||||
@session.unselect("Frenchman's Pantalons", :from => 'Underwear')
|
||||
@session.click_button('awesome')
|
||||
extract_results(@session)['underwear'].should_not include("Frenchman's Pantalons")
|
||||
end
|
||||
end
|
||||
|
||||
context "with single select" do
|
|
@ -42,6 +42,10 @@ class TestApp < Sinatra::Base
|
|||
redirect '/redirect_again'
|
||||
end
|
||||
|
||||
delete "/delete" do
|
||||
"The requested object was deleted"
|
||||
end
|
||||
|
||||
get '/redirect_back' do
|
||||
redirect back
|
||||
end
|
|
@ -33,6 +33,11 @@
|
|||
<input type="text" name="form[name]" value="John Smith" id="form_name"/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="form_schmooo">Schmooo</label>
|
||||
<input type="schmooo" name="form[schmooo]" value="This is Schmooo!" id="form_schmooo"/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>Street<br/>
|
||||
<input type="text" name="form[street]" value="Sesame street 66"/>
|
||||
|
@ -71,6 +76,8 @@
|
|||
<option selected="selected" value="en">English</option>
|
||||
<option value="fi">Finish</option>
|
||||
<option value="no">Norwegian</option>
|
||||
<option value="jo">John's made-up language</option>
|
||||
<option value="jbo"> Lojban </option>
|
||||
</select>
|
||||
</p>
|
||||
|
||||
|
@ -137,6 +144,7 @@
|
|||
<option>Boxers</option>
|
||||
<option selected="selected">Briefs</option>
|
||||
<option selected="selected">Commando</option>
|
||||
<option selected="selected">Frenchman's Pantalons</option>
|
||||
</select>
|
||||
</p>
|
||||
|
||||
|
@ -151,8 +159,9 @@
|
|||
<input type="button" name="form[fresh]" id="fresh_btn" value="i am fresh"/>
|
||||
<input type="submit" name="form[awesome]" id="awe123" value="awesome"/>
|
||||
<input type="submit" name="form[crappy]" id="crap321" value="crappy"/>
|
||||
<input type="image" name="form[okay]" id="okay556" value="okay"/>
|
||||
<input type="image" name="form[okay]" id="okay556" value="okay" alt="oh hai thar"/>
|
||||
<button type="submit" id="click_me_123" value="click_me">Click me!</button>
|
||||
<button type="submit" name="form[no_value]">No Value!</button>
|
||||
</p>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>This is the title of frame one</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="divInFrameOne">This is the text of divInFrameOne</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>This is the title of frame two</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="divInFrameTwo">This is the text of divInFrameTwo</div>
|
||||
</body>
|
||||
</html>
|
|
@ -12,7 +12,10 @@
|
|||
<p id="second">
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
|
||||
dolore eu fugiat <a href="/redirect" id="red">Redirect</a> pariatur. Excepteur sint occaecat cupidatat non proident,
|
||||
sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
sunt in culpa qui officia
|
||||
text with
|
||||
whitespace
|
||||
id est laborum.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
@ -20,6 +23,7 @@
|
|||
<a href="/redirect_back">BackToMyself</a>
|
||||
<a title="twas a fine link" href="/redirect">A link came first</a>
|
||||
<a title="a fine link" href="/with_simple_html">A link</a>
|
||||
<a title="a fine link with data method" data-method="delete" href="/delete">A link with data-method</a>
|
||||
<a>No Href</a>
|
||||
<a href="">Blank Href</a>
|
||||
<a href="#">Blank Anchor</a>
|
|
@ -30,5 +30,10 @@
|
|||
<p>
|
||||
<input type="text" name="with_focus_event" value="" id="with_focus_event"/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input type="checkbox" id="checkbox_with_event"/>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>With Frames</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="divInMainWindow">This is the text for divInMainWindow</div>
|
||||
<iframe src="/frame_one" id="frameOne"></iframe>
|
||||
<iframe src="/frame_two" id="frameTwo"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,3 @@
|
|||
module Capybara
|
||||
VERSION = '0.3.8'
|
||||
end
|
|
@ -4,7 +4,7 @@ module Capybara
|
|||
|
||||
class << self
|
||||
|
||||
def timeout(seconds = 1, &block)
|
||||
def timeout(seconds = 1, driver = nil, &block)
|
||||
start_time = Time.now
|
||||
|
||||
result = nil
|
||||
|
@ -12,9 +12,14 @@ module Capybara
|
|||
until result
|
||||
return result if result = yield
|
||||
|
||||
if (Time.now - start_time) > seconds
|
||||
raise TimeoutError
|
||||
delay = seconds - (Time.now - start_time)
|
||||
if delay <= 0
|
||||
raise TimeoutError
|
||||
end
|
||||
|
||||
driver && driver.wait_until(delay)
|
||||
|
||||
sleep(0.05)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -5,10 +5,16 @@ module Capybara
|
|||
class XPath
|
||||
|
||||
class << self
|
||||
def from_css(css)
|
||||
Nokogiri::CSS.xpath_for(css).first
|
||||
def escape(string)
|
||||
if string.include?("'")
|
||||
string = string.split("'", -1).map do |substr|
|
||||
"'#{substr}'"
|
||||
end.join(%q{,"'",})
|
||||
"concat(#{string})"
|
||||
else
|
||||
"'#{string}'"
|
||||
end
|
||||
end
|
||||
alias_method :for_css, :from_css
|
||||
|
||||
def wrap(path)
|
||||
if path.is_a?(self)
|
||||
|
@ -33,6 +39,27 @@ module Capybara
|
|||
@paths = paths
|
||||
end
|
||||
|
||||
def scope(scope)
|
||||
XPath.new(*paths.map { |p| scope + p })
|
||||
end
|
||||
|
||||
def to_s
|
||||
@paths.join(' | ')
|
||||
end
|
||||
|
||||
def append(path)
|
||||
XPath.new(*[@paths, XPath.wrap(path).paths].flatten)
|
||||
end
|
||||
|
||||
def prepend(path)
|
||||
XPath.new(*[XPath.wrap(path).paths, @paths].flatten)
|
||||
end
|
||||
|
||||
def from_css(css)
|
||||
append(Nokogiri::CSS.xpath_for(css).first)
|
||||
end
|
||||
alias_method :for_css, :from_css
|
||||
|
||||
def field(locator, options={})
|
||||
if options[:with]
|
||||
fillable_field(locator, options)
|
||||
|
@ -46,13 +73,11 @@ module Capybara
|
|||
end
|
||||
|
||||
def fillable_field(locator, options={})
|
||||
[:text, :password, :email, :url, :search, :tel, :color].inject(text_area(locator, options)) do |all, type|
|
||||
all.input_field(type, locator, options)
|
||||
end
|
||||
text_area(locator, options).text_field(locator, options)
|
||||
end
|
||||
|
||||
def content(locator)
|
||||
append("/descendant-or-self::*[contains(.,#{s(locator)})]")
|
||||
append("/descendant-or-self::*[contains(normalize-space(.),#{s(locator)})]")
|
||||
end
|
||||
|
||||
def table(locator, options={})
|
||||
|
@ -80,9 +105,15 @@ module Capybara
|
|||
xpath = append("//input[@type='submit' or @type='image' or @type='button'][@id=#{s(locator)} or contains(@value,#{s(locator)})]")
|
||||
xpath = xpath.append("//button[@id=#{s(locator)} or contains(@value,#{s(locator)}) or contains(.,#{s(locator)})]")
|
||||
xpath = xpath.prepend("//input[@type='submit' or @type='image' or @type='button'][@value=#{s(locator)}]")
|
||||
xpath = xpath.prepend("//input[@type='image'][@alt=#{s(locator)} or contains(@alt,#{s(locator)})]")
|
||||
xpath = xpath.prepend("//button[@value=#{s(locator)} or text()=#{s(locator)}]")
|
||||
end
|
||||
|
||||
def text_field(locator, options={})
|
||||
options = options.merge(:value => options[:with]) if options.has_key?(:with)
|
||||
add_field(locator, "//input[@type!='radio' and @type!='checkbox' and @type!='hidden']", options)
|
||||
end
|
||||
|
||||
def text_area(locator, options={})
|
||||
options = options.merge(:text => options[:with]) if options.has_key?(:with)
|
||||
add_field(locator, "//textarea", options)
|
||||
|
@ -92,27 +123,6 @@ module Capybara
|
|||
add_field(locator, "//select", options)
|
||||
end
|
||||
|
||||
def input_field(type, locator, options={})
|
||||
options = options.merge(:value => options[:with]) if options.has_key?(:with)
|
||||
add_field(locator, "//input[@type='#{type}']", options)
|
||||
end
|
||||
|
||||
def scope(scope)
|
||||
XPath.new(*paths.map { |p| scope + p })
|
||||
end
|
||||
|
||||
def to_s
|
||||
@paths.join(' | ')
|
||||
end
|
||||
|
||||
def append(path)
|
||||
XPath.new(*[@paths, XPath.wrap(path).paths].flatten)
|
||||
end
|
||||
|
||||
def prepend(path)
|
||||
XPath.new(*[XPath.wrap(path).paths, @paths].flatten)
|
||||
end
|
||||
|
||||
def checkbox(locator, options={})
|
||||
input_field(:checkbox, locator, options)
|
||||
end
|
||||
|
@ -121,16 +131,17 @@ module Capybara
|
|||
input_field(:radio, locator, options)
|
||||
end
|
||||
|
||||
[:text, :password, :email, :url, :search, :tel, :color, :file].each do |type|
|
||||
class_eval <<-RUBY, __FILE__, __LINE__+1
|
||||
def #{type}_field(locator)
|
||||
input_field(:#{type}, locator)
|
||||
end
|
||||
RUBY
|
||||
def file_field(locator, options={})
|
||||
input_field(:file, locator, options)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def input_field(type, locator, options={})
|
||||
options = options.merge(:value => options[:with]) if options.has_key?(:with)
|
||||
add_field(locator, "//input[@type='#{type}']", options)
|
||||
end
|
||||
|
||||
# place this between to nodes to indicate that they should be siblings
|
||||
def sibling
|
||||
'/following-sibling::*[1]/self::'
|
||||
|
@ -161,15 +172,7 @@ module Capybara
|
|||
|
||||
# Sanitize a String for putting it into an xpath query
|
||||
def s(string)
|
||||
if string.include?("'")
|
||||
string = string.split("'", -1).map do |substr|
|
||||
"'#{substr}'"
|
||||
end.join(%q{,"'",})
|
||||
"concat(#{string})"
|
||||
else
|
||||
"'#{string}'"
|
||||
end
|
||||
|
||||
XPath.escape(string)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# File: script/console
|
||||
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
||||
|
||||
libs = " -r irb/completion"
|
||||
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
||||
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
||||
libs << " -r #{File.dirname(__FILE__) + '/../lib/capybara.rb'}"
|
||||
puts "Loading capybara gem"
|
||||
exec "#{irb} #{libs} --simple-prompt"
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
||||
|
||||
begin
|
||||
require 'rubigen'
|
||||
rescue LoadError
|
||||
require 'rubygems'
|
||||
require 'rubigen'
|
||||
end
|
||||
require 'rubigen/scripts/destroy'
|
||||
|
||||
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
||||
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
||||
RubiGen::Scripts::Destroy.new.run(ARGV)
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
||||
|
||||
begin
|
||||
require 'rubigen'
|
||||
rescue LoadError
|
||||
require 'rubygems'
|
||||
require 'rubigen'
|
||||
end
|
||||
require 'rubigen/scripts/generate'
|
||||
|
||||
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
||||
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
||||
RubiGen::Scripts::Generate.new.run(ARGV)
|
|
@ -2,14 +2,13 @@ require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
|||
|
||||
if RUBY_PLATFORM =~ /java/
|
||||
describe Capybara::Driver::Celerity do
|
||||
before do
|
||||
before(:all) do
|
||||
@driver = Capybara::Driver::Celerity.new(TestApp)
|
||||
end
|
||||
|
||||
it_should_behave_like "driver"
|
||||
it_should_behave_like "driver with javascript support"
|
||||
it_should_behave_like "driver with header support"
|
||||
it_should_behave_like "driver with node path support"
|
||||
|
||||
end
|
||||
else
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
||||
|
||||
describe Capybara::Driver::Culerity do
|
||||
before do
|
||||
before(:all) do
|
||||
@driver = Capybara::Driver::Culerity.new(TestApp)
|
||||
end
|
||||
|
||||
it_should_behave_like "driver"
|
||||
it_should_behave_like "driver with javascript support"
|
||||
it_should_behave_like "driver with header support"
|
||||
it_should_behave_like "driver with node path support"
|
||||
|
||||
end
|
||||
|
|
|
@ -5,8 +5,13 @@ describe Capybara::Driver::RackTest do
|
|||
@driver = Capybara::Driver::RackTest.new(TestApp)
|
||||
end
|
||||
|
||||
it "should throw an error when no rack app is given" do
|
||||
running do
|
||||
Capybara::Driver::RackTest.new(nil)
|
||||
end.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it_should_behave_like "driver"
|
||||
it_should_behave_like "driver with header support"
|
||||
it_should_behave_like "driver with node path support"
|
||||
|
||||
end
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
||||
|
||||
describe Capybara::Driver::Culerity do
|
||||
before do
|
||||
@driver = Capybara::Driver::Culerity.new(TestApp)
|
||||
end
|
||||
|
||||
before(:all) do
|
||||
Capybara.app_host = "http://capybara-testapp.heroku.com"
|
||||
Capybara.run_server = false
|
||||
@driver = Capybara::Driver::Culerity.new(TestApp)
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
|
|
|
@ -7,6 +7,5 @@ describe Capybara::Driver::Selenium do
|
|||
|
||||
it_should_behave_like "driver"
|
||||
it_should_behave_like "driver with javascript support"
|
||||
it_should_behave_like "driver without node path support"
|
||||
|
||||
it_should_behave_like "driver with frame support"
|
||||
end
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
module CheckSpec
|
||||
shared_examples_for "check" do
|
||||
|
||||
describe "#check" do
|
||||
before do
|
||||
@session.visit('/form')
|
||||
end
|
||||
|
||||
describe "'checked' attribute" do
|
||||
it "should be true if checked" do
|
||||
@session.check("Terms of Use")
|
||||
@session.find(:xpath, "//input[@id='form_terms_of_use']")['checked'].should be_true
|
||||
end
|
||||
|
||||
it "should be false if unchecked" do
|
||||
@session.find(:xpath, "//input[@id='form_terms_of_use']")['checked'].should be_false
|
||||
end
|
||||
end
|
||||
|
||||
it "should check a checkbox by id" do
|
||||
@session.check("form_pets_cat")
|
||||
@session.click_button('awesome')
|
||||
extract_results(@session)['pets'].should include('dog', 'cat', 'hamster')
|
||||
end
|
||||
|
||||
it "should check a checkbox by label" do
|
||||
@session.check("Cat")
|
||||
@session.click_button('awesome')
|
||||
extract_results(@session)['pets'].should include('dog', 'cat', 'hamster')
|
||||
end
|
||||
|
||||
context "with a locator that doesn't exist" do
|
||||
it "should raise an error" do
|
||||
running { @session.check('does not exist') }.should raise_error(Capybara::ElementNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,8 +26,8 @@ module Capybara
|
|||
|
||||
context "with :text filter" do
|
||||
before do
|
||||
@node1 = stub(Node, :text => 'node one text')
|
||||
@node2 = stub(Node, :text => 'node two text')
|
||||
@node1 = stub(Node, :text => 'node one text (with parens)')
|
||||
@node2 = stub(Node, :text => 'node two text [-]')
|
||||
@searchable.stub(:all_unfiltered).and_return([@node1, @node2])
|
||||
end
|
||||
|
||||
|
@ -40,6 +40,11 @@ module Capybara
|
|||
@searchable.all('//x', :text => "node one").should == [@node1]
|
||||
@searchable.all('//x', :text => "node two").should == [@node2]
|
||||
end
|
||||
|
||||
it "should allow Regexp reserved words in text" do
|
||||
@searchable.all('//x', :text => "node one text (with parens)").should == [@node1]
|
||||
@searchable.all('//x', :text => "node two text [-]").should == [@node2]
|
||||
end
|
||||
end
|
||||
|
||||
context "with :visible filter" do
|
||||
|
|
|
@ -11,6 +11,12 @@ describe Capybara::Server do
|
|||
@res.body.should include('Hello Server')
|
||||
end
|
||||
|
||||
it "should do nothing when no server given" do
|
||||
running do
|
||||
@server = Capybara::Server.new(nil).boot
|
||||
end.should_not raise_error
|
||||
end
|
||||
|
||||
it "should find an available port" do
|
||||
@app1 = proc { |env| [200, {}, "Hello Server!"]}
|
||||
@app2 = proc { |env| [200, {}, "Hello Second Server!"]}
|
||||
|
|
|
@ -2,7 +2,7 @@ require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
|||
|
||||
if RUBY_PLATFORM =~ /java/
|
||||
describe Capybara::Driver::Celerity do
|
||||
before do
|
||||
before(:all) do
|
||||
@session = Capybara::Session.new(:celerity, TestApp)
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
|||
|
||||
describe Capybara::Session do
|
||||
context 'with culerity driver' do
|
||||
before do
|
||||
before(:all) do
|
||||
@session = Capybara::Session.new(:culerity, TestApp)
|
||||
end
|
||||
|
||||
|
|
|
@ -18,6 +18,14 @@ describe Capybara::Session do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#click_link' do
|
||||
it "should use data-method if available" do
|
||||
@session.visit "/with_html"
|
||||
@session.click_link "A link with data-method"
|
||||
@session.body.should == 'The requested object was deleted'
|
||||
end
|
||||
end
|
||||
|
||||
it_should_behave_like "session"
|
||||
it_should_behave_like "session without javascript support"
|
||||
it_should_behave_like "session with headers support"
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
||||
|
||||
|
||||
shared_examples_for "session with headers support" do
|
||||
|
||||
describe '#response_headers' do
|
||||
it "should return response headers" do
|
||||
@session.visit('/with_simple_html')
|
||||
@session.response_headers['Content-Type'].should == 'text/html'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,182 +0,0 @@
|
|||
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
||||
|
||||
require 'nokogiri'
|
||||
|
||||
shared_examples_for "session with javascript support" do
|
||||
before do
|
||||
Capybara.default_wait_time = 1
|
||||
end
|
||||
|
||||
after do
|
||||
Capybara.default_wait_time = 0
|
||||
end
|
||||
|
||||
describe '#find' do
|
||||
it "should allow triggering of custom JS events" do
|
||||
pending "cannot figure out how to do this with selenium" if @session.mode == :selenium
|
||||
@session.visit('/with_js')
|
||||
@session.find(:css, '#with_focus_event').trigger(:focus)
|
||||
@session.should have_css('#focus_event_triggered')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#body' do
|
||||
it "should return the current state of the page" do
|
||||
@session.visit('/with_js')
|
||||
@session.body.should include('I changed it')
|
||||
@session.body.should_not include('This is text')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#source' do
|
||||
it "should return the original, unmodified source of the page" do
|
||||
pending "cannot figure out how to do this with selenium" if @session.mode == :selenium
|
||||
@session.visit('/with_js')
|
||||
@session.source.should include('This is text')
|
||||
@session.source.should_not include('I changed it')
|
||||
end
|
||||
end
|
||||
|
||||
describe "#evaluate_script" do
|
||||
it "should return the evaluated script" do
|
||||
@session.visit('/with_js')
|
||||
@session.evaluate_script("1+3").should == 4
|
||||
end
|
||||
end
|
||||
|
||||
describe '#locate' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.locate("//a[contains(.,'Has been clicked')]")[:href].should == '#'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#wait_until' do
|
||||
before do
|
||||
@default_timeout = Capybara.default_wait_time
|
||||
end
|
||||
|
||||
after do
|
||||
Capybara.default_wait_time = @default_wait_time
|
||||
end
|
||||
|
||||
it "should wait for block to return true" do
|
||||
@session.visit('/with_js')
|
||||
@session.select('My Waiting Option', :from => 'waiter')
|
||||
@session.evaluate_script('activeRequests == 1').should be_true
|
||||
@session.wait_until do
|
||||
@session.evaluate_script('activeRequests == 0')
|
||||
end
|
||||
@session.evaluate_script('activeRequests == 0').should be_true
|
||||
end
|
||||
|
||||
it "should raise Capybara::TimeoutError if block doesn't return true within timeout" do
|
||||
@session.visit('/with_html')
|
||||
Proc.new do
|
||||
@session.wait_until(0.1) do
|
||||
@session.find('//div[@id="nosuchthing"]')
|
||||
end
|
||||
end.should raise_error(::Capybara::TimeoutError)
|
||||
end
|
||||
|
||||
it "should accept custom timeout in seconds" do
|
||||
start = Time.now
|
||||
Capybara.default_wait_time = 5
|
||||
begin
|
||||
@session.wait_until(0.1) { false }
|
||||
rescue Capybara::TimeoutError; end
|
||||
(Time.now - start).should be_close(0.1, 0.1)
|
||||
end
|
||||
|
||||
it "should default to Capybara.default_wait_time before timeout" do
|
||||
start = Time.now
|
||||
Capybara.default_wait_time = 0.2
|
||||
begin
|
||||
@session.wait_until { false }
|
||||
rescue Capybara::TimeoutError; end
|
||||
(Time.now - start).should be_close(0.2, 0.1)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#click' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.click('Has been clicked')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#click_link' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.click_link('Has been clicked')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#click_button' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.click_button('New Here')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#fill_in' do
|
||||
it "should wait for asynchronous load" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.fill_in('new_field', :with => 'Testing...')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_xpath?' do
|
||||
it "should wait for content to appear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_xpath("//input[@type='submit' and @value='New Here']")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_no_xpath?' do
|
||||
it "should wait for content to disappear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_no_xpath("//p[@id='change']")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_css?' do
|
||||
it "should wait for content to appear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_css("input[type='submit'][value='New Here']")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_no_xpath?' do
|
||||
it "should wait for content to disappear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_no_css("p#change")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_content?' do
|
||||
it "should wait for content to appear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_content("Has been clicked")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_no_content?' do
|
||||
it "should wait for content to disappear" do
|
||||
@session.visit('/with_js')
|
||||
@session.click_link('Click me')
|
||||
@session.should have_no_content("I changed it")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
||||
|
||||
require 'nokogiri'
|
||||
|
||||
shared_examples_for "session without headers support" do
|
||||
describe "#evaluate_script" do
|
||||
before{ @session.visit('/with_simple_html') }
|
||||
it "should raise an error" do
|
||||
running {
|
||||
@session.response_headers
|
||||
}.should raise_error(Capybara::NotSupportedByDriverError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
||||
|
||||
require 'nokogiri'
|
||||
|
||||
shared_examples_for "session without javascript support" do
|
||||
describe "#evaluate_script" do
|
||||
before{ @session.visit('/with_js') }
|
||||
it "should raise an error" do
|
||||
running {
|
||||
@session.evaluate_script("1+5")
|
||||
}.should raise_error(Capybara::NotSupportedByDriverError)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -5,16 +5,8 @@ require 'rubygems'
|
|||
require 'spec'
|
||||
require 'spec/autorun'
|
||||
require 'capybara'
|
||||
require 'test_app'
|
||||
require 'drivers_spec'
|
||||
require 'session_spec'
|
||||
Dir[File.dirname(__FILE__)+'/dsl/*'].each { |group|
|
||||
require group
|
||||
}
|
||||
require 'session_with_javascript_support_spec'
|
||||
require 'session_without_javascript_support_spec'
|
||||
require 'session_with_headers_support_spec'
|
||||
require 'session_without_headers_support_spec'
|
||||
require 'capybara/spec/driver'
|
||||
require 'capybara/spec/session'
|
||||
|
||||
alias :running :lambda
|
||||
|
||||
|
|
|
@ -83,10 +83,8 @@ describe Capybara::XPath do
|
|||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.field('First Name').input_field(:password, 'First Name').to_s
|
||||
@query = @xpath.field('First Name').button('Click me!').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.field('Password').input_field(:password, 'Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -101,42 +99,8 @@ describe Capybara::XPath do
|
|||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.fillable_field('First Name').password_field('First Name').to_s
|
||||
@query = @xpath.fillable_field('First Name').button('Click me!').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.fillable_field('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#text_field' do
|
||||
it "should find a text field by id or label" do
|
||||
@query = @xpath.text_field('form_first_name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.text_field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.text_field('First Name').password_field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.text_field('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#password_field' do
|
||||
it "should find a password field by id or label" do
|
||||
@query = @xpath.password_field('form_password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
@query = @xpath.password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.password_field('First Name').text_field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.password_field('Password').text_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -149,10 +113,8 @@ describe Capybara::XPath do
|
|||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.text_area('Description').password_field('Description').to_s
|
||||
@query = @xpath.text_area('Description').button('Click me!').to_s
|
||||
@driver.find(@query).first.text.should == 'Descriptive text goes here'
|
||||
@query = @xpath.text_area('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -182,10 +144,8 @@ describe Capybara::XPath do
|
|||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.radio_button('Male').password_field('Male').to_s
|
||||
@query = @xpath.radio_button('Male').button('Click me!').to_s
|
||||
@driver.find(@query).first.value.should == 'male'
|
||||
@query = @xpath.radio_button('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -198,10 +158,8 @@ describe Capybara::XPath do
|
|||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.checkbox('Cat').password_field('Cat').to_s
|
||||
@query = @xpath.checkbox('Cat').button('Click me!').to_s
|
||||
@driver.find(@query).first.value.should == 'cat'
|
||||
@query = @xpath.checkbox('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -214,58 +172,9 @@ describe Capybara::XPath do
|
|||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.select('Region').password_field('Region').to_s
|
||||
@query = @xpath.select('Region').button('Click me!').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[region]'
|
||||
@query = @xpath.select('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#file_field' do
|
||||
it "should find a file field by id or label" do
|
||||
@query = @xpath.file_field('Document').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[document]'
|
||||
@query = @xpath.file_field('form_document').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[document]'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.file_field('Document').password_field('Document').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[document]'
|
||||
@query = @xpath.file_field('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
[ [:email_field, 'html5_email', 'Html5 Email', 'person@email.com'],
|
||||
[:url_field, 'html5_url', 'Html5 Url', 'http://www.example.com'],
|
||||
[:search_field, 'html5_search', 'Html5 Search', 'what are you looking for'],
|
||||
[:tel_field, 'html5_tel', 'Html5 Tel', '911'],
|
||||
[:color_field, 'html5_color', 'Html5 Color', '#FFF']].each do |method, id, label, output|
|
||||
describe "##{method}" do
|
||||
it "should find a file field by label" do
|
||||
@query = @xpath.send(method, label).to_s
|
||||
@driver.find(@query).first.value.should == output
|
||||
end
|
||||
|
||||
it "should find a file field by id" do
|
||||
@query = @xpath.send(method, id).to_s
|
||||
@driver.find(@query).first.value.should == output
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.send(method, label).password_field(label).to_s
|
||||
@driver.find(@query).first.value.should == output
|
||||
@query = @xpath.send(method, 'Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
|
||||
it "should be a #fillable_field" do
|
||||
@query = @xpath.fillable_field(label).to_s
|
||||
@driver.find(@query).first.value.should == output
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue