capybara 3.30.0 → 3.35.3
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 +153 -13
- data/README.md +9 -4
- data/lib/capybara.rb +18 -8
- data/lib/capybara/config.rb +4 -6
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +4 -0
- data/lib/capybara/dsl.rb +10 -2
- data/lib/capybara/helpers.rb +25 -1
- data/lib/capybara/minitest.rb +232 -144
- data/lib/capybara/minitest/spec.rb +156 -97
- data/lib/capybara/node/actions.rb +16 -21
- data/lib/capybara/node/base.rb +6 -6
- data/lib/capybara/node/element.rb +14 -13
- data/lib/capybara/node/finders.rb +12 -7
- data/lib/capybara/node/matchers.rb +36 -27
- data/lib/capybara/node/simple.rb +6 -2
- data/lib/capybara/queries/ancestor_query.rb +1 -1
- data/lib/capybara/queries/base_query.rb +2 -1
- data/lib/capybara/queries/current_path_query.rb +14 -4
- data/lib/capybara/queries/selector_query.rb +40 -18
- data/lib/capybara/queries/sibling_query.rb +1 -1
- data/lib/capybara/queries/style_query.rb +1 -1
- data/lib/capybara/queries/text_query.rb +7 -1
- data/lib/capybara/rack_test/browser.rb +9 -3
- data/lib/capybara/rack_test/driver.rb +1 -0
- data/lib/capybara/rack_test/form.rb +1 -1
- data/lib/capybara/rack_test/node.rb +35 -10
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +18 -12
- data/lib/capybara/registrations/patches/puma_ssl.rb +3 -1
- data/lib/capybara/registrations/servers.rb +3 -2
- data/lib/capybara/result.rb +35 -15
- data/lib/capybara/rspec.rb +2 -0
- data/lib/capybara/rspec/matcher_proxies.rb +5 -5
- data/lib/capybara/rspec/matchers.rb +33 -32
- data/lib/capybara/rspec/matchers/base.rb +12 -6
- data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
- data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
- data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +15 -7
- data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
- data/lib/capybara/rspec/matchers/have_text.rb +3 -3
- data/lib/capybara/rspec/matchers/have_title.rb +2 -2
- data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
- data/lib/capybara/rspec/matchers/match_style.rb +7 -2
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +2 -1
- data/lib/capybara/selector.rb +14 -3
- data/lib/capybara/selector/builders/css_builder.rb +1 -1
- data/lib/capybara/selector/builders/xpath_builder.rb +3 -1
- data/lib/capybara/selector/definition.rb +11 -9
- data/lib/capybara/selector/definition/button.rb +26 -14
- data/lib/capybara/selector/definition/css.rb +1 -1
- data/lib/capybara/selector/definition/datalist_input.rb +1 -1
- data/lib/capybara/selector/definition/element.rb +2 -1
- data/lib/capybara/selector/definition/fillable_field.rb +1 -1
- data/lib/capybara/selector/definition/label.rb +2 -2
- data/lib/capybara/selector/definition/link.rb +8 -0
- data/lib/capybara/selector/definition/select.rb +32 -13
- data/lib/capybara/selector/definition/table.rb +1 -1
- data/lib/capybara/selector/definition/table_row.rb +2 -2
- data/lib/capybara/selector/filter_set.rb +2 -2
- data/lib/capybara/selector/selector.rb +9 -1
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
- data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +1 -1
- data/lib/capybara/selenium/driver.rb +52 -7
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +10 -12
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -11
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +3 -3
- data/lib/capybara/selenium/extensions/find.rb +4 -4
- data/lib/capybara/selenium/extensions/html5_drag.rb +24 -8
- data/lib/capybara/selenium/extensions/scroll.rb +8 -10
- data/lib/capybara/selenium/logger_suppressor.rb +8 -2
- data/lib/capybara/selenium/node.rb +96 -16
- data/lib/capybara/selenium/nodes/chrome_node.rb +27 -16
- data/lib/capybara/selenium/nodes/edge_node.rb +1 -1
- data/lib/capybara/selenium/nodes/firefox_node.rb +9 -4
- data/lib/capybara/selenium/nodes/safari_node.rb +1 -1
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +4 -4
- data/lib/capybara/selenium/patches/logs.rb +7 -9
- data/lib/capybara/server/animation_disabler.rb +8 -3
- data/lib/capybara/server/middleware.rb +4 -2
- data/lib/capybara/session.rb +53 -29
- data/lib/capybara/session/config.rb +3 -1
- data/lib/capybara/session/matchers.rb +11 -11
- data/lib/capybara/spec/public/test.js +64 -7
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
- data/lib/capybara/spec/session/all_spec.rb +45 -5
- data/lib/capybara/spec/session/assert_text_spec.rb +5 -5
- data/lib/capybara/spec/session/check_spec.rb +6 -0
- data/lib/capybara/spec/session/click_button_spec.rb +11 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
- data/lib/capybara/spec/session/current_url_spec.rb +11 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
- data/lib/capybara/spec/session/find_spec.rb +11 -8
- data/lib/capybara/spec/session/has_button_spec.rb +51 -0
- data/lib/capybara/spec/session/has_css_spec.rb +14 -10
- data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
- data/lib/capybara/spec/session/has_field_spec.rb +16 -0
- data/lib/capybara/spec/session/has_select_spec.rb +32 -4
- data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
- data/lib/capybara/spec/session/has_text_spec.rb +5 -12
- data/lib/capybara/spec/session/html_spec.rb +1 -1
- data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
- data/lib/capybara/spec/session/node_spec.rb +169 -33
- data/lib/capybara/spec/session/refresh_spec.rb +2 -1
- data/lib/capybara/spec/session/save_page_spec.rb +4 -4
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_spec.rb +8 -8
- data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
- data/lib/capybara/spec/spec_helper.rb +13 -14
- data/lib/capybara/spec/test_app.rb +23 -21
- data/lib/capybara/spec/views/form.erb +36 -3
- data/lib/capybara/spec/views/with_animation.erb +8 -0
- data/lib/capybara/spec/views/with_dragula.erb +3 -1
- data/lib/capybara/spec/views/with_html.erb +2 -2
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +3 -0
- data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +3 -7
- data/spec/basic_node_spec.rb +9 -8
- data/spec/capybara_spec.rb +1 -1
- data/spec/dsl_spec.rb +14 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
- data/spec/minitest_spec.rb +3 -2
- data/spec/rack_test_spec.rb +28 -6
- data/spec/regexp_dissassembler_spec.rb +0 -4
- data/spec/result_spec.rb +40 -29
- data/spec/rspec/features_spec.rb +3 -1
- data/spec/rspec/scenarios_spec.rb +4 -0
- data/spec/rspec/shared_spec_matchers.rb +63 -51
- data/spec/rspec_spec.rb +4 -0
- data/spec/selector_spec.rb +17 -2
- data/spec/selenium_spec_chrome.rb +45 -21
- data/spec/selenium_spec_chrome_remote.rb +7 -1
- data/spec/selenium_spec_firefox.rb +15 -13
- data/spec/server_spec.rb +60 -49
- data/spec/shared_selenium_node.rb +18 -0
- data/spec/shared_selenium_session.rb +98 -7
- data/spec/spec_helper.rb +1 -1
- metadata +50 -14
- data/lib/capybara/spec/session/source_spec.rb +0 -0
|
@@ -24,12 +24,13 @@ module Capybara
|
|
|
24
24
|
# @option options [Boolean] normalize_ws
|
|
25
25
|
# Whether the `text`/`exact_text` options are compared against elment text with whitespace normalized or as returned by the driver.
|
|
26
26
|
# Defaults to {Capybara.configure default_normalize_ws}.
|
|
27
|
-
# @option options [Boolean, Symbol] visible
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
27
|
+
# @option options [Boolean, Symbol] visible
|
|
28
|
+
# Only find elements with the specified visibility. Defaults to behavior indicated by {Capybara.configure ignore_hidden_elements}.
|
|
29
|
+
# * true - only finds visible elements.
|
|
30
|
+
# * false - finds invisible _and_ visible elements.
|
|
31
|
+
# * :all - same as false; finds visible and invisible elements.
|
|
32
|
+
# * :hidden - only finds invisible elements.
|
|
33
|
+
# * :visible - same as true; only finds visible elements.
|
|
33
34
|
# @option options [Boolean] obscured Only find elements with the specified obscured state:
|
|
34
35
|
# * true - only find elements whose centerpoint is not in the viewport or is obscured by another non-descendant element.
|
|
35
36
|
# * false - only find elements whose centerpoint is in the viewport and is not obscured by other non-descendant elements.
|
|
@@ -235,13 +236,16 @@ module Capybara
|
|
|
235
236
|
# @option options [Integer] maximum Maximum number of matches that are expected to be found
|
|
236
237
|
# @option options [Integer] minimum Minimum number of matches that are expected to be found
|
|
237
238
|
# @option options [Range] between Number of matches found must be within the given range
|
|
239
|
+
# @option options [Boolean] allow_reload Beta feature - May be removed in any version.
|
|
240
|
+
# When `true` allows elements to be reloaded if they become stale. This is an advanced behavior and should only be used
|
|
241
|
+
# if you fully understand the potential ramifications. The results can be confusing on dynamic pages. Defaults to `false`
|
|
238
242
|
# @overload all([kind = Capybara.default_selector], locator = nil, **options)
|
|
239
243
|
# @overload all([kind = Capybara.default_selector], locator = nil, **options, &filter_block)
|
|
240
244
|
# @yieldparam element [Capybara::Node::Element] The element being considered for inclusion in the results
|
|
241
245
|
# @yieldreturn [Boolean] Should the element be considered in the results?
|
|
242
246
|
# @return [Capybara::Result] A collection of found elements
|
|
243
247
|
# @raise [Capybara::ExpectationNotMet] The number of elements found doesn't match the specified conditions
|
|
244
|
-
def all(*args, **options, &optional_filter_block)
|
|
248
|
+
def all(*args, allow_reload: false, **options, &optional_filter_block)
|
|
245
249
|
minimum_specified = options_include_minimum?(options)
|
|
246
250
|
options = { minimum: 1 }.merge(options) unless minimum_specified
|
|
247
251
|
options[:session_options] = session_options
|
|
@@ -250,6 +254,7 @@ module Capybara
|
|
|
250
254
|
begin
|
|
251
255
|
synchronize(query.wait) do
|
|
252
256
|
result = query.resolve_for(self)
|
|
257
|
+
result.allow_reload! if allow_reload
|
|
253
258
|
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
|
|
254
259
|
|
|
255
260
|
result
|
|
@@ -60,15 +60,16 @@ module Capybara
|
|
|
60
60
|
# @param styles [Hash]
|
|
61
61
|
# @return [Boolean] If the styles match
|
|
62
62
|
#
|
|
63
|
-
def matches_style?(styles, **options)
|
|
64
|
-
|
|
63
|
+
def matches_style?(styles = nil, **options)
|
|
64
|
+
styles, options = options, {} if styles.nil?
|
|
65
|
+
make_predicate(options) { assert_matches_style(styles, **options) }
|
|
65
66
|
end
|
|
66
67
|
|
|
67
68
|
##
|
|
68
69
|
# @deprecated Use {#matches_style?} instead.
|
|
69
70
|
#
|
|
70
|
-
def has_style?(styles, **options)
|
|
71
|
-
warn
|
|
71
|
+
def has_style?(styles = nil, **options)
|
|
72
|
+
Capybara::Helpers.warn "DEPRECATED: has_style? is deprecated, please use matches_style? : #{Capybara::Helpers.filter_backtrace(caller)}"
|
|
72
73
|
matches_style?(styles, **options)
|
|
73
74
|
end
|
|
74
75
|
|
|
@@ -122,9 +123,10 @@ module Capybara
|
|
|
122
123
|
# @param styles [Hash]
|
|
123
124
|
# @raise [Capybara::ExpectationNotMet] If the element doesn't have the specified styles
|
|
124
125
|
#
|
|
125
|
-
def assert_matches_style(styles, **options)
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
def assert_matches_style(styles = nil, **options)
|
|
127
|
+
styles, options = options, {} if styles.nil?
|
|
128
|
+
query_args, query_opts = _set_query_session_options(styles, options)
|
|
129
|
+
query = Capybara::Queries::StyleQuery.new(*query_args, **query_opts)
|
|
128
130
|
synchronize(query.wait) do
|
|
129
131
|
raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
|
|
130
132
|
end
|
|
@@ -134,7 +136,7 @@ module Capybara
|
|
|
134
136
|
##
|
|
135
137
|
# @deprecated Use {#assert_matches_style} instead.
|
|
136
138
|
#
|
|
137
|
-
def assert_style(styles, **options)
|
|
139
|
+
def assert_style(styles = nil, **options)
|
|
138
140
|
warn 'assert_style is deprecated, please use assert_matches_style instead'
|
|
139
141
|
assert_matches_style(styles, **options)
|
|
140
142
|
end
|
|
@@ -201,12 +203,10 @@ module Capybara
|
|
|
201
203
|
selector = extract_selector(args)
|
|
202
204
|
synchronize(wait) do
|
|
203
205
|
res = args.map do |locator|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
e.message
|
|
209
|
-
end
|
|
206
|
+
assert_selector(selector, locator, options, &optional_filter_block)
|
|
207
|
+
break nil
|
|
208
|
+
rescue Capybara::ExpectationNotMet => e
|
|
209
|
+
e.message
|
|
210
210
|
end
|
|
211
211
|
raise Capybara::ExpectationNotMet, res.join(' or ') if res
|
|
212
212
|
|
|
@@ -386,7 +386,7 @@ module Capybara
|
|
|
386
386
|
#
|
|
387
387
|
# page.has_field?('Email', type: 'email')
|
|
388
388
|
#
|
|
389
|
-
#
|
|
389
|
+
# NOTE: 'textarea' and 'select' are valid type values, matching the associated tag names.
|
|
390
390
|
#
|
|
391
391
|
# @param [String] locator The label, name or id of a field to check for
|
|
392
392
|
# @option options [String, Regexp] :with The text content of the field or a Regexp to match
|
|
@@ -672,8 +672,8 @@ module Capybara
|
|
|
672
672
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
|
673
673
|
# @return [true]
|
|
674
674
|
#
|
|
675
|
-
def assert_text(*args)
|
|
676
|
-
_verify_text(*args) do |count, query|
|
|
675
|
+
def assert_text(type_or_text, *args, **opts)
|
|
676
|
+
_verify_text(type_or_text, *args, **opts) do |count, query|
|
|
677
677
|
unless query.matches_count?(count) && (count.positive? || query.expects_none?)
|
|
678
678
|
raise Capybara::ExpectationNotMet, query.failure_message
|
|
679
679
|
end
|
|
@@ -688,8 +688,8 @@ module Capybara
|
|
|
688
688
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
|
689
689
|
# @return [true]
|
|
690
690
|
#
|
|
691
|
-
def assert_no_text(*args)
|
|
692
|
-
_verify_text(*args) do |count, query|
|
|
691
|
+
def assert_no_text(type_or_text, *args, **opts)
|
|
692
|
+
_verify_text(type_or_text, *args, **opts) do |count, query|
|
|
693
693
|
if query.matches_count?(count) && (count.positive? || query.expects_none?)
|
|
694
694
|
raise Capybara::ExpectationNotMet, query.negative_failure_message
|
|
695
695
|
end
|
|
@@ -711,7 +711,7 @@ module Capybara
|
|
|
711
711
|
# @return [Boolean] Whether it exists
|
|
712
712
|
#
|
|
713
713
|
def has_text?(*args, **options)
|
|
714
|
-
make_predicate(options) { assert_text(*args, options) }
|
|
714
|
+
make_predicate(options) { assert_text(*args, **options) }
|
|
715
715
|
end
|
|
716
716
|
alias_method :has_content?, :has_text?
|
|
717
717
|
|
|
@@ -723,7 +723,7 @@ module Capybara
|
|
|
723
723
|
# @return [Boolean] Whether it doesn't exist
|
|
724
724
|
#
|
|
725
725
|
def has_no_text?(*args, **options)
|
|
726
|
-
make_predicate(options) { assert_no_text(*args, options) }
|
|
726
|
+
make_predicate(options) { assert_no_text(*args, **options) }
|
|
727
727
|
end
|
|
728
728
|
alias_method :has_no_content?, :has_no_text?
|
|
729
729
|
|
|
@@ -832,8 +832,14 @@ module Capybara
|
|
|
832
832
|
end
|
|
833
833
|
|
|
834
834
|
def _verify_selector_result(query_args, optional_filter_block, query_type = Capybara::Queries::SelectorQuery)
|
|
835
|
-
query_args =
|
|
836
|
-
|
|
835
|
+
# query_args, query_opts = if query_args[0].is_a? Symbol
|
|
836
|
+
# a,o = _set_query_session_options(*query_args.slice(2..))
|
|
837
|
+
# [query_args.slice(0..1).concat(a), o]
|
|
838
|
+
# else
|
|
839
|
+
# _set_query_session_options(*query_args)
|
|
840
|
+
# end
|
|
841
|
+
query_args, query_opts = _set_query_session_options(*query_args)
|
|
842
|
+
query = query_type.new(*query_args, **query_opts, &optional_filter_block)
|
|
837
843
|
synchronize(query.wait) do
|
|
838
844
|
yield query.resolve_for(self), query
|
|
839
845
|
end
|
|
@@ -841,8 +847,8 @@ module Capybara
|
|
|
841
847
|
end
|
|
842
848
|
|
|
843
849
|
def _verify_match_result(query_args, optional_filter_block)
|
|
844
|
-
query_args = _set_query_session_options(*query_args)
|
|
845
|
-
query = Capybara::Queries::MatchQuery.new(*query_args, &optional_filter_block)
|
|
850
|
+
query_args, query_opts = _set_query_session_options(*query_args)
|
|
851
|
+
query = Capybara::Queries::MatchQuery.new(*query_args, **query_opts, &optional_filter_block)
|
|
846
852
|
synchronize(query.wait) do
|
|
847
853
|
yield query.resolve_for(parent || session&.document || query_scope)
|
|
848
854
|
end
|
|
@@ -858,9 +864,12 @@ module Capybara
|
|
|
858
864
|
true
|
|
859
865
|
end
|
|
860
866
|
|
|
861
|
-
def _set_query_session_options(*query_args
|
|
867
|
+
def _set_query_session_options(*query_args)
|
|
868
|
+
query_args, query_options = query_args.dup, {}
|
|
869
|
+
# query_options = query_args.pop if query_options.empty? && query_args.last.is_a?(Hash)
|
|
870
|
+
query_options = query_args.pop if query_args.last.is_a?(Hash)
|
|
862
871
|
query_options[:session_options] = session_options
|
|
863
|
-
query_args
|
|
872
|
+
[query_args, query_options]
|
|
864
873
|
end
|
|
865
874
|
|
|
866
875
|
def make_predicate(options)
|
data/lib/capybara/node/simple.rb
CHANGED
|
@@ -100,7 +100,7 @@ module Capybara
|
|
|
100
100
|
# @param [Boolean] check_ancestors Whether to inherit visibility from ancestors
|
|
101
101
|
# @return [Boolean] Whether the element is visible
|
|
102
102
|
#
|
|
103
|
-
def visible?(check_ancestors = true)
|
|
103
|
+
def visible?(check_ancestors = true) # rubocop:disable Style/OptionalBooleanParameter
|
|
104
104
|
return false if (tag_name == 'input') && (native[:type] == 'hidden')
|
|
105
105
|
return false if tag_name == 'template'
|
|
106
106
|
|
|
@@ -148,11 +148,15 @@ module Capybara
|
|
|
148
148
|
native.has_attribute?('multiple')
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
+
def readonly?
|
|
152
|
+
native.has_attribute?('readonly')
|
|
153
|
+
end
|
|
154
|
+
|
|
151
155
|
def synchronize(_seconds = nil)
|
|
152
156
|
yield # simple nodes don't need to wait
|
|
153
157
|
end
|
|
154
158
|
|
|
155
|
-
def allow_reload!
|
|
159
|
+
def allow_reload!(*)
|
|
156
160
|
# no op
|
|
157
161
|
end
|
|
158
162
|
|
|
@@ -16,7 +16,7 @@ module Capybara
|
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def description(applied = false)
|
|
19
|
+
def description(applied = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
20
20
|
child_query = @child_node&.instance_variable_get(:@query)
|
|
21
21
|
desc = super
|
|
22
22
|
desc += " that is an ancestor of #{child_query.description}" if child_query
|
|
@@ -79,7 +79,8 @@ module Capybara
|
|
|
79
79
|
if count
|
|
80
80
|
message << " #{occurrences count}"
|
|
81
81
|
elsif between
|
|
82
|
-
message << " between #{between.
|
|
82
|
+
message << " between #{between.begin ? between.first : 1} and" \
|
|
83
|
+
" #{between.end ? between.last : 'infinite'} times"
|
|
83
84
|
elsif maximum
|
|
84
85
|
message << " at most #{occurrences maximum}"
|
|
85
86
|
elsif minimum
|
|
@@ -6,26 +6,30 @@ module Capybara
|
|
|
6
6
|
# @api private
|
|
7
7
|
module Queries
|
|
8
8
|
class CurrentPathQuery < BaseQuery
|
|
9
|
-
def initialize(expected_path, **options)
|
|
9
|
+
def initialize(expected_path, **options, &optional_filter_block)
|
|
10
10
|
super(options)
|
|
11
11
|
@expected_path = expected_path
|
|
12
12
|
@options = {
|
|
13
13
|
url: !@expected_path.is_a?(Regexp) && !::Addressable::URI.parse(@expected_path || '').hostname.nil?,
|
|
14
14
|
ignore_query: false
|
|
15
15
|
}.merge(options)
|
|
16
|
+
@filter_block = optional_filter_block
|
|
16
17
|
assert_valid_keys
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def resolves_for?(session)
|
|
20
21
|
uri = ::Addressable::URI.parse(session.current_url)
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
@actual_path = (options[:ignore_query] ? uri&.omit(:query) : uri).yield_self do |u|
|
|
23
|
+
options[:url] ? u&.to_s : u&.request_uri
|
|
24
|
+
end
|
|
23
25
|
|
|
24
|
-
if @expected_path.is_a? Regexp
|
|
26
|
+
res = if @expected_path.is_a? Regexp
|
|
25
27
|
@actual_path.to_s.match?(@expected_path)
|
|
26
28
|
else
|
|
27
29
|
::Addressable::URI.parse(@expected_path) == ::Addressable::URI.parse(@actual_path)
|
|
28
30
|
end
|
|
31
|
+
|
|
32
|
+
res && matches_filter_block?(uri)
|
|
29
33
|
end
|
|
30
34
|
|
|
31
35
|
def failure_message
|
|
@@ -38,6 +42,12 @@ module Capybara
|
|
|
38
42
|
|
|
39
43
|
private
|
|
40
44
|
|
|
45
|
+
def matches_filter_block?(url)
|
|
46
|
+
return true unless @filter_block
|
|
47
|
+
|
|
48
|
+
@filter_block.call(url)
|
|
49
|
+
end
|
|
50
|
+
|
|
41
51
|
def failure_message_helper(negated = '')
|
|
42
52
|
verb = @expected_path.is_a?(Regexp) ? 'match' : 'equal'
|
|
43
53
|
"expected #{@actual_path.inspect}#{negated} to #{verb} #{@expected_path.inspect}"
|
|
@@ -6,6 +6,7 @@ module Capybara
|
|
|
6
6
|
module Queries
|
|
7
7
|
class SelectorQuery < Queries::BaseQuery
|
|
8
8
|
attr_reader :expression, :selector, :locator, :options
|
|
9
|
+
|
|
9
10
|
SPATIAL_KEYS = %i[above below left_of right_of near].freeze
|
|
10
11
|
VALID_KEYS = SPATIAL_KEYS + COUNT_KEYS +
|
|
11
12
|
%i[text id class style visible obscured exact exact_text normalize_ws match wait filter_set]
|
|
@@ -14,6 +15,7 @@ module Capybara
|
|
|
14
15
|
def initialize(*args,
|
|
15
16
|
session_options:,
|
|
16
17
|
enable_aria_label: session_options.enable_aria_label,
|
|
18
|
+
enable_aria_role: session_options.enable_aria_role,
|
|
17
19
|
test_id: session_options.test_id,
|
|
18
20
|
selector_format: nil,
|
|
19
21
|
order: nil,
|
|
@@ -30,7 +32,11 @@ module Capybara
|
|
|
30
32
|
|
|
31
33
|
@selector = Selector.new(
|
|
32
34
|
find_selector(args[0].is_a?(Symbol) ? args.shift : args[0]),
|
|
33
|
-
config: {
|
|
35
|
+
config: {
|
|
36
|
+
enable_aria_label: enable_aria_label,
|
|
37
|
+
enable_aria_role: enable_aria_role,
|
|
38
|
+
test_id: test_id
|
|
39
|
+
},
|
|
34
40
|
format: selector_format
|
|
35
41
|
)
|
|
36
42
|
|
|
@@ -49,7 +55,7 @@ module Capybara
|
|
|
49
55
|
def name; selector.name; end
|
|
50
56
|
def label; selector.label || selector.name; end
|
|
51
57
|
|
|
52
|
-
def description(only_applied = false)
|
|
58
|
+
def description(only_applied = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
53
59
|
desc = +''
|
|
54
60
|
show_for = show_for_stage(only_applied)
|
|
55
61
|
|
|
@@ -89,11 +95,9 @@ module Capybara
|
|
|
89
95
|
desc << ' that also matches the custom filter block' if @filter_block && show_for[:node]
|
|
90
96
|
|
|
91
97
|
desc << " within #{@resolved_node.inspect}" if describe_within?
|
|
92
|
-
if locator.is_a?(String) && locator.start_with?('#', './/', '//')
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
"Please see the documentation for acceptable locator values.\n\n"
|
|
96
|
-
end
|
|
98
|
+
if locator.is_a?(String) && locator.start_with?('#', './/', '//') && !selector.raw_locator?
|
|
99
|
+
desc << "\nNote: It appears you may be passing a CSS selector or XPath expression rather than a locator. " \
|
|
100
|
+
"Please see the documentation for acceptable locator values.\n\n"
|
|
97
101
|
end
|
|
98
102
|
desc
|
|
99
103
|
end
|
|
@@ -233,17 +237,18 @@ module Capybara
|
|
|
233
237
|
hints[:styles] = options[:style] if use_default_style_filter?
|
|
234
238
|
hints[:position] = true if use_spatial_filter?
|
|
235
239
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
else
|
|
240
|
+
case selector_format
|
|
241
|
+
when :css
|
|
242
|
+
if node.method(:find_css).arity == 1
|
|
240
243
|
node.find_css(css)
|
|
241
|
-
end
|
|
242
|
-
elsif selector_format == :xpath
|
|
243
|
-
if node.method(:find_xpath).arity != 1
|
|
244
|
-
node.find_xpath(xpath(exact), **hints)
|
|
245
244
|
else
|
|
245
|
+
node.find_css(css, **hints)
|
|
246
|
+
end
|
|
247
|
+
when :xpath
|
|
248
|
+
if node.method(:find_xpath).arity == 1
|
|
246
249
|
node.find_xpath(xpath(exact))
|
|
250
|
+
else
|
|
251
|
+
node.find_xpath(xpath(exact), **hints)
|
|
247
252
|
end
|
|
248
253
|
else
|
|
249
254
|
raise ArgumentError, "Unknown format: #{selector_format}"
|
|
@@ -477,9 +482,25 @@ module Capybara
|
|
|
477
482
|
end
|
|
478
483
|
|
|
479
484
|
def matches_class_filter?(node)
|
|
480
|
-
return true unless use_default_class_filter? &&
|
|
485
|
+
return true unless use_default_class_filter? && need_to_process_classes?
|
|
481
486
|
|
|
482
|
-
options[:class].
|
|
487
|
+
if options[:class].is_a? Regexp
|
|
488
|
+
options[:class].match? node[:class]
|
|
489
|
+
else
|
|
490
|
+
classes = (node[:class] || '').split
|
|
491
|
+
options[:class].select { |c| c.is_a? Regexp }.all? do |r|
|
|
492
|
+
classes.any? { |cls| r.match? cls }
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def need_to_process_classes?
|
|
498
|
+
case options[:class]
|
|
499
|
+
when Regexp then true
|
|
500
|
+
when Array then options[:class].any?(Regexp)
|
|
501
|
+
else
|
|
502
|
+
false
|
|
503
|
+
end
|
|
483
504
|
end
|
|
484
505
|
|
|
485
506
|
def matches_style_filter?(node)
|
|
@@ -575,6 +596,7 @@ module Capybara
|
|
|
575
596
|
|
|
576
597
|
class Rectangle
|
|
577
598
|
attr_reader :top, :bottom, :left, :right
|
|
599
|
+
|
|
578
600
|
def initialize(position)
|
|
579
601
|
# rubocop:disable Style/RescueModifier
|
|
580
602
|
@top = position['top'] rescue position['y']
|
|
@@ -645,7 +667,7 @@ module Capybara
|
|
|
645
667
|
|
|
646
668
|
d = u.dot w
|
|
647
669
|
e = v.dot w
|
|
648
|
-
cap_d = (a * c) - (b
|
|
670
|
+
cap_d = (a * c) - (b**2)
|
|
649
671
|
sD = tD = cap_d
|
|
650
672
|
|
|
651
673
|
# compute the line parameters of the two closest points
|
|
@@ -15,7 +15,7 @@ module Capybara
|
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def description(applied = false)
|
|
18
|
+
def description(applied = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
19
19
|
desc = super
|
|
20
20
|
sibling_query = @sibling_node&.instance_variable_get(:@query)
|
|
21
21
|
desc += " that is a sibling of #{sibling_query.description}" if sibling_query
|
|
@@ -6,13 +6,15 @@ module Capybara
|
|
|
6
6
|
class TextQuery < BaseQuery
|
|
7
7
|
def initialize(type = nil, expected_text, session_options:, **options) # rubocop:disable Style/OptionalArguments
|
|
8
8
|
@type = type.nil? ? default_type : type
|
|
9
|
+
raise ArgumentError, "#{@type} is not a valid type for a text query" unless valid_types.include?(@type)
|
|
10
|
+
|
|
9
11
|
@options = options
|
|
10
12
|
super(@options)
|
|
11
13
|
self.session_options = session_options
|
|
12
14
|
|
|
13
15
|
if expected_text.nil? && !exact?
|
|
14
16
|
warn 'Checking for expected text of nil is confusing and/or pointless since it will always match. '\
|
|
15
|
-
|
|
17
|
+
"Please specify a string or regexp instead. #{Capybara::Helpers.filter_backtrace(caller)}"
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
@expected_text = expected_text.is_a?(Regexp) ? expected_text : expected_text.to_s
|
|
@@ -89,6 +91,10 @@ module Capybara
|
|
|
89
91
|
COUNT_KEYS + %i[wait exact normalize_ws]
|
|
90
92
|
end
|
|
91
93
|
|
|
94
|
+
def valid_types
|
|
95
|
+
%i[all visible]
|
|
96
|
+
end
|
|
97
|
+
|
|
92
98
|
def check_visible_text?
|
|
93
99
|
@type == :visible
|
|
94
100
|
end
|