capybara 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +51 -3
- data/README.rdoc +10 -5
- data/lib/capybara.rb +1 -1
- data/lib/capybara/driver/base.rb +7 -0
- data/lib/capybara/driver/rack_test_driver.rb +28 -14
- data/lib/capybara/driver/selenium_driver.rb +2 -2
- data/lib/capybara/node.rb +0 -9
- data/lib/capybara/server.rb +1 -0
- data/lib/capybara/session.rb +15 -35
- data/lib/capybara/wait_until.rb +6 -3
- data/lib/capybara/xpath.rb +35 -36
- data/spec/driver/celerity_driver_spec.rb +0 -1
- data/spec/dsl/fill_in_spec.rb +13 -0
- data/spec/dsl/has_content_spec.rb +5 -0
- data/spec/public/test.js +4 -1
- data/spec/server_spec.rb +6 -0
- data/spec/session_with_javascript_support_spec.rb +14 -1
- data/spec/views/form.erb +5 -0
- data/spec/views/with_html.erb +4 -1
- data/spec/views/with_js.erb +5 -0
- data/spec/xpath_spec.rb +6 -97
- metadata +83 -41
data/History.txt
CHANGED
@@ -1,4 +1,52 @@
|
|
1
|
-
|
1
|
+
# Version 0.3.6
|
2
|
+
|
3
|
+
Release date: 2010-03-22
|
4
|
+
|
5
|
+
This is a maintainance release with minor bug fixes, should be
|
6
|
+
drop in compatible.
|
7
|
+
|
8
|
+
### Added
|
9
|
+
|
10
|
+
* It's now possible to load in external drivers
|
11
|
+
|
12
|
+
### Fixed
|
13
|
+
|
14
|
+
* has_content? ignores whitespace
|
15
|
+
* Trigger events when choosing radios and checking checkboxes under Selenium
|
16
|
+
* Make Capybara.app totally optional when running without server
|
17
|
+
* Changed fallback host so it matches the one set up by Rails' integration tests
|
18
|
+
|
19
|
+
# Version 0.3.5
|
20
|
+
|
21
|
+
Release date: 2010-02-26
|
22
|
+
|
23
|
+
This is a mostly backwards compatible release, it does break
|
24
|
+
the API in some minor places, which should hopefully not affect
|
25
|
+
too many users, please read the release notes carefully!
|
26
|
+
|
27
|
+
### Breaking
|
28
|
+
|
29
|
+
* Relative searching in a node (e.g. find('//p').all('//a')) will now follow XPath standard
|
30
|
+
this means that if you want to find descendant nodes only, you'll need to prefix a dot!
|
31
|
+
* `visit` now accepts fully qualified URLs for drivers that support it.
|
32
|
+
* Capybara will always try to run a rack server, unless you set Capybara.run_sever = false
|
33
|
+
|
34
|
+
### Changed
|
35
|
+
|
36
|
+
* thin is preferred over mongrel and webrick, since it is Ruby 1.9 compatible
|
37
|
+
* click_button and click will find <input type="button">, clicking them does nothing in RackTest
|
38
|
+
|
39
|
+
### Added
|
40
|
+
|
41
|
+
* Much improved error messages in a multitude of places
|
42
|
+
* More semantic page querying with has_link?, has_button?, etc...
|
43
|
+
* Option to ignore hidden elements when querying and interacting with the page
|
44
|
+
* Support for multiple selects
|
45
|
+
|
46
|
+
### Fixed
|
47
|
+
|
48
|
+
* find_by_id is no longer broken
|
49
|
+
* clicking links where the image's alt attribute contains the text is now possible
|
50
|
+
* within_fieldset and within_table work when the default selector is CSS
|
51
|
+
* boolean attributes work the same across drivers (return true/false)
|
2
52
|
|
3
|
-
* 1 major enhancement:
|
4
|
-
* Initial release
|
data/README.rdoc
CHANGED
@@ -55,6 +55,9 @@ Now you can use it in your steps:
|
|
55
55
|
click_link 'Sign in'
|
56
56
|
end
|
57
57
|
|
58
|
+
Please note that while Capybara uses XPath selectors by default, Cucumber explicitly
|
59
|
+
changes this to CSS in `env.rb`. See "XPath and CSS" below.
|
60
|
+
|
58
61
|
== Default and current driver
|
59
62
|
|
60
63
|
You can set up a default driver for your features. For example if you'd prefer
|
@@ -151,7 +154,7 @@ with the various form elements:
|
|
151
154
|
fill_in('First Name', :with => 'John')
|
152
155
|
fill_in('Password', :with => 'Seekrit')
|
153
156
|
fill_in('Description', :with => 'Really Long Text…')
|
154
|
-
choose('
|
157
|
+
choose('A Radio Button')
|
155
158
|
check('A Checkbox')
|
156
159
|
uncheck('A Checkbox')
|
157
160
|
attach_file('Image', '/path/to/image.jpg')
|
@@ -177,7 +180,7 @@ You can choose which kind of selector Capybara uses by default, by setting
|
|
177
180
|
|
178
181
|
There are special methods for restricting the scope to a specific fieldset,
|
179
182
|
identified by either an id or the text of the fieldet's legend tag, and to a
|
180
|
-
specific table, identified by either
|
183
|
+
specific table, identified by either id or text of the table's caption tag.
|
181
184
|
|
182
185
|
within_fieldset('Employee') do
|
183
186
|
fill_in 'Name', :with => 'Jimmy'
|
@@ -255,7 +258,7 @@ is (the default is 2 seconds):
|
|
255
258
|
Capybara.default_wait_time = 5
|
256
259
|
|
257
260
|
Be aware that because of this behaviour, the following two statements are *not*
|
258
|
-
|
261
|
+
equivalent, and you should *always* use the latter!
|
259
262
|
|
260
263
|
page.should_not have_xpath('//a')
|
261
264
|
page.should have_no_xpath('//a')
|
@@ -263,12 +266,12 @@ identical, and you should *always* use the latter!
|
|
263
266
|
The former would incorrectly wait for the content to appear, since the
|
264
267
|
asynchronous process has not yet removed the element from the page, it would
|
265
268
|
therefore fail, even though the code might be working correctly. The latter
|
266
|
-
correctly
|
269
|
+
correctly waits for the element to disappear from the page.
|
267
270
|
|
268
271
|
== Using the DSL outside cucumber
|
269
272
|
|
270
273
|
You can mix the DSL into any context, for example you could use it in RSpec
|
271
|
-
examples. Just load the
|
274
|
+
examples. Just load the DSL and include it anywhere:
|
272
275
|
|
273
276
|
require 'capybara'
|
274
277
|
require 'capybara/dsl'
|
@@ -378,6 +381,8 @@ The following people have dedicated their time and effort to Capybara:
|
|
378
381
|
* Bodaniel Jeanes
|
379
382
|
* Carl Porth
|
380
383
|
* Darrin Holst
|
384
|
+
* Steven Parkes
|
385
|
+
* Davide Marquês
|
381
386
|
|
382
387
|
== License:
|
383
388
|
|
data/lib/capybara.rb
CHANGED
data/lib/capybara/driver/base.rb
CHANGED
@@ -19,6 +19,9 @@ class Capybara::Driver::Base
|
|
19
19
|
false
|
20
20
|
end
|
21
21
|
|
22
|
+
def wait_until *args
|
23
|
+
end
|
24
|
+
|
22
25
|
def response_headers
|
23
26
|
raise Capybara::NotSupportedByDriverError
|
24
27
|
end
|
@@ -34,4 +37,8 @@ class Capybara::Driver::Base
|
|
34
37
|
def cleanup!
|
35
38
|
end
|
36
39
|
|
40
|
+
def has_shortcircuit_timeout?
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
37
44
|
end
|
@@ -28,9 +28,7 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
28
28
|
|
29
29
|
|
30
30
|
def set(value)
|
31
|
-
if tag_name == 'input' and
|
32
|
-
node['value'] = value.to_s
|
33
|
-
elsif tag_name == 'input' and type == 'radio'
|
31
|
+
if tag_name == 'input' and type == 'radio'
|
34
32
|
driver.html.xpath("//input[@name='#{self[:name]}']").each { |node| node.remove_attribute("checked") }
|
35
33
|
node['checked'] = 'checked'
|
36
34
|
elsif tag_name == 'input' and type == 'checkbox'
|
@@ -39,6 +37,8 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
39
37
|
else
|
40
38
|
node.remove_attribute('checked')
|
41
39
|
end
|
40
|
+
elsif tag_name == 'input'
|
41
|
+
node['value'] = value.to_s
|
42
42
|
elsif tag_name == "textarea"
|
43
43
|
node.content = value.to_s
|
44
44
|
end
|
@@ -111,9 +111,7 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
111
111
|
def params(button)
|
112
112
|
params = {}
|
113
113
|
|
114
|
-
|
115
|
-
|
116
|
-
node.xpath(".//input[#{text_fields}]").map do |input|
|
114
|
+
node.xpath(".//input[@type!='radio' and @type!='checkbox' and @type!='submit']").map do |input|
|
117
115
|
merge_param!(params, input['name'].to_s, input['value'].to_s)
|
118
116
|
end
|
119
117
|
node.xpath(".//textarea").map do |textarea|
|
@@ -178,11 +176,10 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
178
176
|
end
|
179
177
|
|
180
178
|
include ::Rack::Test::Methods
|
181
|
-
attr_reader :app
|
179
|
+
attr_reader :app
|
182
180
|
|
183
181
|
alias_method :response, :last_response
|
184
182
|
alias_method :request, :last_request
|
185
|
-
alias_method :source, :body
|
186
183
|
|
187
184
|
def initialize(app)
|
188
185
|
@app = app
|
@@ -192,7 +189,6 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
192
189
|
return if path.gsub(/^#{current_path}/, '') =~ /^#/
|
193
190
|
get(path, attributes, env)
|
194
191
|
follow_redirects!
|
195
|
-
cache_body
|
196
192
|
end
|
197
193
|
|
198
194
|
def current_url
|
@@ -207,17 +203,35 @@ class Capybara::Driver::RackTest < Capybara::Driver::Base
|
|
207
203
|
path = current_path if not path or path.empty?
|
208
204
|
send(method, path, attributes, env)
|
209
205
|
follow_redirects!
|
210
|
-
cache_body
|
211
206
|
end
|
212
207
|
|
213
208
|
def find(selector)
|
214
209
|
html.xpath(selector).map { |node| Node.new(self, node) }
|
215
210
|
end
|
211
|
+
|
212
|
+
def body
|
213
|
+
@body ||= response.body
|
214
|
+
end
|
215
|
+
|
216
|
+
def html
|
217
|
+
@html ||= Nokogiri::HTML(body)
|
218
|
+
end
|
219
|
+
alias_method :source, :body
|
216
220
|
|
221
|
+
def get(*args, &block); reset_cache; super; end
|
222
|
+
def post(*args, &block); reset_cache; super; end
|
223
|
+
def put(*args, &block); reset_cache; super; end
|
224
|
+
def delete(*args, &block); reset_cache; super; end
|
225
|
+
|
217
226
|
private
|
218
227
|
|
228
|
+
def reset_cache
|
229
|
+
@body = nil
|
230
|
+
@html = nil
|
231
|
+
end
|
232
|
+
|
219
233
|
def build_rack_mock_session # :nodoc:
|
220
|
-
Rack::MockSession.new(app, Capybara.default_host || "example.
|
234
|
+
Rack::MockSession.new(app, Capybara.default_host || "www.example.com")
|
221
235
|
end
|
222
236
|
|
223
237
|
def current_path
|
@@ -244,9 +258,9 @@ private
|
|
244
258
|
env
|
245
259
|
end
|
246
260
|
|
247
|
-
def
|
248
|
-
@body =
|
249
|
-
@html =
|
261
|
+
def reset_cache
|
262
|
+
@body = nil
|
263
|
+
@html = nil
|
250
264
|
end
|
251
265
|
|
252
266
|
end
|
@@ -29,9 +29,9 @@ class Capybara::Driver::Selenium < Capybara::Driver::Base
|
|
29
29
|
node.clear
|
30
30
|
node.send_keys(value.to_s)
|
31
31
|
elsif tag_name == 'input' and type == 'radio'
|
32
|
-
node.
|
32
|
+
node.click
|
33
33
|
elsif tag_name == 'input' and type == 'checkbox'
|
34
|
-
node.
|
34
|
+
node.click
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
data/lib/capybara/node.rb
CHANGED
@@ -56,14 +56,5 @@ module Capybara
|
|
56
56
|
def trigger(event)
|
57
57
|
raise NotSupportedByDriverError
|
58
58
|
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
def all_unfiltered(locator)
|
63
|
-
nodes = XPath.wrap(locator).scope(path).paths.map do |path|
|
64
|
-
driver.find(path)
|
65
|
-
end.flatten
|
66
|
-
end
|
67
|
-
|
68
59
|
end
|
69
60
|
end
|
data/lib/capybara/server.rb
CHANGED
data/lib/capybara/session.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
require 'capybara/wait_until'
|
2
3
|
|
3
4
|
module Capybara
|
4
5
|
class Session
|
6
|
+
extend Forwardable
|
5
7
|
include Searchable
|
6
8
|
|
7
9
|
DSL_METHODS = [
|
@@ -15,41 +17,27 @@ module Capybara
|
|
15
17
|
|
16
18
|
attr_reader :mode, :app
|
17
19
|
|
18
|
-
def initialize(mode, app)
|
20
|
+
def initialize(mode, app=nil)
|
19
21
|
@mode = mode
|
20
22
|
@app = app
|
21
23
|
end
|
22
24
|
|
23
25
|
def driver
|
24
|
-
@driver ||=
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
when :celerity
|
30
|
-
Capybara::Driver::Celerity.new(app)
|
31
|
-
when :culerity
|
32
|
-
Capybara::Driver::Culerity.new(app)
|
33
|
-
else
|
26
|
+
@driver ||= begin
|
27
|
+
string = mode.to_s
|
28
|
+
string.gsub!(%r{(^.)|(_.)}) { |m| m[m.length-1,1].upcase }
|
29
|
+
Capybara::Driver.const_get(string.to_sym).new(app)
|
30
|
+
rescue NameError
|
34
31
|
raise Capybara::DriverNotFoundError, "no driver called #{mode} was found"
|
35
32
|
end
|
36
33
|
end
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
def response_headers
|
47
|
-
driver.response_headers
|
48
|
-
end
|
49
|
-
|
50
|
-
def visit(path)
|
51
|
-
driver.visit(path)
|
52
|
-
end
|
35
|
+
def_delegator :driver, :cleanup!
|
36
|
+
def_delegator :driver, :current_url
|
37
|
+
def_delegator :driver, :response_headers
|
38
|
+
def_delegator :driver, :visit
|
39
|
+
def_delegator :driver, :body
|
40
|
+
def_delegator :driver, :source
|
53
41
|
|
54
42
|
def click(locator)
|
55
43
|
msg = "no link or button '#{locator}' found"
|
@@ -107,14 +95,6 @@ module Capybara
|
|
107
95
|
locate(:xpath, XPath.file_field(locator), msg).set(path)
|
108
96
|
end
|
109
97
|
|
110
|
-
def body
|
111
|
-
driver.body
|
112
|
-
end
|
113
|
-
|
114
|
-
def source
|
115
|
-
driver.source
|
116
|
-
end
|
117
|
-
|
118
98
|
def within(kind, scope=nil)
|
119
99
|
kind, scope = Capybara.default_selector, kind unless scope
|
120
100
|
scope = XPath.from_css(scope) if kind == :css
|
@@ -245,7 +225,7 @@ module Capybara
|
|
245
225
|
end
|
246
226
|
|
247
227
|
def wait_until(timeout = Capybara.default_wait_time)
|
248
|
-
WaitUntil.timeout(timeout) { yield }
|
228
|
+
WaitUntil.timeout(timeout,driver) { yield }
|
249
229
|
end
|
250
230
|
|
251
231
|
def evaluate_script(script)
|
data/lib/capybara/wait_until.rb
CHANGED
@@ -4,7 +4,7 @@ module Capybara
|
|
4
4
|
|
5
5
|
class << self
|
6
6
|
|
7
|
-
def timeout(seconds = 1, &block)
|
7
|
+
def timeout(seconds = 1, driver = nil, &block)
|
8
8
|
start_time = Time.now
|
9
9
|
|
10
10
|
result = nil
|
@@ -12,9 +12,12 @@ module Capybara
|
|
12
12
|
until result
|
13
13
|
return result if result = yield
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
delay = seconds - (Time.now - start_time)
|
16
|
+
if delay <= 0
|
17
|
+
raise TimeoutError
|
17
18
|
end
|
19
|
+
|
20
|
+
driver && driver.wait_until(delay)
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
data/lib/capybara/xpath.rb
CHANGED
@@ -5,11 +5,6 @@ module Capybara
|
|
5
5
|
class XPath
|
6
6
|
|
7
7
|
class << self
|
8
|
-
def from_css(css)
|
9
|
-
Nokogiri::CSS.xpath_for(css).first
|
10
|
-
end
|
11
|
-
alias_method :for_css, :from_css
|
12
|
-
|
13
8
|
def wrap(path)
|
14
9
|
if path.is_a?(self)
|
15
10
|
path
|
@@ -33,6 +28,27 @@ module Capybara
|
|
33
28
|
@paths = paths
|
34
29
|
end
|
35
30
|
|
31
|
+
def scope(scope)
|
32
|
+
XPath.new(*paths.map { |p| scope + p })
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
@paths.join(' | ')
|
37
|
+
end
|
38
|
+
|
39
|
+
def append(path)
|
40
|
+
XPath.new(*[@paths, XPath.wrap(path).paths].flatten)
|
41
|
+
end
|
42
|
+
|
43
|
+
def prepend(path)
|
44
|
+
XPath.new(*[XPath.wrap(path).paths, @paths].flatten)
|
45
|
+
end
|
46
|
+
|
47
|
+
def from_css(css)
|
48
|
+
append(Nokogiri::CSS.xpath_for(css).first)
|
49
|
+
end
|
50
|
+
alias_method :for_css, :from_css
|
51
|
+
|
36
52
|
def field(locator, options={})
|
37
53
|
if options[:with]
|
38
54
|
fillable_field(locator, options)
|
@@ -46,13 +62,11 @@ module Capybara
|
|
46
62
|
end
|
47
63
|
|
48
64
|
def fillable_field(locator, options={})
|
49
|
-
|
50
|
-
all.input_field(type, locator, options)
|
51
|
-
end
|
65
|
+
text_area(locator, options).text_field(locator, options)
|
52
66
|
end
|
53
67
|
|
54
68
|
def content(locator)
|
55
|
-
append("/descendant-or-self::*[contains(
|
69
|
+
append("/descendant-or-self::*[contains(normalize-space(.),#{s(locator)})]")
|
56
70
|
end
|
57
71
|
|
58
72
|
def table(locator, options={})
|
@@ -84,6 +98,11 @@ module Capybara
|
|
84
98
|
xpath = xpath.prepend("//button[@value=#{s(locator)} or text()=#{s(locator)}]")
|
85
99
|
end
|
86
100
|
|
101
|
+
def text_field(locator, options={})
|
102
|
+
options = options.merge(:value => options[:with]) if options.has_key?(:with)
|
103
|
+
add_field(locator, "//input[@type!='radio' and @type!='checkbox' and @type!='hidden']", options)
|
104
|
+
end
|
105
|
+
|
87
106
|
def text_area(locator, options={})
|
88
107
|
options = options.merge(:text => options[:with]) if options.has_key?(:with)
|
89
108
|
add_field(locator, "//textarea", options)
|
@@ -93,27 +112,6 @@ module Capybara
|
|
93
112
|
add_field(locator, "//select", options)
|
94
113
|
end
|
95
114
|
|
96
|
-
def input_field(type, locator, options={})
|
97
|
-
options = options.merge(:value => options[:with]) if options.has_key?(:with)
|
98
|
-
add_field(locator, "//input[@type='#{type}']", options)
|
99
|
-
end
|
100
|
-
|
101
|
-
def scope(scope)
|
102
|
-
XPath.new(*paths.map { |p| scope + p })
|
103
|
-
end
|
104
|
-
|
105
|
-
def to_s
|
106
|
-
@paths.join(' | ')
|
107
|
-
end
|
108
|
-
|
109
|
-
def append(path)
|
110
|
-
XPath.new(*[@paths, XPath.wrap(path).paths].flatten)
|
111
|
-
end
|
112
|
-
|
113
|
-
def prepend(path)
|
114
|
-
XPath.new(*[XPath.wrap(path).paths, @paths].flatten)
|
115
|
-
end
|
116
|
-
|
117
115
|
def checkbox(locator, options={})
|
118
116
|
input_field(:checkbox, locator, options)
|
119
117
|
end
|
@@ -122,16 +120,17 @@ module Capybara
|
|
122
120
|
input_field(:radio, locator, options)
|
123
121
|
end
|
124
122
|
|
125
|
-
|
126
|
-
|
127
|
-
def #{type}_field(locator)
|
128
|
-
input_field(:#{type}, locator)
|
129
|
-
end
|
130
|
-
RUBY
|
123
|
+
def file_field(locator, options={})
|
124
|
+
input_field(:file, locator, options)
|
131
125
|
end
|
132
126
|
|
133
127
|
protected
|
134
128
|
|
129
|
+
def input_field(type, locator, options={})
|
130
|
+
options = options.merge(:value => options[:with]) if options.has_key?(:with)
|
131
|
+
add_field(locator, "//input[@type='#{type}']", options)
|
132
|
+
end
|
133
|
+
|
135
134
|
# place this between to nodes to indicate that they should be siblings
|
136
135
|
def sibling
|
137
136
|
'/following-sibling::*[1]/self::'
|
data/spec/dsl/fill_in_spec.rb
CHANGED
@@ -52,6 +52,19 @@ shared_examples_for "fill_in" do
|
|
52
52
|
extract_results(@session)['password'].should == 'supasikrit'
|
53
53
|
end
|
54
54
|
|
55
|
+
it "should fill in a field with a custom type" do
|
56
|
+
pending "selenium doesn't seem to find custom fields" if @session.mode == :selenium
|
57
|
+
@session.fill_in('Schmooo', :with => 'Schmooo is the game')
|
58
|
+
@session.click_button('awesome')
|
59
|
+
extract_results(@session)['schmooo'].should == 'Schmooo is the game'
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should fill in a password field by name" do
|
63
|
+
@session.fill_in('form[password]', :with => 'supasikrit')
|
64
|
+
@session.click_button('awesome')
|
65
|
+
extract_results(@session)['password'].should == 'supasikrit'
|
66
|
+
end
|
67
|
+
|
55
68
|
it "should fill in a password field by label" do
|
56
69
|
@session.fill_in('Password', :with => 'supasikrit')
|
57
70
|
@session.click_button('awesome')
|
@@ -27,6 +27,11 @@ shared_examples_for "has_content" do
|
|
27
27
|
@session.should have_content('exercitation ullamco laboris')
|
28
28
|
end
|
29
29
|
|
30
|
+
it "should ignore extra whitespace and newlines" do
|
31
|
+
@session.visit('/with_html')
|
32
|
+
@session.should have_content('text with whitespace')
|
33
|
+
end
|
34
|
+
|
30
35
|
it "should be false if the given content is not on the page" do
|
31
36
|
@session.visit('/with_html')
|
32
37
|
@session.should_not have_content('xxxxyzzz')
|
data/spec/public/test.js
CHANGED
@@ -27,4 +27,7 @@ $(function() {
|
|
27
27
|
$('#with_focus_event').focus(function() {
|
28
28
|
$('body').append('<p id="focus_event_triggered">Focus Event triggered</p>')
|
29
29
|
});
|
30
|
-
|
30
|
+
$('#checkbox_with_event').click(function() {
|
31
|
+
$('body').append('<p id="checkbox_event_triggered">Checkbox event triggered</p>')
|
32
|
+
});
|
33
|
+
});
|
data/spec/server_spec.rb
CHANGED
@@ -10,6 +10,12 @@ describe Capybara::Server do
|
|
10
10
|
|
11
11
|
@res.body.should include('Hello Server')
|
12
12
|
end
|
13
|
+
|
14
|
+
it "should do nothing when no server given" do
|
15
|
+
running do
|
16
|
+
@server = Capybara::Server.new(nil).boot
|
17
|
+
end.should_not raise_error
|
18
|
+
end
|
13
19
|
|
14
20
|
it "should find an available port" do
|
15
21
|
@app1 = proc { |env| [200, {}, "Hello Server!"]}
|
@@ -91,12 +91,17 @@ shared_examples_for "session with javascript support" do
|
|
91
91
|
end
|
92
92
|
|
93
93
|
it "should default to Capybara.default_wait_time before timeout" do
|
94
|
+
@session.driver # init the driver to exclude init timing from test
|
94
95
|
start = Time.now
|
95
96
|
Capybara.default_wait_time = 0.2
|
96
97
|
begin
|
97
98
|
@session.wait_until { false }
|
98
99
|
rescue Capybara::TimeoutError; end
|
99
|
-
|
100
|
+
if @session.driver.has_shortcircuit_timeout?
|
101
|
+
(Time.now - start).should be_close(0, 0.1)
|
102
|
+
else
|
103
|
+
(Time.now - start).should be_close(0.2, 0.1)
|
104
|
+
end
|
100
105
|
end
|
101
106
|
end
|
102
107
|
|
@@ -132,6 +137,14 @@ shared_examples_for "session with javascript support" do
|
|
132
137
|
end
|
133
138
|
end
|
134
139
|
|
140
|
+
describe '#check' do
|
141
|
+
it "should trigger associated events" do
|
142
|
+
@session.visit('/with_js')
|
143
|
+
@session.check('checkbox_with_event')
|
144
|
+
@session.should have_css('#checkbox_event_triggered');
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
135
148
|
describe '#has_xpath?' do
|
136
149
|
it "should wait for content to appear" do
|
137
150
|
@session.visit('/with_js')
|
data/spec/views/form.erb
CHANGED
@@ -32,6 +32,11 @@
|
|
32
32
|
<label for="form_name">Name</label>
|
33
33
|
<input type="text" name="form[name]" value="John Smith" id="form_name"/>
|
34
34
|
</p>
|
35
|
+
|
36
|
+
<p>
|
37
|
+
<label for="form_schmooo">Schmooo</label>
|
38
|
+
<input type="schmooo" name="form[schmooo]" value="This is Schmooo!" id="form_schmooo"/>
|
39
|
+
</p>
|
35
40
|
|
36
41
|
<p>
|
37
42
|
<label>Street<br/>
|
data/spec/views/with_html.erb
CHANGED
@@ -12,7 +12,10 @@
|
|
12
12
|
<p id="second">
|
13
13
|
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
|
14
14
|
dolore eu fugiat <a href="/redirect" id="red">Redirect</a> pariatur. Excepteur sint occaecat cupidatat non proident,
|
15
|
-
sunt in culpa qui officia
|
15
|
+
sunt in culpa qui officia
|
16
|
+
text with
|
17
|
+
whitespace
|
18
|
+
id est laborum.
|
16
19
|
</p>
|
17
20
|
|
18
21
|
<p>
|
data/spec/views/with_js.erb
CHANGED
data/spec/xpath_spec.rb
CHANGED
@@ -83,10 +83,8 @@ describe Capybara::XPath do
|
|
83
83
|
end
|
84
84
|
|
85
85
|
it "should be chainable" do
|
86
|
-
@query = @xpath.field('First Name').
|
86
|
+
@query = @xpath.field('First Name').button('Click me!').to_s
|
87
87
|
@driver.find(@query).first.value.should == 'John'
|
88
|
-
@query = @xpath.field('Password').input_field(:password, 'Password').to_s
|
89
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
90
88
|
end
|
91
89
|
end
|
92
90
|
|
@@ -101,45 +99,11 @@ describe Capybara::XPath do
|
|
101
99
|
end
|
102
100
|
|
103
101
|
it "should be chainable" do
|
104
|
-
@query = @xpath.fillable_field('First Name').
|
105
|
-
@driver.find(@query).first.value.should == 'John'
|
106
|
-
@query = @xpath.fillable_field('Password').password_field('Password').to_s
|
107
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe '#text_field' do
|
112
|
-
it "should find a text field by id or label" do
|
113
|
-
@query = @xpath.text_field('form_first_name').to_s
|
114
|
-
@driver.find(@query).first.value.should == 'John'
|
115
|
-
@query = @xpath.text_field('First Name').to_s
|
116
|
-
@driver.find(@query).first.value.should == 'John'
|
117
|
-
end
|
118
|
-
|
119
|
-
it "should be chainable" do
|
120
|
-
@query = @xpath.text_field('First Name').password_field('First Name').to_s
|
102
|
+
@query = @xpath.fillable_field('First Name').button('Click me!').to_s
|
121
103
|
@driver.find(@query).first.value.should == 'John'
|
122
|
-
@query = @xpath.text_field('Password').password_field('Password').to_s
|
123
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
124
104
|
end
|
125
105
|
end
|
126
106
|
|
127
|
-
describe '#password_field' do
|
128
|
-
it "should find a password field by id or label" do
|
129
|
-
@query = @xpath.password_field('form_password').to_s
|
130
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
131
|
-
@query = @xpath.password_field('Password').to_s
|
132
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
133
|
-
end
|
134
|
-
|
135
|
-
it "should be chainable" do
|
136
|
-
@query = @xpath.password_field('First Name').text_field('First Name').to_s
|
137
|
-
@driver.find(@query).first.value.should == 'John'
|
138
|
-
@query = @xpath.password_field('Password').text_field('Password').to_s
|
139
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
107
|
describe '#text_area' do
|
144
108
|
it "should find a text area by id or label" do
|
145
109
|
@query = @xpath.text_area('form_description').to_s
|
@@ -149,10 +113,8 @@ describe Capybara::XPath do
|
|
149
113
|
end
|
150
114
|
|
151
115
|
it "should be chainable" do
|
152
|
-
@query = @xpath.text_area('Description').
|
116
|
+
@query = @xpath.text_area('Description').button('Click me!').to_s
|
153
117
|
@driver.find(@query).first.text.should == 'Descriptive text goes here'
|
154
|
-
@query = @xpath.text_area('Password').password_field('Password').to_s
|
155
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
156
118
|
end
|
157
119
|
end
|
158
120
|
|
@@ -182,10 +144,8 @@ describe Capybara::XPath do
|
|
182
144
|
end
|
183
145
|
|
184
146
|
it "should be chainable" do
|
185
|
-
@query = @xpath.radio_button('Male').
|
147
|
+
@query = @xpath.radio_button('Male').button('Click me!').to_s
|
186
148
|
@driver.find(@query).first.value.should == 'male'
|
187
|
-
@query = @xpath.radio_button('Password').password_field('Password').to_s
|
188
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
189
149
|
end
|
190
150
|
end
|
191
151
|
|
@@ -198,10 +158,8 @@ describe Capybara::XPath do
|
|
198
158
|
end
|
199
159
|
|
200
160
|
it "should be chainable" do
|
201
|
-
@query = @xpath.checkbox('Cat').
|
161
|
+
@query = @xpath.checkbox('Cat').button('Click me!').to_s
|
202
162
|
@driver.find(@query).first.value.should == 'cat'
|
203
|
-
@query = @xpath.checkbox('Password').password_field('Password').to_s
|
204
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
205
163
|
end
|
206
164
|
end
|
207
165
|
|
@@ -214,58 +172,9 @@ describe Capybara::XPath do
|
|
214
172
|
end
|
215
173
|
|
216
174
|
it "should be chainable" do
|
217
|
-
@query = @xpath.select('Region').
|
175
|
+
@query = @xpath.select('Region').button('Click me!').to_s
|
218
176
|
@driver.find(@query).first[:name].should == 'form[region]'
|
219
|
-
@query = @xpath.select('Password').password_field('Password').to_s
|
220
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
describe '#file_field' do
|
225
|
-
it "should find a file field by id or label" do
|
226
|
-
@query = @xpath.file_field('Document').to_s
|
227
|
-
@driver.find(@query).first[:name].should == 'form[document]'
|
228
|
-
@query = @xpath.file_field('form_document').to_s
|
229
|
-
@driver.find(@query).first[:name].should == 'form[document]'
|
230
|
-
end
|
231
|
-
|
232
|
-
it "should be chainable" do
|
233
|
-
@query = @xpath.file_field('Document').password_field('Document').to_s
|
234
|
-
@driver.find(@query).first[:name].should == 'form[document]'
|
235
|
-
@query = @xpath.file_field('Password').password_field('Password').to_s
|
236
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
237
177
|
end
|
238
178
|
end
|
239
179
|
|
240
|
-
[ [:email_field, 'html5_email', 'Html5 Email', 'person@email.com'],
|
241
|
-
[:url_field, 'html5_url', 'Html5 Url', 'http://www.example.com'],
|
242
|
-
[:search_field, 'html5_search', 'Html5 Search', 'what are you looking for'],
|
243
|
-
[:tel_field, 'html5_tel', 'Html5 Tel', '911'],
|
244
|
-
[:color_field, 'html5_color', 'Html5 Color', '#FFF']].each do |method, id, label, output|
|
245
|
-
describe "##{method}" do
|
246
|
-
it "should find a file field by label" do
|
247
|
-
@query = @xpath.send(method, label).to_s
|
248
|
-
@driver.find(@query).first.value.should == output
|
249
|
-
end
|
250
|
-
|
251
|
-
it "should find a file field by id" do
|
252
|
-
@query = @xpath.send(method, id).to_s
|
253
|
-
@driver.find(@query).first.value.should == output
|
254
|
-
end
|
255
|
-
|
256
|
-
it "should be chainable" do
|
257
|
-
@query = @xpath.send(method, label).password_field(label).to_s
|
258
|
-
@driver.find(@query).first.value.should == output
|
259
|
-
@query = @xpath.send(method, 'Password').password_field('Password').to_s
|
260
|
-
@driver.find(@query).first.value.should == 'seeekrit'
|
261
|
-
end
|
262
|
-
|
263
|
-
it "should be a #fillable_field" do
|
264
|
-
@query = @xpath.fillable_field(label).to_s
|
265
|
-
@driver.find(@query).first.value.should == output
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
end
|
270
|
-
|
271
180
|
end
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capybara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 3
|
8
|
+
- 6
|
9
|
+
version: 0.3.6
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Jonas Nicklas
|
@@ -9,99 +14,134 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-
|
17
|
+
date: 2010-03-22 00:00:00 +00:00
|
13
18
|
default_executable:
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: nokogiri
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 3
|
30
|
+
- 3
|
23
31
|
version: 1.3.3
|
24
|
-
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
25
34
|
- !ruby/object:Gem::Dependency
|
26
35
|
name: mime-types
|
27
|
-
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
38
|
requirements:
|
31
39
|
- - ">="
|
32
40
|
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 1
|
43
|
+
- 16
|
33
44
|
version: "1.16"
|
34
|
-
|
45
|
+
type: :runtime
|
46
|
+
version_requirements: *id002
|
35
47
|
- !ruby/object:Gem::Dependency
|
36
48
|
name: culerity
|
37
|
-
|
38
|
-
|
39
|
-
version_requirements: !ruby/object:Gem::Requirement
|
49
|
+
prerelease: false
|
50
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
40
51
|
requirements:
|
41
52
|
- - ">="
|
42
53
|
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
- 2
|
57
|
+
- 4
|
43
58
|
version: 0.2.4
|
44
|
-
|
59
|
+
type: :runtime
|
60
|
+
version_requirements: *id003
|
45
61
|
- !ruby/object:Gem::Dependency
|
46
62
|
name: selenium-webdriver
|
47
|
-
|
48
|
-
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
prerelease: false
|
64
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
50
65
|
requirements:
|
51
66
|
- - ">="
|
52
67
|
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
- 0
|
71
|
+
- 3
|
53
72
|
version: 0.0.3
|
54
|
-
|
73
|
+
type: :runtime
|
74
|
+
version_requirements: *id004
|
55
75
|
- !ruby/object:Gem::Dependency
|
56
76
|
name: rack
|
57
|
-
|
58
|
-
|
59
|
-
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
prerelease: false
|
78
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
60
79
|
requirements:
|
61
80
|
- - ">="
|
62
81
|
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 1
|
84
|
+
- 0
|
85
|
+
- 0
|
63
86
|
version: 1.0.0
|
64
|
-
|
87
|
+
type: :runtime
|
88
|
+
version_requirements: *id005
|
65
89
|
- !ruby/object:Gem::Dependency
|
66
90
|
name: rack-test
|
67
|
-
|
68
|
-
|
69
|
-
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
prerelease: false
|
92
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
70
93
|
requirements:
|
71
94
|
- - ">="
|
72
95
|
- !ruby/object:Gem::Version
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
- 5
|
99
|
+
- 2
|
73
100
|
version: 0.5.2
|
74
|
-
|
101
|
+
type: :runtime
|
102
|
+
version_requirements: *id006
|
75
103
|
- !ruby/object:Gem::Dependency
|
76
104
|
name: sinatra
|
77
|
-
|
78
|
-
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
prerelease: false
|
106
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
80
107
|
requirements:
|
81
108
|
- - ">="
|
82
109
|
- !ruby/object:Gem::Version
|
110
|
+
segments:
|
111
|
+
- 0
|
112
|
+
- 9
|
113
|
+
- 4
|
83
114
|
version: 0.9.4
|
84
|
-
|
115
|
+
type: :development
|
116
|
+
version_requirements: *id007
|
85
117
|
- !ruby/object:Gem::Dependency
|
86
118
|
name: rspec
|
87
|
-
|
88
|
-
|
89
|
-
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
prerelease: false
|
120
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
90
121
|
requirements:
|
91
122
|
- - ">="
|
92
123
|
- !ruby/object:Gem::Version
|
124
|
+
segments:
|
125
|
+
- 1
|
126
|
+
- 2
|
127
|
+
- 9
|
93
128
|
version: 1.2.9
|
94
|
-
|
129
|
+
type: :development
|
130
|
+
version_requirements: *id008
|
95
131
|
- !ruby/object:Gem::Dependency
|
96
132
|
name: hoe
|
97
|
-
|
98
|
-
|
99
|
-
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
prerelease: false
|
134
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
100
135
|
requirements:
|
101
136
|
- - ">="
|
102
137
|
- !ruby/object:Gem::Version
|
138
|
+
segments:
|
139
|
+
- 2
|
140
|
+
- 5
|
141
|
+
- 0
|
103
142
|
version: 2.5.0
|
104
|
-
|
143
|
+
type: :development
|
144
|
+
version_requirements: *id009
|
105
145
|
description: |-
|
106
146
|
Capybara aims to simplify the process of integration testing Rack applications,
|
107
147
|
such as Rails, Sinatra or Merb. It is inspired by and aims to replace Webrat as
|
@@ -220,18 +260,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
220
260
|
requirements:
|
221
261
|
- - ">="
|
222
262
|
- !ruby/object:Gem::Version
|
263
|
+
segments:
|
264
|
+
- 0
|
223
265
|
version: "0"
|
224
|
-
version:
|
225
266
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
226
267
|
requirements:
|
227
268
|
- - ">="
|
228
269
|
- !ruby/object:Gem::Version
|
270
|
+
segments:
|
271
|
+
- 0
|
229
272
|
version: "0"
|
230
|
-
version:
|
231
273
|
requirements: []
|
232
274
|
|
233
275
|
rubyforge_project: capybara
|
234
|
-
rubygems_version: 1.3.
|
276
|
+
rubygems_version: 1.3.6
|
235
277
|
signing_key:
|
236
278
|
specification_version: 3
|
237
279
|
summary: Capybara aims to simplify the process of integration testing Rack applications, such as Rails, Sinatra or Merb
|