capybara 3.23.0 → 3.35.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +264 -11
- data/README.md +10 -6
- data/lib/capybara.rb +20 -8
- data/lib/capybara/config.rb +10 -8
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +4 -0
- data/lib/capybara/driver/node.rb +4 -0
- data/lib/capybara/dsl.rb +10 -2
- data/lib/capybara/helpers.rb +28 -2
- data/lib/capybara/minitest.rb +232 -144
- data/lib/capybara/minitest/spec.rb +156 -97
- data/lib/capybara/node/actions.rb +36 -36
- data/lib/capybara/node/base.rb +6 -6
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +3 -3
- data/lib/capybara/node/element.rb +77 -33
- data/lib/capybara/node/finders.rb +24 -17
- data/lib/capybara/node/matchers.rb +79 -64
- data/lib/capybara/node/simple.rb +11 -4
- data/lib/capybara/queries/ancestor_query.rb +6 -10
- 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 +259 -23
- data/lib/capybara/queries/sibling_query.rb +5 -11
- data/lib/capybara/queries/style_query.rb +1 -1
- data/lib/capybara/queries/text_query.rb +13 -1
- data/lib/capybara/rack_test/browser.rb +13 -4
- data/lib/capybara/rack_test/driver.rb +2 -1
- data/lib/capybara/rack_test/form.rb +2 -2
- data/lib/capybara/rack_test/node.rb +42 -6
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +18 -12
- data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
- data/lib/capybara/registrations/servers.rb +9 -2
- data/lib/capybara/result.rb +39 -19
- data/lib/capybara/rspec.rb +2 -0
- data/lib/capybara/rspec/matcher_proxies.rb +5 -5
- data/lib/capybara/rspec/matchers.rb +97 -74
- data/lib/capybara/rspec/matchers/base.rb +19 -6
- data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
- data/lib/capybara/rspec/matchers/have_ancestor.rb +5 -7
- data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +15 -10
- data/lib/capybara/rspec/matchers/have_sibling.rb +4 -7
- data/lib/capybara/rspec/matchers/have_text.rb +4 -7
- 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 +39 -0
- data/lib/capybara/selector.rb +46 -19
- data/lib/capybara/selector/builders/css_builder.rb +10 -6
- data/lib/capybara/selector/builders/xpath_builder.rb +4 -2
- data/lib/capybara/selector/css.rb +1 -1
- data/lib/capybara/selector/definition.rb +13 -11
- data/lib/capybara/selector/definition/button.rb +32 -15
- data/lib/capybara/selector/definition/checkbox.rb +2 -2
- data/lib/capybara/selector/definition/css.rb +3 -1
- data/lib/capybara/selector/definition/datalist_input.rb +2 -2
- data/lib/capybara/selector/definition/datalist_option.rb +1 -1
- data/lib/capybara/selector/definition/element.rb +3 -2
- data/lib/capybara/selector/definition/field.rb +1 -1
- data/lib/capybara/selector/definition/file_field.rb +1 -1
- data/lib/capybara/selector/definition/fillable_field.rb +2 -2
- data/lib/capybara/selector/definition/label.rb +5 -3
- data/lib/capybara/selector/definition/link.rb +8 -0
- data/lib/capybara/selector/definition/option.rb +1 -1
- data/lib/capybara/selector/definition/radio_button.rb +2 -2
- data/lib/capybara/selector/definition/select.rb +33 -14
- data/lib/capybara/selector/definition/table.rb +6 -3
- data/lib/capybara/selector/definition/table_row.rb +2 -2
- data/lib/capybara/selector/filter_set.rb +13 -11
- data/lib/capybara/selector/filters/base.rb +6 -1
- data/lib/capybara/selector/filters/locator_filter.rb +1 -1
- data/lib/capybara/selector/regexp_disassembler.rb +7 -0
- data/lib/capybara/selector/selector.rb +13 -3
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -1
- data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +10 -10
- data/lib/capybara/selenium/driver.rb +86 -24
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +24 -21
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +21 -19
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +17 -1
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +0 -4
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +37 -26
- data/lib/capybara/selenium/extensions/html5_drag.rb +55 -11
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +8 -10
- data/lib/capybara/selenium/logger_suppressor.rb +8 -2
- data/lib/capybara/selenium/node.rb +160 -40
- data/lib/capybara/selenium/nodes/chrome_node.rb +72 -12
- data/lib/capybara/selenium/nodes/edge_node.rb +32 -14
- data/lib/capybara/selenium/nodes/firefox_node.rb +28 -32
- data/lib/capybara/selenium/nodes/safari_node.rb +5 -29
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +4 -4
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +32 -7
- data/lib/capybara/server.rb +19 -3
- data/lib/capybara/server/animation_disabler.rb +8 -3
- data/lib/capybara/server/checker.rb +1 -1
- data/lib/capybara/server/middleware.rb +22 -10
- data/lib/capybara/session.rb +66 -40
- data/lib/capybara/session/config.rb +11 -3
- data/lib/capybara/session/matchers.rb +11 -11
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +75 -7
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
- data/lib/capybara/spec/session/all_spec.rb +60 -5
- data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
- data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
- data/lib/capybara/spec/session/check_spec.rb +6 -0
- data/lib/capybara/spec/session/click_button_spec.rb +16 -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 +55 -0
- data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -0
- data/lib/capybara/spec/session/has_button_spec.rb +51 -0
- data/lib/capybara/spec/session/has_css_spec.rb +26 -4
- data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
- data/lib/capybara/spec/session/has_field_spec.rb +34 -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_table_spec.rb +51 -5
- data/lib/capybara/spec/session/has_text_spec.rb +30 -0
- 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 +394 -9
- data/lib/capybara/spec/session/refresh_spec.rb +2 -1
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/save_page_spec.rb +4 -4
- data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -15
- data/lib/capybara/spec/session/selectors_spec.rb +16 -3
- 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 +14 -14
- data/lib/capybara/spec/test_app.rb +27 -21
- data/lib/capybara/spec/views/form.erb +47 -4
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/with_animation.erb +37 -1
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_html.erb +24 -2
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +4 -1
- data/lib/capybara/spec/views/with_jstree.erb +26 -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 +15 -14
- data/spec/capybara_spec.rb +28 -28
- data/spec/dsl_spec.rb +16 -3
- data/spec/filter_set_spec.rb +5 -5
- data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
- data/spec/minitest_spec.rb +3 -2
- data/spec/minitest_spec_spec.rb +46 -46
- data/spec/rack_test_spec.rb +38 -15
- data/spec/regexp_dissassembler_spec.rb +52 -38
- data/spec/result_spec.rb +43 -32
- data/spec/rspec/features_spec.rb +4 -1
- data/spec/rspec/scenarios_spec.rb +4 -0
- data/spec/rspec/shared_spec_matchers.rb +68 -56
- data/spec/rspec_spec.rb +9 -5
- data/spec/selector_spec.rb +32 -17
- data/spec/selenium_spec_chrome.rb +78 -11
- data/spec/selenium_spec_chrome_remote.rb +23 -6
- data/spec/selenium_spec_edge.rb +15 -12
- data/spec/selenium_spec_firefox.rb +24 -19
- data/spec/selenium_spec_firefox_remote.rb +0 -8
- data/spec/selenium_spec_ie.rb +1 -6
- data/spec/server_spec.rb +106 -44
- data/spec/session_spec.rb +5 -5
- data/spec/shared_selenium_node.rb +56 -2
- data/spec/shared_selenium_session.rb +122 -15
- data/spec/spec_helper.rb +2 -2
- metadata +63 -17
- data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -1,20 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'capybara/rspec/matchers/base'
|
4
|
-
require 'capybara/rspec/matchers/count_sugar'
|
5
4
|
|
6
5
|
module Capybara
|
7
6
|
module RSpecMatchers
|
8
7
|
module Matchers
|
9
|
-
class HaveSibling <
|
10
|
-
include CountSugar
|
11
|
-
|
8
|
+
class HaveSibling < CountableWrappedElementMatcher
|
12
9
|
def element_matches?(el)
|
13
|
-
el.assert_sibling(*@args, &@filter_block)
|
10
|
+
el.assert_sibling(*@args, **session_query_options, &@filter_block)
|
14
11
|
end
|
15
12
|
|
16
13
|
def element_does_not_match?(el)
|
17
|
-
el.assert_no_sibling(*@args, &@filter_block)
|
14
|
+
el.assert_no_sibling(*@args, **session_query_options, &@filter_block)
|
18
15
|
end
|
19
16
|
|
20
17
|
def description
|
@@ -22,7 +19,7 @@ module Capybara
|
|
22
19
|
end
|
23
20
|
|
24
21
|
def query
|
25
|
-
@query ||= Capybara::Queries::SiblingQuery.new(*session_query_args, &@filter_block)
|
22
|
+
@query ||= Capybara::Queries::SiblingQuery.new(*session_query_args, **session_query_options, &@filter_block)
|
26
23
|
end
|
27
24
|
end
|
28
25
|
end
|
@@ -1,24 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'capybara/rspec/matchers/base'
|
4
|
-
require 'capybara/rspec/matchers/count_sugar'
|
5
4
|
|
6
5
|
module Capybara
|
7
6
|
module RSpecMatchers
|
8
7
|
module Matchers
|
9
|
-
class HaveText <
|
10
|
-
include CountSugar
|
11
|
-
|
8
|
+
class HaveText < CountableWrappedElementMatcher
|
12
9
|
def element_matches?(el)
|
13
|
-
el.assert_text(*@args)
|
10
|
+
el.assert_text(*@args, **@kw_args)
|
14
11
|
end
|
15
12
|
|
16
13
|
def element_does_not_match?(el)
|
17
|
-
el.assert_no_text(*@args)
|
14
|
+
el.assert_no_text(*@args, **@kw_args)
|
18
15
|
end
|
19
16
|
|
20
17
|
def description
|
21
|
-
"text #{format(text)}"
|
18
|
+
"have text #{format(text)}"
|
22
19
|
end
|
23
20
|
|
24
21
|
def format(content)
|
@@ -7,11 +7,11 @@ module Capybara
|
|
7
7
|
module Matchers
|
8
8
|
class HaveTitle < WrappedElementMatcher
|
9
9
|
def element_matches?(el)
|
10
|
-
el.assert_title(*@args)
|
10
|
+
el.assert_title(*@args, **@kw_args)
|
11
11
|
end
|
12
12
|
|
13
13
|
def element_does_not_match?(el)
|
14
|
-
el.assert_no_title(*@args)
|
14
|
+
el.assert_no_title(*@args, **@kw_args)
|
15
15
|
end
|
16
16
|
|
17
17
|
def description
|
@@ -7,11 +7,11 @@ module Capybara
|
|
7
7
|
module Matchers
|
8
8
|
class MatchSelector < HaveSelector
|
9
9
|
def element_matches?(el)
|
10
|
-
el.assert_matches_selector(*@args, &@filter_block)
|
10
|
+
el.assert_matches_selector(*@args, **session_query_options, &@filter_block)
|
11
11
|
end
|
12
12
|
|
13
13
|
def element_does_not_match?(el)
|
14
|
-
el.assert_not_matches_selector(*@args, &@filter_block)
|
14
|
+
el.assert_not_matches_selector(*@args, **session_query_options, &@filter_block)
|
15
15
|
end
|
16
16
|
|
17
17
|
def description
|
@@ -19,7 +19,7 @@ module Capybara
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def query
|
22
|
-
@query ||= Capybara::Queries::MatchQuery.new(*session_query_args, &@filter_block)
|
22
|
+
@query ||= Capybara::Queries::MatchQuery.new(*session_query_args, **session_query_options, &@filter_block)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -6,8 +6,13 @@ module Capybara
|
|
6
6
|
module RSpecMatchers
|
7
7
|
module Matchers
|
8
8
|
class MatchStyle < WrappedElementMatcher
|
9
|
+
def initialize(styles = nil, **kw_args, &filter_block)
|
10
|
+
styles, kw_args = kw_args, {} if styles.nil?
|
11
|
+
super(styles, **kw_args, &filter_block)
|
12
|
+
end
|
13
|
+
|
9
14
|
def element_matches?(el)
|
10
|
-
el.assert_matches_style(*@args)
|
15
|
+
el.assert_matches_style(*@args, **@kw_args)
|
11
16
|
end
|
12
17
|
|
13
18
|
def does_not_match?(_actual)
|
@@ -28,7 +33,7 @@ module Capybara
|
|
28
33
|
##
|
29
34
|
# @deprecated
|
30
35
|
class HaveStyle < MatchStyle
|
31
|
-
def initialize(*args, &filter_block)
|
36
|
+
def initialize(*args, **kw_args, &filter_block)
|
32
37
|
warn 'HaveStyle matcher is deprecated, please use the MatchStyle matcher instead'
|
33
38
|
super
|
34
39
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
module RSpecMatchers
|
5
|
+
module SpatialSugar
|
6
|
+
def above(el)
|
7
|
+
options[:above] = el
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def below(el)
|
12
|
+
options[:below] = el
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def left_of(el)
|
17
|
+
options[:left_of] = el
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def right_of(el)
|
22
|
+
options[:right_of] = el
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def near(el)
|
27
|
+
options[:near] = el
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def options
|
34
|
+
# (@args.last.is_a?(Hash) ? @args : @args.push({})).last
|
35
|
+
@kw_args
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/capybara/selector.rb
CHANGED
@@ -7,8 +7,13 @@ require 'capybara/selector/definition'
|
|
7
7
|
#
|
8
8
|
# All Selectors below support the listed selector specific filters in addition to the following system-wide filters
|
9
9
|
# * :id (String, Regexp, XPath::Expression) - Matches the id attribute
|
10
|
-
# * :class (String, Array<String>, Regexp, XPath::Expression) - Matches the class(es) provided
|
10
|
+
# * :class (String, Array<String | Regexp>, Regexp, XPath::Expression) - Matches the class(es) provided
|
11
11
|
# * :style (String, Regexp, Hash<String, String>) - Match on elements style
|
12
|
+
# * :above (Element) - Match elements above the passed element on the page
|
13
|
+
# * :below (Element) - Match elements below the passed element on the page
|
14
|
+
# * :left_of (Element) - Match elements left of the passed element on the page
|
15
|
+
# * :right_of (Element) - Match elements right of the passed element on the page
|
16
|
+
# * :near (Element) - Match elements near (within 50px) the passed element on the page
|
12
17
|
#
|
13
18
|
# ### Built-in Selectors
|
14
19
|
#
|
@@ -25,8 +30,8 @@ require 'capybara/selector/definition'
|
|
25
30
|
# * Locator: Matches against the id, {Capybara.configure test_id} attribute, name, placeholder, or
|
26
31
|
# associated label text
|
27
32
|
# * Filters:
|
28
|
-
# * :name (String) - Matches the name attribute
|
29
|
-
# * :placeholder (String) - Matches the placeholder attribute
|
33
|
+
# * :name (String, Regexp) - Matches the name attribute
|
34
|
+
# * :placeholder (String, Regexp) - Matches the placeholder attribute
|
30
35
|
# * :type (String) - Matches the type attribute of the field or element type for 'textarea' and 'select'
|
31
36
|
# * :readonly (Boolean) - Match on the element being readonly
|
32
37
|
# * :with (String, Regexp) - Matches the current value of the field
|
@@ -34,6 +39,8 @@ require 'capybara/selector/definition'
|
|
34
39
|
# * :unchecked (Boolean) - Match unchecked fields?
|
35
40
|
# * :disabled (Boolean, :all) - Match disabled field? (Default: false)
|
36
41
|
# * :multiple (Boolean) - Match fields that accept multiple values
|
42
|
+
# * :valid (Boolean) - Match fields that are valid/invalid according to HTML5 form validation
|
43
|
+
# * :validation_message (String, Regexp) - Matches the elements current validationMessage
|
37
44
|
#
|
38
45
|
# * **:fieldset** - Select fieldset elements
|
39
46
|
# * Locator: Matches id, {Capybara.configure test_id}, or contents of wrapped legend
|
@@ -52,7 +59,7 @@ require 'capybara/selector/definition'
|
|
52
59
|
# * **:button** - Find buttons ( input [of type submit, reset, image, button] or button elements )
|
53
60
|
# * Locator: Matches the id, {Capybara.configure test_id} attribute, name, value, or title attributes, string content of a button, or the alt attribute of an image type button or of a descendant image of a button
|
54
61
|
# * Filters:
|
55
|
-
# * :name (String) - Matches the name attribute
|
62
|
+
# * :name (String, Regexp) - Matches the name attribute
|
56
63
|
# * :title (String) - Matches the title attribute
|
57
64
|
# * :value (String) - Matches the value of an input button
|
58
65
|
# * :type (String) - Matches the type attribute
|
@@ -66,17 +73,19 @@ require 'capybara/selector/definition'
|
|
66
73
|
# * **:fillable_field** - Find text fillable fields ( textarea, input [not of type submit, image, radio, checkbox, hidden, file] )
|
67
74
|
# * Locator: Matches against the id, {Capybara.configure test_id} attribute, name, placeholder, or associated label text
|
68
75
|
# * Filters:
|
69
|
-
# * :name (String) - Matches the name attribute
|
70
|
-
# * :placeholder (String) - Matches the placeholder attribute
|
76
|
+
# * :name (String, Regexp) - Matches the name attribute
|
77
|
+
# * :placeholder (String, Regexp) - Matches the placeholder attribute
|
71
78
|
# * :with (String, Regexp) - Matches the current value of the field
|
72
79
|
# * :type (String) - Matches the type attribute of the field or element type for 'textarea'
|
73
80
|
# * :disabled (Boolean, :all) - Match disabled field? (Default: false)
|
74
81
|
# * :multiple (Boolean) - Match fields that accept multiple values
|
82
|
+
# * :valid (Boolean) - Match fields that are valid/invalid according to HTML5 form validation
|
83
|
+
# * :validation_message (String, Regexp) - Matches the elements current validationMessage
|
75
84
|
#
|
76
85
|
# * **:radio_button** - Find radio buttons
|
77
86
|
# * Locator: Match id, {Capybara.configure test_id} attribute, name, or associated label text
|
78
87
|
# * Filters:
|
79
|
-
# * :name (String) - Matches the name attribute
|
88
|
+
# * :name (String, Regexp) - Matches the name attribute
|
80
89
|
# * :checked (Boolean) - Match checked fields?
|
81
90
|
# * :unchecked (Boolean) - Match unchecked fields?
|
82
91
|
# * :disabled (Boolean, :all) - Match disabled field? (Default: false)
|
@@ -86,21 +95,23 @@ require 'capybara/selector/definition'
|
|
86
95
|
# * **:checkbox** - Find checkboxes
|
87
96
|
# * Locator: Match id, {Capybara.configure test_id} attribute, name, or associated label text
|
88
97
|
# * Filters:
|
89
|
-
# * :name (String) - Matches the name attribute
|
98
|
+
# * :name (String, Regexp) - Matches the name attribute
|
90
99
|
# * :checked (Boolean) - Match checked fields?
|
91
100
|
# * :unchecked (Boolean) - Match unchecked fields?
|
92
101
|
# * :disabled (Boolean, :all) - Match disabled field? (Default: false)
|
93
|
-
# * :
|
94
|
-
# * :
|
102
|
+
# * :with (String, Regexp) - Match the current value
|
103
|
+
# * :option - Alias of :with
|
95
104
|
#
|
96
105
|
# * **:select** - Find select elements
|
97
106
|
# * Locator: Match id, {Capybara.configure test_id} attribute, name, placeholder, or associated label text
|
98
107
|
# * Filters:
|
99
|
-
# * :name (String) - Matches the name attribute
|
100
|
-
# * :placeholder (String) - Matches the placeholder attribute
|
108
|
+
# * :name (String, Regexp) - Matches the name attribute
|
109
|
+
# * :placeholder (String, Placeholder) - Matches the placeholder attribute
|
101
110
|
# * :disabled (Boolean, :all) - Match disabled field? (Default: false)
|
102
111
|
# * :multiple (Boolean) - Match fields that accept multiple values
|
103
112
|
# * :options (Array<String>) - Exact match options
|
113
|
+
# * :enabled_options (Array<String>) - Exact match enabled options
|
114
|
+
# * :disabled_options (Array<String>) - Exact match disabled options
|
104
115
|
# * :with_options (Array<String>) - Partial match options
|
105
116
|
# * :selected (String, Array<String>) - Match the selection(s)
|
106
117
|
# * :with_selected (String, Array<String>) - Partial match the selection(s)
|
@@ -115,8 +126,8 @@ require 'capybara/selector/definition'
|
|
115
126
|
# * Locator: Matches against the id, {Capybara.configure test_id} attribute, name,
|
116
127
|
# placeholder, or associated label text
|
117
128
|
# * Filters:
|
118
|
-
# * :name (String) - Matches the name attribute
|
119
|
-
# * :placeholder (String) - Matches the placeholder attribute
|
129
|
+
# * :name (String, Regexp) - Matches the name attribute
|
130
|
+
# * :placeholder (String, Regexp) - Matches the placeholder attribute
|
120
131
|
# * :disabled (Boolean, :all) - Match disabled field? (Default: false)
|
121
132
|
# * :options (Array<String>) - Exact match options
|
122
133
|
# * :with_options (Array<String>) - Partial match options
|
@@ -129,7 +140,7 @@ require 'capybara/selector/definition'
|
|
129
140
|
# * **:file_field** - Find file input elements
|
130
141
|
# * Locator: Match id, {Capybara.configure test_id} attribute, name, or associated label text
|
131
142
|
# * Filters:
|
132
|
-
# * :name (String) - Matches the name attribute
|
143
|
+
# * :name (String, Regexp) - Matches the name attribute
|
133
144
|
# * :disabled (Boolean, :all) - Match disabled field? (Default: false)
|
134
145
|
# * :multiple (Boolean) - Match field that accepts multiple values
|
135
146
|
#
|
@@ -160,15 +171,28 @@ require 'capybara/selector/definition'
|
|
160
171
|
# * Filters:
|
161
172
|
# * :\<any> (String, Regexp) - Match on any specified element attribute
|
162
173
|
#
|
163
|
-
class Capybara::Selector; end
|
174
|
+
class Capybara::Selector; end # rubocop:disable Lint/EmptyClass
|
164
175
|
|
165
176
|
Capybara::Selector::FilterSet.add(:_field) do
|
166
177
|
node_filter(:checked, :boolean) { |node, value| !(value ^ node.checked?) }
|
167
178
|
node_filter(:unchecked, :boolean) { |node, value| (value ^ node.checked?) }
|
168
179
|
node_filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| !(value ^ node.disabled?) }
|
180
|
+
node_filter(:valid, :boolean) { |node, value| node.evaluate_script('this.validity.valid') == value }
|
181
|
+
node_filter(:name) { |node, value| !value.is_a?(Regexp) || value.match?(node[:name]) }
|
182
|
+
node_filter(:placeholder) { |node, value| !value.is_a?(Regexp) || value.match?(node[:placeholder]) }
|
183
|
+
node_filter(:validation_message) do |node, msg|
|
184
|
+
vm = node[:validationMessage]
|
185
|
+
(msg.is_a?(Regexp) ? msg.match?(vm) : vm == msg.to_s).tap do |res|
|
186
|
+
add_error("Expected validation message to be #{msg.inspect} but was #{vm}") unless res
|
187
|
+
end
|
188
|
+
end
|
169
189
|
|
170
|
-
expression_filter(:name)
|
171
|
-
|
190
|
+
expression_filter(:name) do |xpath, val|
|
191
|
+
builder(xpath).add_attribute_conditions(name: val)
|
192
|
+
end
|
193
|
+
expression_filter(:placeholder) do |xpath, val|
|
194
|
+
builder(xpath).add_attribute_conditions(placeholder: val)
|
195
|
+
end
|
172
196
|
expression_filter(:disabled) { |xpath, val| val ? xpath : xpath[~XPath.attr(:disabled)] }
|
173
197
|
expression_filter(:multiple) { |xpath, val| xpath[val ? XPath.attr(:multiple) : ~XPath.attr(:multiple)] }
|
174
198
|
|
@@ -182,12 +206,15 @@ Capybara::Selector::FilterSet.add(:_field) do
|
|
182
206
|
desc
|
183
207
|
end
|
184
208
|
|
185
|
-
describe(:node_filters) do |checked: nil, unchecked: nil, disabled: nil, **|
|
209
|
+
describe(:node_filters) do |checked: nil, unchecked: nil, disabled: nil, valid: nil, validation_message: nil, **|
|
186
210
|
desc, states = +'', []
|
187
211
|
states << 'checked' if checked || (unchecked == false)
|
188
212
|
states << 'not checked' if unchecked || (checked == false)
|
189
213
|
states << 'disabled' if disabled == true
|
190
214
|
desc << " that is #{states.join(' and ')}" unless states.empty?
|
215
|
+
desc << ' that is valid' if valid == true
|
216
|
+
desc << ' that is invalid' if valid == false
|
217
|
+
desc << " with validation message #{validation_message.to_s.inspect}" if validation_message
|
191
218
|
desc
|
192
219
|
end
|
193
220
|
end
|
@@ -17,11 +17,7 @@ module Capybara
|
|
17
17
|
conditions = if name == :class
|
18
18
|
class_conditions(value)
|
19
19
|
elsif value.is_a? Regexp
|
20
|
-
|
21
|
-
strs.map do |str|
|
22
|
-
"[#{name}*='#{str}'#{' i' if value.casefold?}]"
|
23
|
-
end.join
|
24
|
-
end
|
20
|
+
regexp_conditions(name, value)
|
25
21
|
else
|
26
22
|
[attribute_conditions(name => value)]
|
27
23
|
end
|
@@ -36,6 +32,14 @@ module Capybara
|
|
36
32
|
|
37
33
|
private
|
38
34
|
|
35
|
+
def regexp_conditions(name, value)
|
36
|
+
Selector::RegexpDisassembler.new(value).alternated_substrings.map do |strs|
|
37
|
+
strs.map do |str|
|
38
|
+
"[#{name}*='#{str}'#{' i' if value.casefold?}]"
|
39
|
+
end.join
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
39
43
|
def attribute_conditions(attributes)
|
40
44
|
attributes.map do |attribute, value|
|
41
45
|
case value
|
@@ -70,7 +74,7 @@ module Capybara
|
|
70
74
|
end.join
|
71
75
|
end
|
72
76
|
else
|
73
|
-
cls = Array(classes).
|
77
|
+
cls = Array(classes).reject { |c| c.is_a? Regexp }.group_by { |cl| cl.match?(/^!(?!!!)/) }
|
74
78
|
[(cls[false].to_a.map { |cl| ".#{Capybara::Selector::CSS.escape(cl.sub(/^!!/, ''))}" } +
|
75
79
|
cls[true].to_a.map { |cl| ":not(.#{Capybara::Selector::CSS.escape(cl.slice(1..-1))})" }).join]
|
76
80
|
end
|
@@ -15,6 +15,8 @@ module Capybara
|
|
15
15
|
def add_attribute_conditions(**conditions)
|
16
16
|
@expression = conditions.inject(expression) do |xp, (name, value)|
|
17
17
|
conditions = name == :class ? class_conditions(value) : attribute_conditions(name => value)
|
18
|
+
return xp if conditions.nil?
|
19
|
+
|
18
20
|
if xp.is_a? XPath::Expression
|
19
21
|
xp[conditions]
|
20
22
|
else
|
@@ -47,8 +49,8 @@ module Capybara
|
|
47
49
|
when XPath::Expression, Regexp
|
48
50
|
attribute_conditions(class: classes)
|
49
51
|
else
|
50
|
-
Array(classes).map do |klass|
|
51
|
-
if klass.
|
52
|
+
Array(classes).reject { |c| c.is_a? Regexp }.map do |klass|
|
53
|
+
if klass.match?(/^!(?!!!)/)
|
52
54
|
!XPath.attr(:class).contains_word(klass.slice(1..-1))
|
53
55
|
else
|
54
56
|
XPath.attr(:class).contains_word(klass.sub(/^!!/, ''))
|
@@ -10,11 +10,12 @@ module Capybara
|
|
10
10
|
class Selector
|
11
11
|
class Definition
|
12
12
|
attr_reader :name, :expressions
|
13
|
+
|
13
14
|
extend Forwardable
|
14
15
|
|
15
16
|
def initialize(name, locator_type: nil, raw_locator: false, supports_exact: nil, &block)
|
16
17
|
@name = name
|
17
|
-
@filter_set = Capybara::Selector::FilterSet.add(name)
|
18
|
+
@filter_set = Capybara::Selector::FilterSet.add(name)
|
18
19
|
@match = nil
|
19
20
|
@label = nil
|
20
21
|
@failure_message = nil
|
@@ -82,7 +83,7 @@ module Capybara
|
|
82
83
|
# Automatic selector detection
|
83
84
|
#
|
84
85
|
# @yield [locator] This block takes the passed in locator string and returns whether or not it matches the selector
|
85
|
-
# @yieldparam [String], locator The locator string used to
|
86
|
+
# @yieldparam [String], locator The locator string used to determine if it matches the selector
|
86
87
|
# @yieldreturn [Boolean] Whether this selector matches the locator string
|
87
88
|
# @return [#call] The block that will be used to detect selector match
|
88
89
|
#
|
@@ -166,7 +167,7 @@ module Capybara
|
|
166
167
|
|
167
168
|
def locator_filter(*types, **options, &block)
|
168
169
|
types.each { |type| options[type] = true }
|
169
|
-
@locator_filter = Capybara::Selector::Filters::LocatorFilter.new(block, options) if block
|
170
|
+
@locator_filter = Capybara::Selector::Filters::LocatorFilter.new(block, **options) if block
|
170
171
|
@locator_filter
|
171
172
|
end
|
172
173
|
|
@@ -177,11 +178,11 @@ module Capybara
|
|
177
178
|
def_delegator :@filter_set, :describe
|
178
179
|
|
179
180
|
def describe_expression_filters(&block)
|
180
|
-
if
|
181
|
+
if block
|
181
182
|
describe(:expression_filters, &block)
|
182
183
|
else
|
183
184
|
describe(:expression_filters) do |**options|
|
184
|
-
describe_all_expression_filters(options)
|
185
|
+
describe_all_expression_filters(**options)
|
185
186
|
end
|
186
187
|
end
|
187
188
|
end
|
@@ -189,7 +190,7 @@ module Capybara
|
|
189
190
|
def describe_all_expression_filters(**opts)
|
190
191
|
expression_filters.map do |ef_name, ef|
|
191
192
|
if ef.matcher?
|
192
|
-
|
193
|
+
handled_custom_options(ef, opts).map { |option, value| " with #{ef_name}[#{option} => #{value}]" }.join
|
193
194
|
elsif opts.key?(ef_name)
|
194
195
|
" with #{ef_name} #{opts[ef_name]}"
|
195
196
|
end
|
@@ -214,7 +215,7 @@ module Capybara
|
|
214
215
|
end
|
215
216
|
|
216
217
|
def default_visibility(fallback = Capybara.ignore_hidden_elements, options = {})
|
217
|
-
vis = if @default_visibility
|
218
|
+
vis = if @default_visibility.respond_to?(:call)
|
218
219
|
@default_visibility.call(options)
|
219
220
|
else
|
220
221
|
@default_visibility
|
@@ -251,14 +252,15 @@ module Capybara
|
|
251
252
|
|
252
253
|
private
|
253
254
|
|
254
|
-
def
|
255
|
-
|
256
|
-
filter.handles_option?(
|
255
|
+
def handled_custom_options(filter, options)
|
256
|
+
options.select do |option, _|
|
257
|
+
filter.handles_option?(option) && !::Capybara::Queries::SelectorQuery::VALID_KEYS.include?(option)
|
257
258
|
end
|
258
259
|
end
|
259
260
|
|
260
261
|
def parameter_names(block)
|
261
|
-
|
262
|
+
key_types = %i[key keyreq]
|
263
|
+
block.parameters.select { |(type, _name)| key_types.include? type }.map { |(_type, name)| name }
|
262
264
|
end
|
263
265
|
|
264
266
|
def expression(type, allowed_filters, &block)
|