capybara 2.11.0 → 2.12.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.
- checksums.yaml +4 -4
- data/History.md +30 -4
- data/README.md +4 -0
- data/lib/capybara.rb +4 -2
- data/lib/capybara/driver/base.rb +2 -2
- data/lib/capybara/helpers.rb +8 -2
- data/lib/capybara/node/actions.rb +52 -1
- data/lib/capybara/node/document_matchers.rb +1 -0
- data/lib/capybara/node/finders.rb +2 -1
- data/lib/capybara/node/matchers.rb +54 -0
- data/lib/capybara/node/simple.rb +1 -1
- data/lib/capybara/queries/current_path_query.rb +4 -2
- data/lib/capybara/queries/selector_query.rb +23 -3
- data/lib/capybara/queries/text_query.rb +15 -7
- data/lib/capybara/queries/title_query.rb +2 -2
- data/lib/capybara/rack_test/form.rb +1 -1
- data/lib/capybara/rack_test/node.rb +4 -4
- data/lib/capybara/result.rb +2 -2
- data/lib/capybara/selector.rb +16 -4
- data/lib/capybara/selenium/driver.rb +27 -22
- data/lib/capybara/selenium/node.rb +10 -1
- data/lib/capybara/session.rb +91 -30
- data/lib/capybara/spec/session/accept_prompt_spec.rb +3 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +94 -0
- data/lib/capybara/spec/session/assert_current_path.rb +12 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +30 -0
- data/lib/capybara/spec/session/click_link_spec.rb +12 -1
- data/lib/capybara/spec/session/current_url_spec.rb +8 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +14 -0
- data/lib/capybara/spec/session/execute_script_spec.rb +13 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
- data/lib/capybara/spec/session/find_field_spec.rb +2 -0
- data/lib/capybara/spec/session/find_spec.rb +3 -3
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +103 -0
- data/lib/capybara/spec/session/{within_frame_spec.rb → frame/within_frame_spec.rb} +12 -0
- data/lib/capybara/spec/session/has_current_path_spec.rb +28 -0
- data/lib/capybara/spec/session/has_selector_spec.rb +21 -0
- data/lib/capybara/spec/session/has_text_spec.rb +13 -1
- data/lib/capybara/spec/session/has_title_spec.rb +15 -0
- data/lib/capybara/spec/session/node_spec.rb +34 -1
- data/lib/capybara/spec/session/within_spec.rb +7 -0
- data/lib/capybara/spec/spec_helper.rb +4 -0
- data/lib/capybara/spec/views/form.erb +48 -0
- data/lib/capybara/spec/views/with_js.erb +5 -0
- data/lib/capybara/spec/views/within_frames.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +1 -1
- data/spec/capybara_spec.rb +2 -2
- data/spec/rack_test_spec.rb +10 -0
- data/spec/result_spec.rb +3 -3
- data/spec/rspec/shared_spec_matchers.rb +1 -1
- data/spec/session_spec.rb +10 -0
- data/spec/shared_selenium_session.rb +2 -1
- data/spec/spec_helper.rb +2 -0
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc177e8165f5b72a1dc1c1303b726701bc24254c
|
4
|
+
data.tar.gz: dab6b087b3ef03904d496bef6d3f66e2736b5bbd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f21cbebab1e87a9b9a411caf05acab9d912257604d6004db90af7439a692b862966e11291134424105698477b772cca46774aa95aad6ab78bdecd827ab862e83
|
7
|
+
data.tar.gz: c643a679ac6ac6cf17f03d63f74a97a20919980eead96c30b8b8c571120b19e0f94d2b7be978878580c6365483cc41476a83710b96200559e6be124dce620af0
|
data/History.md
CHANGED
@@ -1,4 +1,30 @@
|
|
1
|
-
#2.
|
1
|
+
#Version 2.12.0
|
2
|
+
Release date: 2017-01-22
|
3
|
+
|
4
|
+
### Added
|
5
|
+
|
6
|
+
* Session#switch_to_frame for manually handling frame switching - Issue #1365 [Thomas Walpole]
|
7
|
+
* Session#within_frame now accepts a selector type (defaults to :frame) and locator [Thomas Walpole]
|
8
|
+
* Session#execute_script and Session#evaluate_script now accept optional arguments that will be passed to the JS function. This may not be supported
|
9
|
+
by all drivers, and the types of arguments that may be passed is limited. If drivers opt to support this feature they should support passing page elements. [Thomas Walpole]
|
10
|
+
* :exact option for text and title matchers - Issue #1256 [Thomas Walpole]
|
11
|
+
* :exact_text option for selector finders/minders - Issue #1256 [Thomas Walpole]
|
12
|
+
* Capybara.exact_text setting that affects the text matchers and :text options passed to selector finders/matchers. Issue #1256 [Thomas Walpole]
|
13
|
+
* :make_visible option for #attach_file that allows for convenient changing of the CSS style of a file input element before attaching the file to it. Requires driver
|
14
|
+
support for passing page elements to Session#execute_script [Thomas Walpole]
|
15
|
+
* assert_all_selectors/assert_none_of_selectors assertions added
|
16
|
+
* :link selector (used by find_link/click_link) now supports finding hyperlink placeholders (no href attribute) when href: nil option is specified [Thomas Walpole]
|
17
|
+
* `within_element` as an alias of `within` due to RSpec collision
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
* Fields inside a disabled fieldset are now correctly considered disabled - Issue #1816 [Thomas Walpole]
|
21
|
+
* Lazy Capybara::Results evaluation enabled for JRuby 9.1.6.0+
|
22
|
+
* A driver returning nil for #current_url won't raise an exception when calling #current_path [Dylan Reichstadt]
|
23
|
+
* Support Ruby 2.4.0 unified Integer [Koichi ITO]
|
24
|
+
* RackTest driver no longer modifies the text content of textarea elements in order to behave more like a real browser [Thomas Walpole]
|
25
|
+
* TextQuery (assert_text/have_text/etc) now ignores errors when trying to generate more helpful errors messages so the original error isn't hidden [Thomas Walpole]
|
26
|
+
|
27
|
+
#Version 2.11.0
|
2
28
|
Release date: 2016-12-05
|
3
29
|
|
4
30
|
### Added
|
@@ -13,14 +39,14 @@ Release date: 2016-12-05
|
|
13
39
|
* Selenium driver with Chrome should support multiple file upload [Thomas Walpole]
|
14
40
|
* Fix visible: :hidden with :text option behavior [Thomas Walpole]
|
15
41
|
|
16
|
-
#2.10.2
|
42
|
+
#Version 2.10.2
|
17
43
|
Release date: 2016-11-30
|
18
44
|
|
19
45
|
### Fixed
|
20
46
|
* App exceptions with multiple parameter initializers now re-raised correctly - Issue #1785 [Michael Lutsiuk]
|
21
47
|
* Use Addressable::URI when parsing current_path since it's more lenient of technically invalid URLs - Issue #1801 [Marcos Duque, Thomas Walpole]
|
22
48
|
|
23
|
-
#2.10.1
|
49
|
+
#Version 2.10.1
|
24
50
|
Release date: 2016-10-08
|
25
51
|
|
26
52
|
### Fixed
|
@@ -28,7 +54,7 @@ Release date: 2016-10-08
|
|
28
54
|
* Capybara::Result optimization disabled in JRuby due to issue with lazy enumerator evaluation [Thomas Walpole]
|
29
55
|
See: https://github.com/jruby/jruby/issues/4212
|
30
56
|
|
31
|
-
#2.10.0
|
57
|
+
#Version 2.10.0
|
32
58
|
Release date: 2016-10-05
|
33
59
|
|
34
60
|
### Added
|
data/README.md
CHANGED
@@ -672,6 +672,10 @@ Or have it save and automatically open:
|
|
672
672
|
save_and_open_screenshot
|
673
673
|
```
|
674
674
|
|
675
|
+
Screenshots are saved to `Capybara.save_path`, relative to the app directory.
|
676
|
+
If you have required `capybara/rails`, `Capybara.save_path` will default to
|
677
|
+
`tmp/capybara`.
|
678
|
+
|
675
679
|
## <a name="matching"></a>Matching
|
676
680
|
|
677
681
|
It is possible to customize how Capybara finds elements. At your disposal
|
data/lib/capybara.rb
CHANGED
@@ -29,6 +29,7 @@ module Capybara
|
|
29
29
|
attr_accessor :raise_server_errors, :server_errors
|
30
30
|
attr_writer :default_driver, :current_driver, :javascript_driver, :session_name, :server_host
|
31
31
|
attr_reader :save_and_open_page_path
|
32
|
+
attr_accessor :exact_text
|
32
33
|
attr_accessor :app
|
33
34
|
|
34
35
|
##
|
@@ -244,7 +245,7 @@ module Capybara
|
|
244
245
|
# manually.
|
245
246
|
#
|
246
247
|
# @param [Rack Application] app The rack application to run
|
247
|
-
# @param [
|
248
|
+
# @param [Integer] port The port to run the application on
|
248
249
|
#
|
249
250
|
def run_default_server(app, port)
|
250
251
|
servers[:webrick].call(app, port, server_host)
|
@@ -368,7 +369,7 @@ module Capybara
|
|
368
369
|
def HTML(html)
|
369
370
|
Nokogiri::HTML(html).tap do |document|
|
370
371
|
document.xpath('//textarea').each do |textarea|
|
371
|
-
textarea
|
372
|
+
textarea['_capybara_raw_value'] = textarea.content.sub(/\A\n/,'')
|
372
373
|
end
|
373
374
|
end
|
374
375
|
end
|
@@ -495,6 +496,7 @@ Capybara.configure do |config|
|
|
495
496
|
config.automatic_reload = true
|
496
497
|
config.match = :smart
|
497
498
|
config.exact = false
|
499
|
+
config.exact_text = false
|
498
500
|
config.raise_server_errors = true
|
499
501
|
config.server_errors = [StandardError]
|
500
502
|
config.visible_text_only = false
|
data/lib/capybara/driver/base.rb
CHANGED
@@ -28,11 +28,11 @@ class Capybara::Driver::Base
|
|
28
28
|
raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#go_forward'
|
29
29
|
end
|
30
30
|
|
31
|
-
def execute_script(script)
|
31
|
+
def execute_script(script, *args)
|
32
32
|
raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#execute_script'
|
33
33
|
end
|
34
34
|
|
35
|
-
def evaluate_script(script)
|
35
|
+
def evaluate_script(script, *args)
|
36
36
|
raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#evaluate_script'
|
37
37
|
end
|
38
38
|
|
data/lib/capybara/helpers.rb
CHANGED
@@ -28,8 +28,14 @@ module Capybara
|
|
28
28
|
# @param [String] text Text to escape
|
29
29
|
# @return [String] Escaped text
|
30
30
|
#
|
31
|
-
def to_regexp(text,
|
32
|
-
text.is_a?(Regexp)
|
31
|
+
def to_regexp(text, regexp_options=nil, exact=false)
|
32
|
+
if text.is_a?(Regexp)
|
33
|
+
text
|
34
|
+
else
|
35
|
+
escaped = Regexp.escape(normalize_whitespace(text))
|
36
|
+
escaped = "\\A#{escaped}\\z" if exact
|
37
|
+
Regexp.new(escaped, regexp_options)
|
38
|
+
end
|
33
39
|
end
|
34
40
|
|
35
41
|
##
|
@@ -75,6 +75,7 @@ module Capybara
|
|
75
75
|
# @macro waiting_behavior
|
76
76
|
# @option options [String] :with The value to fill in - required
|
77
77
|
# @option options [Hash] :fill_options Driver specific options regarding how to fill fields
|
78
|
+
# @option options [String] :currently_with The current value property of the field to fill in
|
78
79
|
# @option options [Boolean] :multiple Match fields that can have multiple values?
|
79
80
|
# @option options [String] :id Match fields that match the id attribute
|
80
81
|
# @option options [String] :name Match fields that match the name attribute
|
@@ -87,6 +88,7 @@ module Capybara
|
|
87
88
|
raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
|
88
89
|
with = options.delete(:with)
|
89
90
|
fill_options = options.delete(:fill_options)
|
91
|
+
options[:with] = options.delete(:currently_with) if options.has_key?(:currently_with)
|
90
92
|
find(:fillable_field, locator, options).set(with, fill_options)
|
91
93
|
end
|
92
94
|
|
@@ -228,6 +230,7 @@ module Capybara
|
|
228
230
|
# @option options [String] id Match fields that match the id attribute
|
229
231
|
# @option options [String] name Match fields that match the name attribute
|
230
232
|
# @option options [String, Array<String>] :class Match links that match the class(es) provided
|
233
|
+
# @option options [true, Hash] make_visible A Hash of CSS styles to change before attempting to attach the file, if `true` { opacity: 1, display: 'block', visibility: 'visible' } is used (may not be supported by all drivers)
|
231
234
|
#
|
232
235
|
# @return [Capybara::Node::Element] The file field element
|
233
236
|
def attach_file(locator, path, options={})
|
@@ -235,10 +238,58 @@ module Capybara
|
|
235
238
|
Array(path).each do |p|
|
236
239
|
raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
|
237
240
|
end
|
238
|
-
|
241
|
+
# Allow user to update the CSS style of the file input since they are so often hidden on a page
|
242
|
+
if style = options.delete(:make_visible)
|
243
|
+
style = { opacity: 1, display: 'block', visibility: 'visible' } if style == true
|
244
|
+
ff = find(:file_field, locator, options.merge({visible: :all}))
|
245
|
+
_update_style(ff, style)
|
246
|
+
if ff.visible?
|
247
|
+
begin
|
248
|
+
ff.set(path)
|
249
|
+
ensure
|
250
|
+
_reset_style(ff)
|
251
|
+
end
|
252
|
+
else
|
253
|
+
raise ExpectationNotMet, "The style changes in :make_visible did not make the file input visible"
|
254
|
+
end
|
255
|
+
else
|
256
|
+
find(:file_field, locator, options).set(path)
|
257
|
+
end
|
239
258
|
end
|
240
259
|
|
241
260
|
private
|
261
|
+
def _update_style(element, style)
|
262
|
+
script = <<-JS
|
263
|
+
var el = arguments[0];
|
264
|
+
el.capybara_style_cache = el.style.cssText;
|
265
|
+
var css = arguments[1];
|
266
|
+
for (var prop in css){
|
267
|
+
if (css.hasOwnProperty(prop)) {
|
268
|
+
el.style[prop] = css[prop]
|
269
|
+
}
|
270
|
+
}
|
271
|
+
JS
|
272
|
+
begin
|
273
|
+
session.execute_script(script, element, style)
|
274
|
+
rescue Capybara::NotSupportedByDriverError
|
275
|
+
warn "The :make_visible option is not supported by the current driver - ignoring"
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def _reset_style(element)
|
280
|
+
script = <<-JS
|
281
|
+
var el = arguments[0];
|
282
|
+
if (el.hasOwnProperty('capybara_style_cache')) {
|
283
|
+
el.style.cssText = el.capybara_style_cache;
|
284
|
+
delete el.capybara_style_cache;
|
285
|
+
}
|
286
|
+
JS
|
287
|
+
begin
|
288
|
+
session.execute_script(script, element)
|
289
|
+
rescue
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
242
293
|
|
243
294
|
def _check_with_label(selector, checked, locator, options)
|
244
295
|
locator, options = nil, locator if locator.is_a? Hash
|
@@ -11,6 +11,7 @@ module Capybara
|
|
11
11
|
# @overload $0(regexp, options = {})
|
12
12
|
# @param regexp [Regexp] The regexp that title should match to
|
13
13
|
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for title to eq/match given string/regexp argument
|
14
|
+
# @option options [Boolean] :exact (false) When passed a string should the match be exact or just substring
|
14
15
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
15
16
|
# @return [true]
|
16
17
|
#
|
@@ -89,7 +89,7 @@ module Capybara
|
|
89
89
|
#
|
90
90
|
# @macro waiting_behavior
|
91
91
|
#
|
92
|
-
# @option options [String,Regexp] href Value to match against the links href
|
92
|
+
# @option options [String,Regexp,nil] href Value to match against the links href, if nil finds link placeholders (<a> elements with no href attribute)
|
93
93
|
# @option options [String] id Match links with the id provided
|
94
94
|
# @option options [String] title Match links with the title provided
|
95
95
|
# @option options [String] alt Match links with a contained img element whose alt matches
|
@@ -188,6 +188,7 @@ module Capybara
|
|
188
188
|
# @param [Symbol] kind Optional selector type (:css, :xpath, :field, etc.) - Defaults to Capybara.default_selector
|
189
189
|
# @param [String] locator The selector
|
190
190
|
# @option options [String, Regexp] text Only find elements which contain this text or match this regexp
|
191
|
+
# @option options [String, Boolean] exact_text (Capybara.exact_text) When String the string the elements contained text must match exactly, when Boolean controls whether the :text option must match exactly
|
191
192
|
# @option options [Boolean, Symbol] visible Only find elements with the specified visibility:
|
192
193
|
# * true - only finds visible elements.
|
193
194
|
# * false - finds invisible _and_ visible elements.
|
@@ -97,6 +97,58 @@ module Capybara
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
+
# Asserts that all of the provided selectors are present on the given page
|
101
|
+
# or descendants of the current node. If options are provided, the assertion
|
102
|
+
# will check that each locator is present with those options as well (other than :wait).
|
103
|
+
#
|
104
|
+
# page.assert_all_of_selectors(:custom, 'Tom', 'Joe', visible: all)
|
105
|
+
# page.assert_all_of_selectors(:css, '#my_div', 'a.not_clicked')
|
106
|
+
#
|
107
|
+
# It accepts all options that {Capybara::Node::Finders#all} accepts,
|
108
|
+
# such as :text and :visible.
|
109
|
+
#
|
110
|
+
# The :wait option applies to all of the selectors as a group, so all of the locators must be present
|
111
|
+
# within :wait (Defaults to Capybara.default_max_wait_time) seconds.
|
112
|
+
#
|
113
|
+
# @overload assert_all_of_selectors([kind = Capybara.default_selector], *locators, options = {})
|
114
|
+
#
|
115
|
+
def assert_all_of_selectors(*args, &optional_filter_block)
|
116
|
+
options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
117
|
+
selector = if args.first.is_a?(Symbol) then args.shift else Capybara.default_selector end
|
118
|
+
wait = options.fetch(:wait, Capybara.default_max_wait_time)
|
119
|
+
synchronize(wait) do
|
120
|
+
args.each do |locator|
|
121
|
+
assert_selector(selector, locator, options, &optional_filter_block)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Asserts that none of the provided selectors are present on the given page
|
127
|
+
# or descendants of the current node. If options are provided, the assertion
|
128
|
+
# will check that each locator is present with those options as well (other than :wait).
|
129
|
+
#
|
130
|
+
# page.assert_none_of_selectors(:custom, 'Tom', 'Joe', visible: all)
|
131
|
+
# page.assert_none_of_selectors(:css, '#my_div', 'a.not_clicked')
|
132
|
+
#
|
133
|
+
# It accepts all options that {Capybara::Node::Finders#all} accepts,
|
134
|
+
# such as :text and :visible.
|
135
|
+
#
|
136
|
+
# The :wait option applies to all of the selectors as a group, so none of the locators must be present
|
137
|
+
# within :wait (Defaults to Capybara.default_max_wait_time) seconds.
|
138
|
+
#
|
139
|
+
# @overload assert_none_of_selectors([kind = Capybara.default_selector], *locators, options = {})
|
140
|
+
#
|
141
|
+
def assert_none_of_selectors(*args, &optional_filter_block)
|
142
|
+
options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
143
|
+
selector = if args.first.is_a?(Symbol) then args.shift else Capybara.default_selector end
|
144
|
+
wait = options.fetch(:wait, Capybara.default_max_wait_time)
|
145
|
+
synchronize(wait) do
|
146
|
+
args.each do |locator|
|
147
|
+
assert_no_selector(selector, locator, options, &optional_filter_block)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
100
152
|
##
|
101
153
|
#
|
102
154
|
# Asserts that a given selector is not on the page or a descendant of the current node.
|
@@ -546,6 +598,7 @@ module Capybara
|
|
546
598
|
# @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
|
547
599
|
# @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
|
548
600
|
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for text to eq/match given string/regexp argument
|
601
|
+
# @option options [Boolean] :exact (Capybara.exact_text) Whether text must be an exact match or just substring
|
549
602
|
# @overload $0(text, options = {})
|
550
603
|
# @param [String, Regexp] text The string/regexp to check for. If it's a string, text is expected to include it. If it's a regexp, text is expected to match it.
|
551
604
|
# @option options [Integer] :count (nil) Number of times the text is expected to occur
|
@@ -553,6 +606,7 @@ module Capybara
|
|
553
606
|
# @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
|
554
607
|
# @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
|
555
608
|
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for text to eq/match given string/regexp argument
|
609
|
+
# @option options [Boolean] :exact (Capybara.exact_text) Whether text must be an exact match or just substring
|
556
610
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
557
611
|
# @return [true]
|
558
612
|
#
|
data/lib/capybara/node/simple.rb
CHANGED
@@ -76,7 +76,7 @@ module Capybara
|
|
76
76
|
#
|
77
77
|
def value
|
78
78
|
if tag_name == 'textarea'
|
79
|
-
native
|
79
|
+
native['_capybara_raw_value']
|
80
80
|
elsif tag_name == 'select'
|
81
81
|
if native['multiple'] == 'multiple'
|
82
82
|
native.xpath(".//option[@selected='selected']").map { |option| option[:value] || option.content }
|
@@ -17,10 +17,12 @@ module Capybara
|
|
17
17
|
@actual_path = if options[:url]
|
18
18
|
session.current_url
|
19
19
|
else
|
20
|
+
uri = ::Addressable::URI.parse(session.current_url)
|
21
|
+
|
20
22
|
if options[:only_path]
|
21
|
-
|
23
|
+
uri.path unless uri.nil? # Ensure the parsed url isn't nil.
|
22
24
|
else
|
23
|
-
|
25
|
+
uri.request_uri unless uri.nil? # Ensure the parsed url isn't nil.
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
@@ -4,7 +4,7 @@ module Capybara
|
|
4
4
|
class SelectorQuery < Queries::BaseQuery
|
5
5
|
attr_accessor :selector, :locator, :options, :expression, :find, :negative
|
6
6
|
|
7
|
-
VALID_KEYS = COUNT_KEYS + [:text, :id, :class, :visible, :exact, :match, :wait, :filter_set]
|
7
|
+
VALID_KEYS = COUNT_KEYS + [:text, :id, :class, :visible, :exact, :exact_text, :match, :wait, :filter_set]
|
8
8
|
VALID_MATCH = [:first, :smart, :prefer_exact, :one]
|
9
9
|
|
10
10
|
def initialize(*args, &filter_block)
|
@@ -42,7 +42,8 @@ module Capybara
|
|
42
42
|
|
43
43
|
def description
|
44
44
|
@description = String.new("#{label} #{locator.inspect}")
|
45
|
-
@description << " with text #{options[:text].inspect}" if options[:text]
|
45
|
+
@description << " with#{" exact" if exact_text === true} text #{options[:text].inspect}" if options[:text]
|
46
|
+
@description << " with exact text #{options[:exact_text]}" if options[:exact_text].is_a?(String)
|
46
47
|
@description << " with id #{options[:id]}" if options[:id]
|
47
48
|
@description << " with classes #{Array(options[:class]).join(',')}]" if options[:class]
|
48
49
|
@description << selector.description(options)
|
@@ -52,7 +53,22 @@ module Capybara
|
|
52
53
|
|
53
54
|
def matches_filters?(node)
|
54
55
|
if options[:text]
|
55
|
-
regexp = options[:text].is_a?(Regexp)
|
56
|
+
regexp = if options[:text].is_a?(Regexp)
|
57
|
+
options[:text]
|
58
|
+
else
|
59
|
+
if exact_text === true
|
60
|
+
"\\A#{Regexp.escape(options[:text].to_s)}\\z"
|
61
|
+
else
|
62
|
+
Regexp.escape(options[:text].to_s)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
text_visible = visible
|
66
|
+
text_visible = :all if text_visible == :hidden
|
67
|
+
return false if not node.text(text_visible).match(regexp)
|
68
|
+
end
|
69
|
+
|
70
|
+
if exact_text.is_a?(String)
|
71
|
+
regexp = "\\A#{Regexp.escape(options[:exact_text])}\\z"
|
56
72
|
text_visible = visible
|
57
73
|
text_visible = :all if text_visible == :hidden
|
58
74
|
return false if not node.text(text_visible).match(regexp)
|
@@ -187,6 +203,10 @@ module Capybara
|
|
187
203
|
warn "The :exact option only has an effect on queries using the XPath#is method. Using it with the query \"#{expression.to_s}\" has no effect."
|
188
204
|
end
|
189
205
|
end
|
206
|
+
|
207
|
+
def exact_text
|
208
|
+
exact_text = options.fetch(:exact_text, Capybara.exact_text)
|
209
|
+
end
|
190
210
|
end
|
191
211
|
end
|
192
212
|
end
|
@@ -10,8 +10,8 @@ module Capybara
|
|
10
10
|
unless @expected_text.is_a?(Regexp)
|
11
11
|
@expected_text = Capybara::Helpers.normalize_whitespace(@expected_text)
|
12
12
|
end
|
13
|
-
@search_regexp = Capybara::Helpers.to_regexp(@expected_text)
|
14
13
|
@options ||= {}
|
14
|
+
@search_regexp = Capybara::Helpers.to_regexp(@expected_text, nil, exact?)
|
15
15
|
assert_valid_keys
|
16
16
|
end
|
17
17
|
|
@@ -33,12 +33,16 @@ module Capybara
|
|
33
33
|
if @expected_text.is_a?(Regexp)
|
34
34
|
"text matching #{@expected_text.inspect}"
|
35
35
|
else
|
36
|
-
"text #{@expected_text.inspect}"
|
36
|
+
"#{"exact " if exact?}text #{@expected_text.inspect}"
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
41
41
|
|
42
|
+
def exact?
|
43
|
+
options.fetch(:exact, Capybara.exact_text)
|
44
|
+
end
|
45
|
+
|
42
46
|
def build_message(report_on_invisible)
|
43
47
|
message = String.new()
|
44
48
|
unless (COUNT_KEYS & @options.keys).empty?
|
@@ -57,10 +61,14 @@ module Capybara
|
|
57
61
|
end
|
58
62
|
|
59
63
|
if @node and check_visible_text? and report_on_invisible
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
+
begin
|
65
|
+
invisible_text = text(@node, :all)
|
66
|
+
invisible_count = invisible_text.scan(@search_regexp).size
|
67
|
+
if invisible_count != @count
|
68
|
+
details_message << ". it was found #{invisible_count} #{Capybara::Helpers.declension("time", "times", invisible_count)} including non-visible text"
|
69
|
+
end
|
70
|
+
rescue
|
71
|
+
# An error getting the non-visible text (if element goes out of scope) should not affect the response
|
64
72
|
end
|
65
73
|
end
|
66
74
|
|
@@ -70,7 +78,7 @@ module Capybara
|
|
70
78
|
end
|
71
79
|
|
72
80
|
def valid_keys
|
73
|
-
COUNT_KEYS + [:wait]
|
81
|
+
COUNT_KEYS + [:wait, :exact]
|
74
82
|
end
|
75
83
|
|
76
84
|
def check_visible_text?
|