capybara 0.2.0 → 0.3.0
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/Manifest.txt +39 -0
- data/README.rdoc +181 -57
- data/Rakefile +7 -16
- data/config.ru +6 -0
- data/lib/capybara.rb +19 -9
- data/lib/capybara/cucumber.rb +4 -0
- data/lib/capybara/driver/base.rb +25 -8
- data/lib/capybara/driver/celerity_driver.rb +108 -0
- data/lib/capybara/driver/culerity_driver.rb +1 -70
- data/lib/capybara/driver/rack_test_driver.rb +57 -25
- data/lib/capybara/driver/selenium_driver.rb +28 -10
- data/lib/capybara/dsl.rb +7 -4
- data/lib/capybara/node.rb +50 -29
- data/lib/capybara/rails.rb +1 -1
- data/lib/capybara/save_and_open_page.rb +1 -1
- data/lib/capybara/searchable.rb +45 -0
- data/lib/capybara/server.rb +11 -4
- data/lib/capybara/session.rb +94 -94
- data/lib/capybara/wait_until.rb +23 -0
- data/lib/capybara/xpath.rb +55 -41
- data/spec/capybara_spec.rb +18 -0
- data/spec/driver/celerity_driver_spec.rb +17 -0
- data/spec/driver/culerity_driver_spec.rb +3 -0
- data/spec/driver/rack_test_driver_spec.rb +3 -0
- data/spec/driver/remote_culerity_driver_spec.rb +19 -0
- data/spec/driver/remote_selenium_driver_spec.rb +18 -0
- data/spec/driver/selenium_driver_spec.rb +2 -0
- data/spec/drivers_spec.rb +51 -5
- data/spec/dsl/all_spec.rb +38 -0
- data/spec/dsl/attach_file_spec.rb +66 -0
- data/spec/dsl/check_spec.rb +28 -0
- data/spec/dsl/choose_spec.rb +28 -0
- data/spec/dsl/click_button_spec.rb +183 -0
- data/spec/dsl/click_link_spec.rb +88 -0
- data/spec/dsl/click_spec.rb +26 -0
- data/spec/dsl/current_url_spec.rb +10 -0
- data/spec/dsl/fill_in_spec.rb +83 -0
- data/spec/dsl/find_button_spec.rb +18 -0
- data/spec/dsl/find_field_spec.rb +24 -0
- data/spec/dsl/find_link_spec.rb +19 -0
- data/spec/dsl/find_spec.rb +36 -0
- data/spec/dsl/has_content_spec.rb +103 -0
- data/spec/dsl/has_css_spec.rb +109 -0
- data/spec/dsl/has_xpath_spec.rb +115 -0
- data/spec/dsl/locate_spec.rb +38 -0
- data/spec/dsl/select_spec.rb +27 -0
- data/spec/dsl/uncheck_spec.rb +29 -0
- data/spec/dsl/within_spec.rb +145 -0
- data/spec/fixtures/capybara.jpg +0 -0
- data/spec/public/test.js +27 -0
- data/spec/searchable_spec.rb +61 -0
- data/spec/server_spec.rb +47 -0
- data/spec/session/celerity_session_spec.rb +27 -0
- data/spec/session/culerity_session_spec.rb +1 -0
- data/spec/session/rack_test_session_spec.rb +1 -0
- data/spec/session/selenium_session_spec.rb +1 -0
- data/spec/session_spec.rb +32 -903
- data/spec/session_with_headers_support_spec.rb +13 -0
- data/spec/session_with_javascript_support_spec.rb +165 -0
- data/spec/session_without_headers_support_spec.rb +15 -0
- data/spec/session_without_javascript_support_spec.rb +15 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/test_app.rb +9 -1
- data/spec/views/form.erb +38 -0
- data/spec/views/postback.erb +13 -0
- data/spec/views/with_html.erb +13 -0
- data/spec/views/with_js.erb +9 -24
- data/spec/views/with_simple_html.erb +1 -1
- data/spec/wait_until_spec.rb +28 -0
- data/spec/xpath_spec.rb +34 -3
- metadata +54 -5
data/lib/capybara/dsl.rb
CHANGED
@@ -47,10 +47,13 @@ module Capybara
|
|
47
47
|
end
|
48
48
|
|
49
49
|
SESSION_METHODS = [
|
50
|
-
:visit, :body, :click_link, :click_button, :drag, :fill_in,
|
51
|
-
:
|
52
|
-
:
|
53
|
-
:
|
50
|
+
:visit, :current_url, :body, :click_link, :click_button, :drag, :fill_in,
|
51
|
+
:choose, :has_xpath?, :has_no_xpath?, :has_css?, :has_no_css?,
|
52
|
+
:check, :uncheck, :attach_file, :select, :source,
|
53
|
+
:has_content?, :has_no_content?, :within, :within_fieldset, :within_table,
|
54
|
+
:save_and_open_page, :find, :find_field, :find_link, :find_button,
|
55
|
+
:field_labeled, :all, :locate, :evaluate_script,
|
56
|
+
:click, :wait_until
|
54
57
|
]
|
55
58
|
SESSION_METHODS.each do |method|
|
56
59
|
class_eval <<-RUBY, __FILE__, __LINE__+1
|
data/lib/capybara/node.rb
CHANGED
@@ -1,40 +1,61 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module Capybara
|
2
|
+
class Node
|
3
|
+
include Searchable
|
3
4
|
|
4
|
-
|
5
|
-
@driver = driver
|
6
|
-
@node = node
|
7
|
-
end
|
5
|
+
attr_reader :driver, :node
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
def initialize(driver, node)
|
8
|
+
@driver = driver
|
9
|
+
@node = node
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
def text
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
def [](name)
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
def value
|
21
|
+
self[:value]
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def set(value)
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
def select(option)
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
def click
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
def drag_to(element)
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
def tag_name
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
43
|
+
|
44
|
+
def visible?
|
45
|
+
raise NotImplementedError
|
46
|
+
end
|
47
|
+
|
48
|
+
def path
|
49
|
+
raise NotSupportedByDriverError
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def all_unfiltered(locator)
|
55
|
+
nodes = XPath.wrap(locator).scope(path).paths.map do |path|
|
56
|
+
driver.find(path)
|
57
|
+
end.flatten
|
58
|
+
end
|
36
59
|
|
37
|
-
def tag_name
|
38
|
-
raise "Not implemented"
|
39
60
|
end
|
40
61
|
end
|
data/lib/capybara/rails.rb
CHANGED
@@ -23,7 +23,7 @@ module Capybara
|
|
23
23
|
|
24
24
|
def rewrite_css_and_image_references(response_html) # :nodoc:
|
25
25
|
return response_html unless Capybara.asset_root
|
26
|
-
response_html.gsub(/("|')\/(stylesheets|images)/, '\1' + Capybara.asset_root + '/\2')
|
26
|
+
response_html.gsub(/("|')\/(stylesheets|images|javascripts)/, '\1' + Capybara.asset_root + '/\2')
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Capybara
|
2
|
+
module Searchable
|
3
|
+
def find(locator, options = {})
|
4
|
+
all(locator, options).first
|
5
|
+
end
|
6
|
+
|
7
|
+
def find_field(locator)
|
8
|
+
find(XPath.field(locator))
|
9
|
+
end
|
10
|
+
alias_method :field_labeled, :find_field
|
11
|
+
|
12
|
+
def find_link(locator)
|
13
|
+
find(XPath.link(locator))
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_button(locator)
|
17
|
+
find(XPath.button(locator))
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_by_id(id)
|
21
|
+
find(Xpath.for_css("##{id}"))
|
22
|
+
end
|
23
|
+
|
24
|
+
def all(locator, options = {})
|
25
|
+
results = all_unfiltered(locator)
|
26
|
+
|
27
|
+
if options[:text]
|
28
|
+
results = results.select { |n| n.text.match(options[:text]) }
|
29
|
+
end
|
30
|
+
|
31
|
+
if options[:visible] == true
|
32
|
+
results.reject! { |n| !n.visible? }
|
33
|
+
end
|
34
|
+
|
35
|
+
results
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def all_unfiltered(locator)
|
41
|
+
raise "Must be overridden"
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/lib/capybara/server.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'net/http'
|
3
3
|
require 'rack'
|
4
|
-
|
4
|
+
begin
|
5
|
+
require 'rack/handler/mongrel'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rack/handler/webrick'
|
8
|
+
end
|
5
9
|
|
6
10
|
class Capybara::Server
|
7
11
|
class Identify
|
@@ -10,7 +14,7 @@ class Capybara::Server
|
|
10
14
|
end
|
11
15
|
|
12
16
|
def call(env)
|
13
|
-
if env["
|
17
|
+
if env["PATH_INFO"] == "/__identify__"
|
14
18
|
[200, {}, @app.object_id.to_s]
|
15
19
|
else
|
16
20
|
@app.call(env)
|
@@ -18,7 +22,6 @@ class Capybara::Server
|
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
21
|
-
|
22
25
|
attr_reader :app, :port
|
23
26
|
|
24
27
|
def initialize(app)
|
@@ -48,7 +51,11 @@ private
|
|
48
51
|
|
49
52
|
Timeout.timeout(10) do
|
50
53
|
Thread.new do
|
51
|
-
Rack::Handler::Mongrel
|
54
|
+
if defined?(Rack::Handler::Mongrel)
|
55
|
+
Rack::Handler::Mongrel.run(Identify.new(@app), :Port => port)
|
56
|
+
else
|
57
|
+
Rack::Handler::WEBrick.run(Identify.new(@app), :Port => port, :AccessLog => [])
|
58
|
+
end
|
52
59
|
end
|
53
60
|
Capybara.log "checking if application has booted"
|
54
61
|
|
data/lib/capybara/session.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
require 'capybara/wait_until'
|
2
|
+
|
1
3
|
module Capybara
|
2
4
|
class Session
|
5
|
+
include Searchable
|
3
6
|
|
4
7
|
attr_reader :mode, :app
|
5
8
|
|
@@ -12,109 +15,92 @@ module Capybara
|
|
12
15
|
@driver ||= case mode
|
13
16
|
when :rack_test
|
14
17
|
Capybara::Driver::RackTest.new(app)
|
15
|
-
when :culerity
|
16
|
-
Capybara::Driver::Culerity.new(app)
|
17
18
|
when :selenium
|
18
19
|
Capybara::Driver::Selenium.new(app)
|
20
|
+
when :celerity
|
21
|
+
Capybara::Driver::Celerity.new(app)
|
22
|
+
when :culerity
|
23
|
+
Capybara::Driver::Culerity.new(app)
|
19
24
|
else
|
20
25
|
raise Capybara::DriverNotFoundError, "no driver called #{mode} was found"
|
21
26
|
end
|
22
27
|
end
|
23
28
|
|
29
|
+
def current_url
|
30
|
+
driver.current_url
|
31
|
+
end
|
32
|
+
|
33
|
+
def response_headers
|
34
|
+
driver.response_headers
|
35
|
+
end
|
36
|
+
|
24
37
|
def visit(path)
|
25
38
|
driver.visit(path)
|
26
39
|
end
|
27
40
|
|
28
41
|
def click(locator)
|
29
|
-
|
30
|
-
|
31
|
-
link.click
|
42
|
+
msg = "no link or button '#{locator}' found"
|
43
|
+
locate(XPath.link(locator).button(locator), msg).click
|
32
44
|
end
|
33
45
|
|
34
46
|
def click_link(locator)
|
35
|
-
|
36
|
-
|
37
|
-
link.click
|
47
|
+
msg = "no link with title, id or text '#{locator}' found"
|
48
|
+
locate(XPath.link(locator), msg).click
|
38
49
|
end
|
39
50
|
|
40
51
|
def click_button(locator)
|
41
|
-
|
42
|
-
|
43
|
-
button.click
|
52
|
+
msg = "no button with value or id or text '#{locator}' found"
|
53
|
+
locate(XPath.button(locator)).click
|
44
54
|
end
|
45
55
|
|
46
56
|
def drag(source_locator, target_locator)
|
47
|
-
source =
|
48
|
-
|
49
|
-
target = find(target_locator)
|
50
|
-
raise Capybara::ElementNotFound, "drag target '#{target_locator}' not found on page" unless target
|
57
|
+
source = locate(source_locator, "drag source '#{source_locator}' not found on page")
|
58
|
+
target = locate(target_locator, "drag target '#{target_locator}' not found on page")
|
51
59
|
source.drag_to(target)
|
52
60
|
end
|
53
61
|
|
54
62
|
def fill_in(locator, options={})
|
55
|
-
|
56
|
-
|
57
|
-
field.set(options[:with])
|
63
|
+
msg = "cannot fill in, no text field, text area or password field with id, name, or label '#{locator}' found"
|
64
|
+
locate(XPath.fillable_field(locator), msg).set(options[:with])
|
58
65
|
end
|
59
66
|
|
60
67
|
def choose(locator)
|
61
|
-
|
62
|
-
|
63
|
-
field.set(true)
|
68
|
+
msg = "cannot choose field, no radio button with id, name, or label '#{locator}' found"
|
69
|
+
locate(XPath.radio_button(locator), msg).set(true)
|
64
70
|
end
|
65
71
|
|
66
72
|
def check(locator)
|
67
|
-
|
68
|
-
|
69
|
-
field.set(true)
|
73
|
+
msg = "cannot check field, no checkbox with id, name, or label '#{locator}' found"
|
74
|
+
locate(XPath.checkbox(locator), msg).set(true)
|
70
75
|
end
|
71
76
|
|
72
77
|
def uncheck(locator)
|
73
|
-
|
74
|
-
|
75
|
-
field.set(false)
|
78
|
+
msg = "cannot uncheck field, no checkbox with id, name, or label '#{locator}' found"
|
79
|
+
locate(XPath.checkbox(locator), msg).set(false)
|
76
80
|
end
|
77
81
|
|
78
82
|
def select(value, options={})
|
79
|
-
|
80
|
-
|
81
|
-
field.select(value)
|
83
|
+
msg = "cannot select option, no select box with id, name, or label '#{options[:from]}' found"
|
84
|
+
locate(XPath.select(options[:from]), msg).select(value)
|
82
85
|
end
|
83
86
|
|
84
87
|
def attach_file(locator, path)
|
85
|
-
|
86
|
-
|
87
|
-
field.set(path)
|
88
|
+
msg = "cannot attach file, no file field with id, name, or label '#{locator}' found"
|
89
|
+
locate(XPath.file_field(locator), msg).set(path)
|
88
90
|
end
|
89
91
|
|
90
92
|
def body
|
91
93
|
driver.body
|
92
94
|
end
|
93
95
|
|
94
|
-
def
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
def has_xpath?(path, options={})
|
99
|
-
results = all(path)
|
100
|
-
if options[:text]
|
101
|
-
results = filter_by_text(results, options[:text])
|
102
|
-
end
|
103
|
-
if options[:count]
|
104
|
-
results.size == options[:count]
|
105
|
-
else
|
106
|
-
results.size > 0
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def has_css?(path, options={})
|
111
|
-
has_xpath?(css_to_xpath(path), options)
|
96
|
+
def source
|
97
|
+
driver.source
|
112
98
|
end
|
113
99
|
|
114
100
|
def within(kind, scope=nil)
|
115
101
|
kind, scope = Capybara.default_selector, kind unless scope
|
116
|
-
scope =
|
117
|
-
|
102
|
+
scope = XPath.from_css(scope) if kind == :css
|
103
|
+
locate(scope, "scope '#{scope}' not found on page")
|
118
104
|
scopes.push(scope)
|
119
105
|
yield
|
120
106
|
scopes.pop
|
@@ -132,67 +118,81 @@ module Capybara
|
|
132
118
|
end
|
133
119
|
end
|
134
120
|
|
135
|
-
def
|
136
|
-
|
137
|
-
|
121
|
+
def has_xpath?(path, options={})
|
122
|
+
wait_conditionally_until do
|
123
|
+
results = all(path, options)
|
124
|
+
|
125
|
+
if options[:count]
|
126
|
+
results.size == options[:count]
|
127
|
+
else
|
128
|
+
results.size > 0
|
129
|
+
end
|
130
|
+
end
|
131
|
+
rescue Capybara::TimeoutError
|
132
|
+
return false
|
138
133
|
end
|
139
134
|
|
140
|
-
def
|
141
|
-
|
142
|
-
|
143
|
-
|
135
|
+
def has_no_xpath?(path, options={})
|
136
|
+
wait_conditionally_until do
|
137
|
+
results = all(path, options)
|
138
|
+
|
139
|
+
if options[:count]
|
140
|
+
results.size != options[:count]
|
141
|
+
else
|
142
|
+
results.empty?
|
143
|
+
end
|
144
|
+
end
|
145
|
+
rescue Capybara::TimeoutError
|
146
|
+
return false
|
144
147
|
end
|
145
148
|
|
146
|
-
def
|
147
|
-
|
149
|
+
def has_css?(path, options={})
|
150
|
+
has_xpath?(XPath.from_css(path), options)
|
148
151
|
end
|
149
|
-
|
150
|
-
def
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
152
|
+
|
153
|
+
def has_no_css?(path, options={})
|
154
|
+
has_no_xpath?(XPath.from_css(path), options)
|
155
|
+
end
|
156
|
+
|
157
|
+
def has_content?(content)
|
158
|
+
has_xpath?(XPath.content(content))
|
159
|
+
end
|
160
|
+
|
161
|
+
def has_no_content?(content)
|
162
|
+
has_no_xpath?(XPath.content(content))
|
158
163
|
end
|
159
164
|
|
160
|
-
def
|
161
|
-
|
165
|
+
def save_and_open_page
|
166
|
+
require 'capybara/save_and_open_page'
|
167
|
+
Capybara::SaveAndOpenPage.save_and_open_page(body)
|
162
168
|
end
|
163
|
-
alias_method :field_labeled, :find_field
|
164
169
|
|
165
|
-
|
166
|
-
|
170
|
+
#return node identified by locator or raise ElementNotFound(using desc)
|
171
|
+
def locate(locator, fail_msg = nil)
|
172
|
+
node = wait_conditionally_until { find(locator) }
|
173
|
+
ensure
|
174
|
+
raise Capybara::ElementNotFound, fail_msg || "Unable to locate '#{locator}'" unless node
|
175
|
+
return node
|
167
176
|
end
|
168
177
|
|
169
|
-
def
|
170
|
-
|
178
|
+
def wait_until(timeout = Capybara.default_wait_time)
|
179
|
+
WaitUntil.timeout(timeout) { yield }
|
171
180
|
end
|
172
181
|
|
173
182
|
def evaluate_script(script)
|
174
|
-
|
175
|
-
driver.evaluate_script(script)
|
176
|
-
rescue NoMethodError
|
177
|
-
raise NotSupportedByDriverError
|
178
|
-
end
|
183
|
+
driver.evaluate_script(script)
|
179
184
|
end
|
180
185
|
|
181
186
|
private
|
182
187
|
|
183
|
-
def
|
184
|
-
|
188
|
+
def wait_conditionally_until
|
189
|
+
if driver.wait? then wait_until { yield } else yield end
|
185
190
|
end
|
186
191
|
|
187
|
-
def
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
node.text.include?(text)
|
192
|
-
when Regexp
|
193
|
-
node.text =~ text
|
194
|
-
end
|
195
|
-
end
|
192
|
+
def all_unfiltered(locator)
|
193
|
+
XPath.wrap(locator).scope(current_scope).paths.map do |path|
|
194
|
+
driver.find(path)
|
195
|
+
end.flatten
|
196
196
|
end
|
197
197
|
|
198
198
|
def current_scope
|