capybara 0.3.5 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|