bjeanes-capybara 0.3.1
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 +4 -0
- data/Manifest.txt +87 -0
- data/README.rdoc +404 -0
- data/Rakefile +29 -0
- data/config.ru +6 -0
- data/lib/capybara.rb +53 -0
- data/lib/capybara/cucumber.rb +32 -0
- data/lib/capybara/driver/base.rb +37 -0
- data/lib/capybara/driver/celerity_driver.rb +135 -0
- data/lib/capybara/driver/culerity_driver.rb +25 -0
- data/lib/capybara/driver/rack_test_driver.rb +244 -0
- data/lib/capybara/driver/selenium_driver.rb +137 -0
- data/lib/capybara/dsl.rb +60 -0
- data/lib/capybara/node.rb +69 -0
- data/lib/capybara/rails.rb +11 -0
- data/lib/capybara/save_and_open_page.rb +33 -0
- data/lib/capybara/searchable.rb +53 -0
- data/lib/capybara/server.rb +111 -0
- data/lib/capybara/session.rb +274 -0
- data/lib/capybara/wait_until.rb +23 -0
- data/lib/capybara/xpath.rb +176 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/capybara_spec.rb +18 -0
- data/spec/driver/celerity_driver_spec.rb +17 -0
- data/spec/driver/culerity_driver_spec.rb +13 -0
- data/spec/driver/rack_test_driver_spec.rb +12 -0
- data/spec/driver/remote_culerity_driver_spec.rb +26 -0
- data/spec/driver/remote_selenium_driver_spec.rb +18 -0
- data/spec/driver/selenium_driver_spec.rb +12 -0
- data/spec/drivers_spec.rb +139 -0
- data/spec/dsl/all_spec.rb +69 -0
- data/spec/dsl/attach_file_spec.rb +64 -0
- data/spec/dsl/check_spec.rb +39 -0
- data/spec/dsl/choose_spec.rb +26 -0
- data/spec/dsl/click_button_spec.rb +218 -0
- data/spec/dsl/click_link_spec.rb +108 -0
- data/spec/dsl/click_spec.rb +24 -0
- data/spec/dsl/current_url_spec.rb +8 -0
- data/spec/dsl/fill_in_spec.rb +91 -0
- data/spec/dsl/find_button_spec.rb +16 -0
- data/spec/dsl/find_by_id_spec.rb +16 -0
- data/spec/dsl/find_field_spec.rb +22 -0
- data/spec/dsl/find_link_spec.rb +17 -0
- data/spec/dsl/find_spec.rb +57 -0
- data/spec/dsl/has_button_spec.rb +32 -0
- data/spec/dsl/has_content_spec.rb +101 -0
- data/spec/dsl/has_css_spec.rb +107 -0
- 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 +123 -0
- data/spec/dsl/locate_spec.rb +59 -0
- data/spec/dsl/select_spec.rb +71 -0
- data/spec/dsl/uncheck_spec.rb +21 -0
- data/spec/dsl/within_spec.rb +153 -0
- data/spec/dsl_spec.rb +140 -0
- data/spec/fixtures/capybara.jpg +0 -0
- data/spec/fixtures/test_file.txt +1 -0
- data/spec/public/jquery-ui.js +35 -0
- data/spec/public/jquery.js +19 -0
- data/spec/public/test.js +30 -0
- data/spec/save_and_open_page_spec.rb +43 -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 +25 -0
- data/spec/session/rack_test_session_spec.rb +25 -0
- data/spec/session/selenium_session_spec.rb +25 -0
- data/spec/session_spec.rb +77 -0
- data/spec/session_with_headers_support_spec.rb +13 -0
- data/spec/session_with_javascript_support_spec.rb +182 -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 +27 -0
- data/spec/test_app.rb +71 -0
- data/spec/views/buttons.erb +4 -0
- data/spec/views/fieldsets.erb +29 -0
- data/spec/views/form.erb +226 -0
- data/spec/views/postback.erb +13 -0
- data/spec/views/tables.erb +122 -0
- data/spec/views/with_html.erb +38 -0
- data/spec/views/with_js.erb +34 -0
- data/spec/views/with_scope.erb +36 -0
- data/spec/views/with_simple_html.erb +1 -0
- data/spec/wait_until_spec.rb +28 -0
- data/spec/xpath_spec.rb +271 -0
- metadata +239 -0
@@ -0,0 +1,274 @@
|
|
1
|
+
require 'capybara/wait_until'
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
class Session
|
5
|
+
include Searchable
|
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?
|
13
|
+
]
|
14
|
+
|
15
|
+
attr_reader :mode, :app
|
16
|
+
|
17
|
+
def initialize(mode, app)
|
18
|
+
@mode = mode
|
19
|
+
@app = app
|
20
|
+
end
|
21
|
+
|
22
|
+
def driver
|
23
|
+
@driver ||= case mode
|
24
|
+
when :rack_test
|
25
|
+
Capybara::Driver::RackTest.new(app)
|
26
|
+
when :selenium
|
27
|
+
Capybara::Driver::Selenium.new(app)
|
28
|
+
when :celerity
|
29
|
+
Capybara::Driver::Celerity.new(app)
|
30
|
+
when :culerity
|
31
|
+
Capybara::Driver::Culerity.new(app)
|
32
|
+
else
|
33
|
+
raise Capybara::DriverNotFoundError, "no driver called #{mode} was found"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def cleanup!
|
38
|
+
driver.cleanup!
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_url
|
42
|
+
driver.current_url
|
43
|
+
end
|
44
|
+
|
45
|
+
def response_headers
|
46
|
+
driver.response_headers
|
47
|
+
end
|
48
|
+
|
49
|
+
def visit(path)
|
50
|
+
driver.visit(path)
|
51
|
+
end
|
52
|
+
|
53
|
+
def click(locator)
|
54
|
+
msg = "no link or button '#{locator}' found"
|
55
|
+
locate(:xpath, XPath.link(locator).button(locator), msg).click
|
56
|
+
end
|
57
|
+
|
58
|
+
def click_link(locator)
|
59
|
+
msg = "no link with title, id or text '#{locator}' found"
|
60
|
+
locate(:xpath, XPath.link(locator), msg).click
|
61
|
+
end
|
62
|
+
|
63
|
+
def click_button(locator)
|
64
|
+
msg = "no button with value or id or text '#{locator}' found"
|
65
|
+
locate(:xpath, XPath.button(locator), msg).click
|
66
|
+
end
|
67
|
+
|
68
|
+
def drag(source_locator, target_locator)
|
69
|
+
source = locate(:xpath, source_locator, "drag source '#{source_locator}' not found on page")
|
70
|
+
target = locate(:xpath, target_locator, "drag target '#{target_locator}' not found on page")
|
71
|
+
source.drag_to(target)
|
72
|
+
end
|
73
|
+
|
74
|
+
def fill_in(locator, options={})
|
75
|
+
msg = "cannot fill in, no text field, text area or password field with id, name, or label '#{locator}' found"
|
76
|
+
locate(:xpath, XPath.fillable_field(locator), msg).set(options[:with])
|
77
|
+
end
|
78
|
+
|
79
|
+
def choose(locator)
|
80
|
+
msg = "cannot choose field, no radio button with id, name, or label '#{locator}' found"
|
81
|
+
locate(:xpath, XPath.radio_button(locator), msg).set(true)
|
82
|
+
end
|
83
|
+
|
84
|
+
def check(locator)
|
85
|
+
msg = "cannot check field, no checkbox with id, name, or label '#{locator}' found"
|
86
|
+
locate(:xpath, XPath.checkbox(locator), msg).set(true)
|
87
|
+
end
|
88
|
+
|
89
|
+
def uncheck(locator)
|
90
|
+
msg = "cannot uncheck field, no checkbox with id, name, or label '#{locator}' found"
|
91
|
+
locate(:xpath, XPath.checkbox(locator), msg).set(false)
|
92
|
+
end
|
93
|
+
|
94
|
+
def select(value, options={})
|
95
|
+
msg = "cannot select option, no select box with id, name, or label '#{options[:from]}' found"
|
96
|
+
locate(:xpath, XPath.select(options[:from]), msg).select(value)
|
97
|
+
end
|
98
|
+
|
99
|
+
def unselect(value, options={})
|
100
|
+
msg = "cannot unselect option, no select box with id, name, or label '#{options[:from]}' found"
|
101
|
+
locate(:xpath, XPath.select(options[:from]), msg).unselect(value)
|
102
|
+
end
|
103
|
+
|
104
|
+
def attach_file(locator, path)
|
105
|
+
msg = "cannot attach file, no file field with id, name, or label '#{locator}' found"
|
106
|
+
locate(:xpath, XPath.file_field(locator), msg).set(path)
|
107
|
+
end
|
108
|
+
|
109
|
+
def body
|
110
|
+
driver.body
|
111
|
+
end
|
112
|
+
|
113
|
+
def source
|
114
|
+
driver.source
|
115
|
+
end
|
116
|
+
|
117
|
+
def within(kind, scope=nil)
|
118
|
+
kind, scope = Capybara.default_selector, kind unless scope
|
119
|
+
scope = XPath.from_css(scope) if kind == :css
|
120
|
+
locate(:xpath, scope, "scope '#{scope}' not found on page")
|
121
|
+
begin
|
122
|
+
scopes.push(scope)
|
123
|
+
yield
|
124
|
+
ensure
|
125
|
+
scopes.pop
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def within_fieldset(locator)
|
130
|
+
within :xpath, XPath.fieldset(locator) do
|
131
|
+
yield
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def within_table(locator)
|
136
|
+
within :xpath, XPath.table(locator) do
|
137
|
+
yield
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def has_xpath?(path, options={})
|
142
|
+
wait_conditionally_until do
|
143
|
+
results = all(:xpath, path, options)
|
144
|
+
|
145
|
+
if options[:count]
|
146
|
+
results.size == options[:count]
|
147
|
+
else
|
148
|
+
results.size > 0
|
149
|
+
end
|
150
|
+
end
|
151
|
+
rescue Capybara::TimeoutError
|
152
|
+
return false
|
153
|
+
end
|
154
|
+
|
155
|
+
def has_no_xpath?(path, options={})
|
156
|
+
wait_conditionally_until do
|
157
|
+
results = all(:xpath, path, options)
|
158
|
+
|
159
|
+
if options[:count]
|
160
|
+
results.size != options[:count]
|
161
|
+
else
|
162
|
+
results.empty?
|
163
|
+
end
|
164
|
+
end
|
165
|
+
rescue Capybara::TimeoutError
|
166
|
+
return false
|
167
|
+
end
|
168
|
+
|
169
|
+
def has_css?(path, options={})
|
170
|
+
has_xpath?(XPath.from_css(path), options)
|
171
|
+
end
|
172
|
+
|
173
|
+
def has_no_css?(path, options={})
|
174
|
+
has_no_xpath?(XPath.from_css(path), options)
|
175
|
+
end
|
176
|
+
|
177
|
+
def has_content?(content)
|
178
|
+
has_xpath?(XPath.content(content))
|
179
|
+
end
|
180
|
+
|
181
|
+
def has_no_content?(content)
|
182
|
+
has_no_xpath?(XPath.content(content))
|
183
|
+
end
|
184
|
+
|
185
|
+
def has_link?(locator)
|
186
|
+
has_xpath?(XPath.link(locator))
|
187
|
+
end
|
188
|
+
|
189
|
+
def has_no_link?(locator)
|
190
|
+
has_no_xpath?(XPath.link(locator))
|
191
|
+
end
|
192
|
+
|
193
|
+
def has_button?(locator)
|
194
|
+
has_xpath?(XPath.button(locator))
|
195
|
+
end
|
196
|
+
|
197
|
+
def has_no_button?(locator)
|
198
|
+
has_no_xpath?(XPath.button(locator))
|
199
|
+
end
|
200
|
+
|
201
|
+
def has_field?(locator, options={})
|
202
|
+
has_xpath?(XPath.field(locator, options))
|
203
|
+
end
|
204
|
+
|
205
|
+
def has_no_field?(locator, options={})
|
206
|
+
has_no_xpath?(XPath.field(locator, options))
|
207
|
+
end
|
208
|
+
|
209
|
+
def has_checked_field?(locator)
|
210
|
+
has_xpath?(XPath.field(locator, :checked => true))
|
211
|
+
end
|
212
|
+
|
213
|
+
def has_unchecked_field?(locator)
|
214
|
+
has_xpath?(XPath.field(locator, :unchecked => true))
|
215
|
+
end
|
216
|
+
|
217
|
+
def has_select?(locator, options={})
|
218
|
+
has_xpath?(XPath.select(locator, options))
|
219
|
+
end
|
220
|
+
|
221
|
+
def has_no_select?(locator, options={})
|
222
|
+
has_no_xpath?(XPath.select(locator, options))
|
223
|
+
end
|
224
|
+
|
225
|
+
def has_table?(locator, options={})
|
226
|
+
has_xpath?(XPath.table(locator, options))
|
227
|
+
end
|
228
|
+
|
229
|
+
def has_no_table?(locator, options={})
|
230
|
+
has_no_xpath?(XPath.table(locator, options))
|
231
|
+
end
|
232
|
+
|
233
|
+
def save_and_open_page
|
234
|
+
require 'capybara/save_and_open_page'
|
235
|
+
Capybara::SaveAndOpenPage.save_and_open_page(body)
|
236
|
+
end
|
237
|
+
|
238
|
+
#return node identified by locator or raise ElementNotFound(using desc)
|
239
|
+
def locate(kind_or_locator, locator=nil, fail_msg = nil)
|
240
|
+
node = wait_conditionally_until { find(kind_or_locator, locator) }
|
241
|
+
ensure
|
242
|
+
raise Capybara::ElementNotFound, fail_msg || "Unable to locate '#{kind_or_locator}'" unless node
|
243
|
+
return node
|
244
|
+
end
|
245
|
+
|
246
|
+
def wait_until(timeout = Capybara.default_wait_time)
|
247
|
+
WaitUntil.timeout(timeout) { yield }
|
248
|
+
end
|
249
|
+
|
250
|
+
def evaluate_script(script)
|
251
|
+
driver.evaluate_script(script)
|
252
|
+
end
|
253
|
+
|
254
|
+
private
|
255
|
+
|
256
|
+
def wait_conditionally_until
|
257
|
+
if driver.wait? then wait_until { yield } else yield end
|
258
|
+
end
|
259
|
+
|
260
|
+
def all_unfiltered(locator)
|
261
|
+
XPath.wrap(locator).scope(current_scope).paths.map do |path|
|
262
|
+
driver.find(path)
|
263
|
+
end.flatten
|
264
|
+
end
|
265
|
+
|
266
|
+
def current_scope
|
267
|
+
scopes.join('')
|
268
|
+
end
|
269
|
+
|
270
|
+
def scopes
|
271
|
+
@scopes ||= []
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Capybara
|
2
|
+
#Provides timeout similar to standard library Timeout, but avoids threads
|
3
|
+
class WaitUntil
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def timeout(seconds = 1, &block)
|
8
|
+
start_time = Time.now
|
9
|
+
|
10
|
+
result = nil
|
11
|
+
|
12
|
+
until result
|
13
|
+
return result if result = yield
|
14
|
+
|
15
|
+
if (Time.now - start_time) > seconds
|
16
|
+
raise TimeoutError
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module Capybara
|
2
|
+
# this is a class for generating XPath queries, use it like this:
|
3
|
+
# Xpath.text_field('foo').link('blah').to_s
|
4
|
+
# this will generate an XPath that matches either a text field or a link
|
5
|
+
class XPath
|
6
|
+
|
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
|
+
def wrap(path)
|
14
|
+
if path.is_a?(self)
|
15
|
+
path
|
16
|
+
else
|
17
|
+
new(path.to_s)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to?(method)
|
22
|
+
new.respond_to?(method)
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(*args)
|
26
|
+
new.send(*args)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :paths
|
31
|
+
|
32
|
+
def initialize(*paths)
|
33
|
+
@paths = paths
|
34
|
+
end
|
35
|
+
|
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
|
46
|
+
end
|
47
|
+
|
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)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def content(locator)
|
55
|
+
append("/descendant-or-self::*[contains(.,#{s(locator)})]")
|
56
|
+
end
|
57
|
+
|
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}")
|
68
|
+
end
|
69
|
+
|
70
|
+
def fieldset(locator)
|
71
|
+
append("//fieldset[@id=#{s(locator)} or contains(legend,#{s(locator)})]")
|
72
|
+
end
|
73
|
+
|
74
|
+
def link(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)}]]")
|
77
|
+
end
|
78
|
+
|
79
|
+
def button(locator)
|
80
|
+
xpath = append("//input[@type='submit' or @type='image' or @type='button'][@id=#{s(locator)} or contains(@value,#{s(locator)})]")
|
81
|
+
xpath = xpath.append("//button[@id=#{s(locator)} or contains(@value,#{s(locator)}) or contains(.,#{s(locator)})]")
|
82
|
+
xpath = xpath.prepend("//input[@type='submit' or @type='image' or @type='button'][@value=#{s(locator)}]")
|
83
|
+
xpath = xpath.prepend("//button[@value=#{s(locator)} or text()=#{s(locator)}]")
|
84
|
+
end
|
85
|
+
|
86
|
+
def text_area(locator, options={})
|
87
|
+
options = options.merge(:text => options[:with]) if options.has_key?(:with)
|
88
|
+
add_field(locator, "//textarea", options)
|
89
|
+
end
|
90
|
+
|
91
|
+
def select(locator, options={})
|
92
|
+
add_field(locator, "//select", options)
|
93
|
+
end
|
94
|
+
|
95
|
+
def input_field(type, locator, options={})
|
96
|
+
options = options.merge(:value => options[:with]) if options.has_key?(:with)
|
97
|
+
add_field(locator, "//input[@type='#{type}']", options)
|
98
|
+
end
|
99
|
+
|
100
|
+
def scope(scope)
|
101
|
+
XPath.new(*paths.map { |p| scope + p })
|
102
|
+
end
|
103
|
+
|
104
|
+
def to_s
|
105
|
+
@paths.join(' | ')
|
106
|
+
end
|
107
|
+
|
108
|
+
def append(path)
|
109
|
+
XPath.new(*[@paths, XPath.wrap(path).paths].flatten)
|
110
|
+
end
|
111
|
+
|
112
|
+
def prepend(path)
|
113
|
+
XPath.new(*[XPath.wrap(path).paths, @paths].flatten)
|
114
|
+
end
|
115
|
+
|
116
|
+
def checkbox(locator, options={})
|
117
|
+
input_field(:checkbox, locator, options)
|
118
|
+
end
|
119
|
+
|
120
|
+
def radio_button(locator, options={})
|
121
|
+
input_field(:radio, locator, options)
|
122
|
+
end
|
123
|
+
|
124
|
+
[:text, :password, :email, :url, :search, :tel, :color, :file].each do |type|
|
125
|
+
class_eval <<-RUBY, __FILE__, __LINE__+1
|
126
|
+
def #{type}_field(locator)
|
127
|
+
input_field(:#{type}, locator)
|
128
|
+
end
|
129
|
+
RUBY
|
130
|
+
end
|
131
|
+
|
132
|
+
protected
|
133
|
+
|
134
|
+
# place this between to nodes to indicate that they should be siblings
|
135
|
+
def sibling
|
136
|
+
'/following-sibling::*[1]/self::'
|
137
|
+
end
|
138
|
+
|
139
|
+
def add_field(locator, field, options={})
|
140
|
+
postfix = extract_postfix(options)
|
141
|
+
xpath = append("#{field}[@id=#{s(locator)}]#{postfix}")
|
142
|
+
xpath = xpath.append("#{field}[@name=#{s(locator)}]#{postfix}")
|
143
|
+
xpath = xpath.append("#{field}[@id=//label[contains(.,#{s(locator)})]/@for]#{postfix}")
|
144
|
+
xpath = xpath.append("//label[contains(.,#{s(locator)})]#{field}#{postfix}")
|
145
|
+
xpath.prepend("#{field}[@id=//label[text()=#{s(locator)}]/@for]#{postfix}")
|
146
|
+
end
|
147
|
+
|
148
|
+
def extract_postfix(options)
|
149
|
+
options.inject("") do |postfix, (key, value)|
|
150
|
+
case key
|
151
|
+
when :value then postfix += "[@value=#{s(value)}]"
|
152
|
+
when :text then postfix += "[text()=#{s(value)}]"
|
153
|
+
when :checked then postfix += "[@checked]"
|
154
|
+
when :unchecked then postfix += "[not(@checked)]"
|
155
|
+
when :options then postfix += value.map { |o| "[./option/text()=#{s(o)}]" }.join
|
156
|
+
when :selected then postfix += [value].flatten.map { |o| "[./option[@selected]/text()=#{s(o)}]" }.join
|
157
|
+
end
|
158
|
+
postfix
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Sanitize a String for putting it into an xpath query
|
163
|
+
def s(string)
|
164
|
+
if string.include?("'")
|
165
|
+
string = string.split("'", -1).map do |substr|
|
166
|
+
"'#{substr}'"
|
167
|
+
end.join(%q{,"'",})
|
168
|
+
"concat(#{string})"
|
169
|
+
else
|
170
|
+
"'#{string}'"
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|