capybara 0.3.0 → 0.3.5
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 +4 -0
- data/README.rdoc +45 -5
- data/lib/capybara.rb +11 -4
- data/lib/capybara/driver/base.rb +3 -0
- data/lib/capybara/driver/celerity_driver.rb +44 -9
- data/lib/capybara/driver/rack_test_driver.rb +80 -16
- data/lib/capybara/driver/selenium_driver.rb +41 -9
- data/lib/capybara/dsl.rb +4 -10
- data/lib/capybara/node.rb +8 -0
- data/lib/capybara/rails.rb +8 -2
- data/lib/capybara/save_and_open_page.rb +5 -1
- data/lib/capybara/searchable.rb +17 -9
- data/lib/capybara/server.rb +35 -23
- data/lib/capybara/session.rb +91 -22
- data/lib/capybara/xpath.rb +66 -27
- data/spec/driver/celerity_driver_spec.rb +2 -2
- data/spec/driver/culerity_driver_spec.rb +1 -2
- data/spec/driver/rack_test_driver_spec.rb +0 -1
- data/spec/driver/remote_culerity_driver_spec.rb +9 -5
- data/spec/driver/selenium_driver_spec.rb +0 -1
- data/spec/drivers_spec.rb +24 -32
- data/spec/dsl/all_spec.rb +56 -25
- data/spec/dsl/attach_file_spec.rb +49 -51
- data/spec/dsl/check_spec.rb +12 -1
- data/spec/dsl/choose_spec.rb +19 -21
- data/spec/dsl/click_button_spec.rb +140 -87
- data/spec/dsl/click_link_spec.rb +88 -68
- data/spec/dsl/click_spec.rb +20 -22
- data/spec/dsl/current_url_spec.rb +6 -8
- data/spec/dsl/fill_in_spec.rb +75 -67
- data/spec/dsl/find_button_spec.rb +12 -14
- data/spec/dsl/find_by_id_spec.rb +16 -0
- data/spec/dsl/find_field_spec.rb +17 -19
- data/spec/dsl/find_link_spec.rb +13 -15
- data/spec/dsl/find_spec.rb +44 -23
- data/spec/dsl/has_button_spec.rb +32 -0
- data/spec/dsl/has_content_spec.rb +79 -81
- data/spec/dsl/has_css_spec.rb +81 -83
- data/spec/dsl/has_field_spec.rb +96 -0
- data/spec/dsl/has_link_spec.rb +33 -0
- data/spec/dsl/has_xpath_spec.rb +97 -89
- data/spec/dsl/locate_spec.rb +47 -26
- data/spec/dsl/select_spec.rb +61 -17
- data/spec/dsl/uncheck_spec.rb +17 -25
- data/spec/dsl/within_spec.rb +112 -104
- data/spec/public/test.js +3 -0
- data/spec/searchable_spec.rb +1 -1
- data/spec/server_spec.rb +7 -7
- data/spec/session/celerity_session_spec.rb +2 -2
- data/spec/session/culerity_session_spec.rb +1 -1
- data/spec/session_spec.rb +7 -0
- data/spec/session_with_javascript_support_spec.rb +139 -120
- data/spec/spec_helper.rb +7 -2
- data/spec/test_app.rb +8 -4
- data/spec/views/form.erb +50 -2
- data/spec/views/tables.erb +61 -1
- data/spec/views/with_html.erb +8 -2
- data/spec/views/with_js.erb +4 -0
- data/spec/xpath_spec.rb +17 -0
- metadata +6 -2
data/lib/capybara/dsl.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
|
1
3
|
module Capybara
|
2
4
|
class << self
|
3
5
|
attr_writer :default_driver, :current_driver, :javascript_driver
|
@@ -30,6 +32,7 @@ module Capybara
|
|
30
32
|
end
|
31
33
|
|
32
34
|
def reset_sessions!
|
35
|
+
session_pool.each { |mode, session| session.cleanup! }
|
33
36
|
@session_pool = nil
|
34
37
|
end
|
35
38
|
|
@@ -46,16 +49,7 @@ module Capybara
|
|
46
49
|
Capybara.current_session
|
47
50
|
end
|
48
51
|
|
49
|
-
|
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
|
57
|
-
]
|
58
|
-
SESSION_METHODS.each do |method|
|
52
|
+
Session::DSL_METHODS.each do |method|
|
59
53
|
class_eval <<-RUBY, __FILE__, __LINE__+1
|
60
54
|
def #{method}(*args, &block)
|
61
55
|
page.#{method}(*args, &block)
|
data/lib/capybara/node.rb
CHANGED
@@ -29,6 +29,10 @@ module Capybara
|
|
29
29
|
raise NotImplementedError
|
30
30
|
end
|
31
31
|
|
32
|
+
def unselect(option)
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
32
36
|
def click
|
33
37
|
raise NotImplementedError
|
34
38
|
end
|
@@ -48,6 +52,10 @@ module Capybara
|
|
48
52
|
def path
|
49
53
|
raise NotSupportedByDriverError
|
50
54
|
end
|
55
|
+
|
56
|
+
def trigger(event)
|
57
|
+
raise NotSupportedByDriverError
|
58
|
+
end
|
51
59
|
|
52
60
|
private
|
53
61
|
|
data/lib/capybara/rails.rb
CHANGED
@@ -3,9 +3,15 @@ require 'capybara/dsl'
|
|
3
3
|
|
4
4
|
Capybara.app = Rack::Builder.new do
|
5
5
|
map "/" do
|
6
|
-
|
7
|
-
|
6
|
+
if Rails.version.to_f >= 3.0
|
7
|
+
ActionDispatch::Static
|
8
|
+
run Rails.application
|
9
|
+
else # Rails 2
|
10
|
+
use Rails::Rack::Static
|
11
|
+
run ActionController::Dispatcher.new
|
12
|
+
end
|
8
13
|
end
|
9
14
|
end.to_app
|
10
15
|
|
11
16
|
Capybara.asset_root = Rails.root.join('public')
|
17
|
+
|
@@ -23,7 +23,11 @@ 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
|
-
|
26
|
+
directories = Dir.new(Capybara.asset_root).entries.inject([]) do |list, name|
|
27
|
+
list << name if File.directory?(name) and not name.to_s =~ /^\./
|
28
|
+
list
|
29
|
+
end
|
30
|
+
response_html.gsub(/("|')\/(#{directories.join('|')})/, '\1' + Capybara.asset_root.to_s + '/\2')
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|
data/lib/capybara/searchable.rb
CHANGED
@@ -1,35 +1,43 @@
|
|
1
1
|
module Capybara
|
2
2
|
module Searchable
|
3
|
-
def find(
|
4
|
-
all(
|
3
|
+
def find(*args)
|
4
|
+
all(*args).first
|
5
5
|
end
|
6
6
|
|
7
7
|
def find_field(locator)
|
8
|
-
find(XPath.field(locator))
|
8
|
+
find(:xpath, XPath.field(locator))
|
9
9
|
end
|
10
10
|
alias_method :field_labeled, :find_field
|
11
11
|
|
12
12
|
def find_link(locator)
|
13
|
-
find(XPath.link(locator))
|
13
|
+
find(:xpath, XPath.link(locator))
|
14
14
|
end
|
15
15
|
|
16
16
|
def find_button(locator)
|
17
|
-
find(XPath.button(locator))
|
17
|
+
find(:xpath, XPath.button(locator))
|
18
18
|
end
|
19
19
|
|
20
20
|
def find_by_id(id)
|
21
|
-
find(
|
21
|
+
find(:css, "##{id}")
|
22
22
|
end
|
23
23
|
|
24
|
-
def all(
|
24
|
+
def all(*args)
|
25
|
+
options = if args.last.is_a?(Hash) then args.pop else {} end
|
26
|
+
if args[1].nil?
|
27
|
+
kind, locator = Capybara.default_selector, args.first
|
28
|
+
else
|
29
|
+
kind, locator = args
|
30
|
+
end
|
31
|
+
locator = XPath.from_css(locator) if kind == :css
|
32
|
+
|
25
33
|
results = all_unfiltered(locator)
|
26
34
|
|
27
35
|
if options[:text]
|
28
36
|
results = results.select { |n| n.text.match(options[:text]) }
|
29
37
|
end
|
30
38
|
|
31
|
-
if options[:visible]
|
32
|
-
results.
|
39
|
+
if options[:visible] or Capybara.ignore_hidden_elements
|
40
|
+
results = results.select { |n| n.visible? }
|
33
41
|
end
|
34
42
|
|
35
43
|
results
|
data/lib/capybara/server.rb
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'net/http'
|
3
3
|
require 'rack'
|
4
|
-
begin
|
5
|
-
require 'rack/handler/mongrel'
|
6
|
-
rescue LoadError
|
7
|
-
require 'rack/handler/webrick'
|
8
|
-
end
|
9
4
|
|
10
5
|
class Capybara::Server
|
11
6
|
class Identify
|
@@ -26,49 +21,66 @@ class Capybara::Server
|
|
26
21
|
|
27
22
|
def initialize(app)
|
28
23
|
@app = app
|
29
|
-
find_available_port
|
30
|
-
boot
|
31
24
|
end
|
32
25
|
|
33
26
|
def host
|
34
|
-
|
27
|
+
"localhost"
|
35
28
|
end
|
36
29
|
|
37
30
|
def url(path)
|
38
|
-
|
39
|
-
|
31
|
+
if path =~ /^http/
|
32
|
+
path
|
33
|
+
else
|
34
|
+
(Capybara.app_host || "http://#{host}:#{port}") + path.to_s
|
35
|
+
end
|
40
36
|
end
|
41
37
|
|
42
38
|
def responsive?
|
43
39
|
is_running_on_port?(port)
|
44
40
|
end
|
45
41
|
|
46
|
-
|
42
|
+
def handler
|
43
|
+
begin
|
44
|
+
require 'rack/handler/thin'
|
45
|
+
Rack::Handler::Thin
|
46
|
+
rescue LoadError
|
47
|
+
begin
|
48
|
+
require 'rack/handler/mongrel'
|
49
|
+
Rack::Handler::Mongrel
|
50
|
+
rescue LoadError
|
51
|
+
require 'rack/handler/webrick'
|
52
|
+
Rack::Handler::WEBrick
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
47
56
|
|
48
57
|
def boot
|
49
|
-
|
58
|
+
find_available_port
|
59
|
+
Capybara.log "application has already booted" and return self if responsive?
|
50
60
|
Capybara.log "booting Rack applicartion on port #{port}"
|
51
61
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
else
|
57
|
-
Rack::Handler::WEBrick.run(Identify.new(@app), :Port => port, :AccessLog => [])
|
58
|
-
end
|
59
|
-
end
|
60
|
-
Capybara.log "checking if application has booted"
|
62
|
+
Thread.new do
|
63
|
+
handler.run(Identify.new(@app), :Port => port, :AccessLog => [])
|
64
|
+
end
|
65
|
+
Capybara.log "checking if application has booted"
|
61
66
|
|
62
|
-
|
63
|
-
|
67
|
+
Capybara::WaitUntil.timeout(10) do
|
68
|
+
if responsive?
|
69
|
+
Capybara.log("application has booted")
|
70
|
+
true
|
71
|
+
else
|
64
72
|
sleep 0.5
|
73
|
+
false
|
65
74
|
end
|
66
75
|
end
|
76
|
+
self
|
67
77
|
rescue Timeout::Error
|
68
78
|
Capybara.log "Rack application timed out during boot"
|
69
79
|
exit
|
70
80
|
end
|
71
81
|
|
82
|
+
private
|
83
|
+
|
72
84
|
def find_available_port
|
73
85
|
@port = 9887
|
74
86
|
@port += 1 while is_port_open?(@port) and not is_running_on_port?(@port)
|
data/lib/capybara/session.rb
CHANGED
@@ -4,6 +4,15 @@ module Capybara
|
|
4
4
|
class Session
|
5
5
|
include Searchable
|
6
6
|
|
7
|
+
DSL_METHODS = [
|
8
|
+
:all, :attach_file, :body, :check, :choose, :click, :click_button, :click_link, :current_url, :drag, :evaluate_script,
|
9
|
+
:field_labeled, :fill_in, :find, :find_button, :find_by_id, :find_field, :find_link, :has_content?, :has_css?,
|
10
|
+
:has_no_content?, :has_no_css?, :has_no_xpath?, :has_xpath?, :locate, :save_and_open_page, :select, :source, :uncheck,
|
11
|
+
:visit, :wait_until, :within, :within_fieldset, :within_table, :has_link?, :has_no_link?, :has_button?, :has_no_button?,
|
12
|
+
:has_field?, :has_no_field?, :has_checked_field?, :has_unchecked_field?, :has_no_table?, :has_table?, :unselect,
|
13
|
+
:has_select?, :has_no_select?
|
14
|
+
]
|
15
|
+
|
7
16
|
attr_reader :mode, :app
|
8
17
|
|
9
18
|
def initialize(mode, app)
|
@@ -26,6 +35,10 @@ module Capybara
|
|
26
35
|
end
|
27
36
|
end
|
28
37
|
|
38
|
+
def cleanup!
|
39
|
+
driver.cleanup!
|
40
|
+
end
|
41
|
+
|
29
42
|
def current_url
|
30
43
|
driver.current_url
|
31
44
|
end
|
@@ -40,53 +53,58 @@ module Capybara
|
|
40
53
|
|
41
54
|
def click(locator)
|
42
55
|
msg = "no link or button '#{locator}' found"
|
43
|
-
locate(XPath.link(locator).button(locator), msg).click
|
56
|
+
locate(:xpath, XPath.link(locator).button(locator), msg).click
|
44
57
|
end
|
45
58
|
|
46
59
|
def click_link(locator)
|
47
60
|
msg = "no link with title, id or text '#{locator}' found"
|
48
|
-
locate(XPath.link(locator), msg).click
|
61
|
+
locate(:xpath, XPath.link(locator), msg).click
|
49
62
|
end
|
50
63
|
|
51
64
|
def click_button(locator)
|
52
65
|
msg = "no button with value or id or text '#{locator}' found"
|
53
|
-
locate(XPath.button(locator)).click
|
66
|
+
locate(:xpath, XPath.button(locator), msg).click
|
54
67
|
end
|
55
68
|
|
56
69
|
def drag(source_locator, target_locator)
|
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")
|
70
|
+
source = locate(:xpath, source_locator, "drag source '#{source_locator}' not found on page")
|
71
|
+
target = locate(:xpath, target_locator, "drag target '#{target_locator}' not found on page")
|
59
72
|
source.drag_to(target)
|
60
73
|
end
|
61
74
|
|
62
75
|
def fill_in(locator, options={})
|
63
76
|
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])
|
77
|
+
locate(:xpath, XPath.fillable_field(locator), msg).set(options[:with])
|
65
78
|
end
|
66
79
|
|
67
80
|
def choose(locator)
|
68
81
|
msg = "cannot choose field, no radio button with id, name, or label '#{locator}' found"
|
69
|
-
locate(XPath.radio_button(locator), msg).set(true)
|
82
|
+
locate(:xpath, XPath.radio_button(locator), msg).set(true)
|
70
83
|
end
|
71
84
|
|
72
85
|
def check(locator)
|
73
86
|
msg = "cannot check field, no checkbox with id, name, or label '#{locator}' found"
|
74
|
-
locate(XPath.checkbox(locator), msg).set(true)
|
87
|
+
locate(:xpath, XPath.checkbox(locator), msg).set(true)
|
75
88
|
end
|
76
89
|
|
77
90
|
def uncheck(locator)
|
78
91
|
msg = "cannot uncheck field, no checkbox with id, name, or label '#{locator}' found"
|
79
|
-
locate(XPath.checkbox(locator), msg).set(false)
|
92
|
+
locate(:xpath, XPath.checkbox(locator), msg).set(false)
|
80
93
|
end
|
81
94
|
|
82
95
|
def select(value, options={})
|
83
96
|
msg = "cannot select option, no select box with id, name, or label '#{options[:from]}' found"
|
84
|
-
locate(XPath.select(options[:from]), msg).select(value)
|
97
|
+
locate(:xpath, XPath.select(options[:from]), msg).select(value)
|
98
|
+
end
|
99
|
+
|
100
|
+
def unselect(value, options={})
|
101
|
+
msg = "cannot unselect option, no select box with id, name, or label '#{options[:from]}' found"
|
102
|
+
locate(:xpath, XPath.select(options[:from]), msg).unselect(value)
|
85
103
|
end
|
86
104
|
|
87
105
|
def attach_file(locator, path)
|
88
106
|
msg = "cannot attach file, no file field with id, name, or label '#{locator}' found"
|
89
|
-
locate(XPath.file_field(locator), msg).set(path)
|
107
|
+
locate(:xpath, XPath.file_field(locator), msg).set(path)
|
90
108
|
end
|
91
109
|
|
92
110
|
def body
|
@@ -100,27 +118,30 @@ module Capybara
|
|
100
118
|
def within(kind, scope=nil)
|
101
119
|
kind, scope = Capybara.default_selector, kind unless scope
|
102
120
|
scope = XPath.from_css(scope) if kind == :css
|
103
|
-
locate(scope, "scope '#{scope}' not found on page")
|
104
|
-
|
105
|
-
|
106
|
-
|
121
|
+
locate(:xpath, scope, "scope '#{scope}' not found on page")
|
122
|
+
begin
|
123
|
+
scopes.push(scope)
|
124
|
+
yield
|
125
|
+
ensure
|
126
|
+
scopes.pop
|
127
|
+
end
|
107
128
|
end
|
108
129
|
|
109
130
|
def within_fieldset(locator)
|
110
|
-
within XPath.fieldset(locator) do
|
131
|
+
within :xpath, XPath.fieldset(locator) do
|
111
132
|
yield
|
112
133
|
end
|
113
134
|
end
|
114
135
|
|
115
136
|
def within_table(locator)
|
116
|
-
within XPath.table(locator) do
|
137
|
+
within :xpath, XPath.table(locator) do
|
117
138
|
yield
|
118
139
|
end
|
119
140
|
end
|
120
141
|
|
121
142
|
def has_xpath?(path, options={})
|
122
143
|
wait_conditionally_until do
|
123
|
-
results = all(path, options)
|
144
|
+
results = all(:xpath, path, options)
|
124
145
|
|
125
146
|
if options[:count]
|
126
147
|
results.size == options[:count]
|
@@ -134,7 +155,7 @@ module Capybara
|
|
134
155
|
|
135
156
|
def has_no_xpath?(path, options={})
|
136
157
|
wait_conditionally_until do
|
137
|
-
results = all(path, options)
|
158
|
+
results = all(:xpath, path, options)
|
138
159
|
|
139
160
|
if options[:count]
|
140
161
|
results.size != options[:count]
|
@@ -162,16 +183,64 @@ module Capybara
|
|
162
183
|
has_no_xpath?(XPath.content(content))
|
163
184
|
end
|
164
185
|
|
186
|
+
def has_link?(locator)
|
187
|
+
has_xpath?(XPath.link(locator))
|
188
|
+
end
|
189
|
+
|
190
|
+
def has_no_link?(locator)
|
191
|
+
has_no_xpath?(XPath.link(locator))
|
192
|
+
end
|
193
|
+
|
194
|
+
def has_button?(locator)
|
195
|
+
has_xpath?(XPath.button(locator))
|
196
|
+
end
|
197
|
+
|
198
|
+
def has_no_button?(locator)
|
199
|
+
has_no_xpath?(XPath.button(locator))
|
200
|
+
end
|
201
|
+
|
202
|
+
def has_field?(locator, options={})
|
203
|
+
has_xpath?(XPath.field(locator, options))
|
204
|
+
end
|
205
|
+
|
206
|
+
def has_no_field?(locator, options={})
|
207
|
+
has_no_xpath?(XPath.field(locator, options))
|
208
|
+
end
|
209
|
+
|
210
|
+
def has_checked_field?(locator)
|
211
|
+
has_xpath?(XPath.field(locator, :checked => true))
|
212
|
+
end
|
213
|
+
|
214
|
+
def has_unchecked_field?(locator)
|
215
|
+
has_xpath?(XPath.field(locator, :unchecked => true))
|
216
|
+
end
|
217
|
+
|
218
|
+
def has_select?(locator, options={})
|
219
|
+
has_xpath?(XPath.select(locator, options))
|
220
|
+
end
|
221
|
+
|
222
|
+
def has_no_select?(locator, options={})
|
223
|
+
has_no_xpath?(XPath.select(locator, options))
|
224
|
+
end
|
225
|
+
|
226
|
+
def has_table?(locator, options={})
|
227
|
+
has_xpath?(XPath.table(locator, options))
|
228
|
+
end
|
229
|
+
|
230
|
+
def has_no_table?(locator, options={})
|
231
|
+
has_no_xpath?(XPath.table(locator, options))
|
232
|
+
end
|
233
|
+
|
165
234
|
def save_and_open_page
|
166
235
|
require 'capybara/save_and_open_page'
|
167
236
|
Capybara::SaveAndOpenPage.save_and_open_page(body)
|
168
237
|
end
|
169
238
|
|
170
239
|
#return node identified by locator or raise ElementNotFound(using desc)
|
171
|
-
def locate(locator, fail_msg = nil)
|
172
|
-
node = wait_conditionally_until { find(locator) }
|
240
|
+
def locate(kind_or_locator, locator=nil, fail_msg = nil)
|
241
|
+
node = wait_conditionally_until { find(kind_or_locator, locator) }
|
173
242
|
ensure
|
174
|
-
raise Capybara::ElementNotFound, fail_msg || "Unable to locate '#{
|
243
|
+
raise Capybara::ElementNotFound, fail_msg || "Unable to locate '#{kind_or_locator}'" unless node
|
175
244
|
return node
|
176
245
|
end
|
177
246
|
|
data/lib/capybara/xpath.rb
CHANGED
@@ -33,13 +33,21 @@ module Capybara
|
|
33
33
|
@paths = paths
|
34
34
|
end
|
35
35
|
|
36
|
-
def field(locator)
|
37
|
-
|
36
|
+
def field(locator, options={})
|
37
|
+
if options[:with]
|
38
|
+
fillable_field(locator, options)
|
39
|
+
else
|
40
|
+
xpath = fillable_field(locator)
|
41
|
+
xpath = xpath.input_field(:file, locator, options)
|
42
|
+
xpath = xpath.checkbox(locator, options)
|
43
|
+
xpath = xpath.radio_button(locator, options)
|
44
|
+
xpath.select(locator, options)
|
45
|
+
end
|
38
46
|
end
|
39
47
|
|
40
|
-
def fillable_field(locator)
|
41
|
-
[:text, :password, :email, :url, :search, :tel, :color].inject(text_area(locator)) do |all, type|
|
42
|
-
all.input_field(type, locator)
|
48
|
+
def fillable_field(locator, options={})
|
49
|
+
[:text, :password, :email, :url, :search, :tel, :color].inject(text_area(locator, options)) do |all, type|
|
50
|
+
all.input_field(type, locator, options)
|
43
51
|
end
|
44
52
|
end
|
45
53
|
|
@@ -47,8 +55,16 @@ module Capybara
|
|
47
55
|
append("/descendant-or-self::*[contains(.,#{s(locator)})]")
|
48
56
|
end
|
49
57
|
|
50
|
-
def table(locator)
|
51
|
-
|
58
|
+
def table(locator, options={})
|
59
|
+
conditions = ""
|
60
|
+
if options[:rows]
|
61
|
+
row_conditions = options[:rows].map do |row|
|
62
|
+
row = row.map { |column| "*[self::td or self::th][text()=#{s(column)}]" }.join(sibling)
|
63
|
+
"tr[./#{row}]"
|
64
|
+
end.join(sibling)
|
65
|
+
conditions << "[.//#{row_conditions}]"
|
66
|
+
end
|
67
|
+
append("//table[@id=#{s(locator)} or contains(caption,#{s(locator)})]#{conditions}")
|
52
68
|
end
|
53
69
|
|
54
70
|
def fieldset(locator)
|
@@ -56,27 +72,30 @@ module Capybara
|
|
56
72
|
end
|
57
73
|
|
58
74
|
def link(locator)
|
59
|
-
xpath = append("//a[@href][@id=#{s(locator)} or contains(.,#{s(locator)}) or contains(@title,#{s(locator)})]")
|
60
|
-
xpath.prepend("//a[@href][text()=#{s(locator)} or @title=#{s(locator)}]")
|
75
|
+
xpath = append("//a[@href][@id=#{s(locator)} or contains(.,#{s(locator)}) or contains(@title,#{s(locator)}) or img[contains(@alt,#{s(locator)})]]")
|
76
|
+
xpath.prepend("//a[@href][text()=#{s(locator)} or @title=#{s(locator)} or img[@alt=#{s(locator)}]]")
|
61
77
|
end
|
62
78
|
|
63
79
|
def button(locator)
|
64
|
-
xpath = append("//input[@type='submit' or @type='image'][@id=#{s(locator)} or contains(@value,#{s(locator)})]")
|
80
|
+
xpath = append("//input[@type='submit' or @type='image' or @type='button'][@id=#{s(locator)} or contains(@value,#{s(locator)})]")
|
65
81
|
xpath = xpath.append("//button[@id=#{s(locator)} or contains(@value,#{s(locator)}) or contains(.,#{s(locator)})]")
|
66
|
-
xpath = xpath.prepend("//input[@type='submit' or @type='image'][@value=#{s(locator)}]")
|
82
|
+
xpath = xpath.prepend("//input[@type='submit' or @type='image' or @type='button'][@value=#{s(locator)}]")
|
83
|
+
xpath = xpath.prepend("//input[@type='image'][@alt=#{s(locator)} or contains(@alt,#{s(locator)})]")
|
67
84
|
xpath = xpath.prepend("//button[@value=#{s(locator)} or text()=#{s(locator)}]")
|
68
85
|
end
|
69
86
|
|
70
|
-
def text_area(locator)
|
71
|
-
|
87
|
+
def text_area(locator, options={})
|
88
|
+
options = options.merge(:text => options[:with]) if options.has_key?(:with)
|
89
|
+
add_field(locator, "//textarea", options)
|
72
90
|
end
|
73
91
|
|
74
|
-
def select(locator)
|
75
|
-
add_field(locator, "//select")
|
92
|
+
def select(locator, options={})
|
93
|
+
add_field(locator, "//select", options)
|
76
94
|
end
|
77
95
|
|
78
|
-
def input_field(type, locator)
|
79
|
-
|
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)
|
80
99
|
end
|
81
100
|
|
82
101
|
def scope(scope)
|
@@ -95,12 +114,12 @@ module Capybara
|
|
95
114
|
XPath.new(*[XPath.wrap(path).paths, @paths].flatten)
|
96
115
|
end
|
97
116
|
|
98
|
-
def checkbox(locator)
|
99
|
-
input_field(:checkbox, locator)
|
117
|
+
def checkbox(locator, options={})
|
118
|
+
input_field(:checkbox, locator, options)
|
100
119
|
end
|
101
120
|
|
102
|
-
def radio_button(locator)
|
103
|
-
input_field(:radio, locator)
|
121
|
+
def radio_button(locator, options={})
|
122
|
+
input_field(:radio, locator, options)
|
104
123
|
end
|
105
124
|
|
106
125
|
[:text, :password, :email, :url, :search, :tel, :color, :file].each do |type|
|
@@ -113,12 +132,32 @@ module Capybara
|
|
113
132
|
|
114
133
|
protected
|
115
134
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
135
|
+
# place this between to nodes to indicate that they should be siblings
|
136
|
+
def sibling
|
137
|
+
'/following-sibling::*[1]/self::'
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_field(locator, field, options={})
|
141
|
+
postfix = extract_postfix(options)
|
142
|
+
xpath = append("#{field}[@id=#{s(locator)}]#{postfix}")
|
143
|
+
xpath = xpath.append("#{field}[@name=#{s(locator)}]#{postfix}")
|
144
|
+
xpath = xpath.append("#{field}[@id=//label[contains(.,#{s(locator)})]/@for]#{postfix}")
|
145
|
+
xpath = xpath.append("//label[contains(.,#{s(locator)})]#{field}#{postfix}")
|
146
|
+
xpath.prepend("#{field}[@id=//label[text()=#{s(locator)}]/@for]#{postfix}")
|
147
|
+
end
|
148
|
+
|
149
|
+
def extract_postfix(options)
|
150
|
+
options.inject("") do |postfix, (key, value)|
|
151
|
+
case key
|
152
|
+
when :value then postfix += "[@value=#{s(value)}]"
|
153
|
+
when :text then postfix += "[text()=#{s(value)}]"
|
154
|
+
when :checked then postfix += "[@checked]"
|
155
|
+
when :unchecked then postfix += "[not(@checked)]"
|
156
|
+
when :options then postfix += value.map { |o| "[./option/text()=#{s(o)}]" }.join
|
157
|
+
when :selected then postfix += [value].flatten.map { |o| "[./option[@selected]/text()=#{s(o)}]" }.join
|
158
|
+
end
|
159
|
+
postfix
|
160
|
+
end
|
122
161
|
end
|
123
162
|
|
124
163
|
# Sanitize a String for putting it into an xpath query
|