capybara 3.16.1 → 3.33.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/History.md +321 -0
- data/README.md +51 -60
- data/lib/capybara.rb +71 -114
- data/lib/capybara/config.rb +8 -5
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/node.rb +15 -3
- data/lib/capybara/dsl.rb +10 -2
- data/lib/capybara/helpers.rb +5 -3
- data/lib/capybara/minitest.rb +242 -141
- data/lib/capybara/minitest/spec.rb +159 -90
- data/lib/capybara/node/actions.rb +85 -74
- data/lib/capybara/node/base.rb +4 -4
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +3 -3
- data/lib/capybara/node/element.rb +216 -117
- data/lib/capybara/node/finders.rb +65 -65
- data/lib/capybara/node/matchers.rb +228 -126
- data/lib/capybara/node/simple.rb +9 -4
- data/lib/capybara/queries/ancestor_query.rb +5 -7
- data/lib/capybara/queries/base_query.rb +2 -1
- data/lib/capybara/queries/current_path_query.rb +1 -1
- data/lib/capybara/queries/selector_query.rb +296 -30
- data/lib/capybara/queries/sibling_query.rb +5 -4
- data/lib/capybara/queries/style_query.rb +2 -2
- data/lib/capybara/queries/text_query.rb +13 -1
- data/lib/capybara/queries/title_query.rb +1 -1
- data/lib/capybara/rack_test/browser.rb +7 -2
- data/lib/capybara/rack_test/driver.rb +1 -1
- data/lib/capybara/rack_test/form.rb +1 -1
- data/lib/capybara/rack_test/node.rb +43 -7
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +36 -0
- data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
- data/lib/capybara/registrations/servers.rb +44 -0
- data/lib/capybara/result.rb +36 -8
- data/lib/capybara/rspec/matcher_proxies.rb +6 -4
- data/lib/capybara/rspec/matchers.rb +100 -63
- data/lib/capybara/rspec/matchers/base.rb +23 -10
- data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
- data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
- data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +16 -8
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +4 -4
- 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 +2 -2
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/selector.rb +219 -588
- data/lib/capybara/selector/builders/css_builder.rb +10 -6
- data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
- data/lib/capybara/selector/css.rb +4 -2
- data/lib/capybara/selector/definition.rb +277 -0
- data/lib/capybara/selector/definition/button.rb +52 -0
- data/lib/capybara/selector/definition/checkbox.rb +26 -0
- data/lib/capybara/selector/definition/css.rb +10 -0
- data/lib/capybara/selector/definition/datalist_input.rb +35 -0
- data/lib/capybara/selector/definition/datalist_option.rb +25 -0
- data/lib/capybara/selector/definition/element.rb +27 -0
- data/lib/capybara/selector/definition/field.rb +40 -0
- data/lib/capybara/selector/definition/fieldset.rb +14 -0
- data/lib/capybara/selector/definition/file_field.rb +13 -0
- data/lib/capybara/selector/definition/fillable_field.rb +33 -0
- data/lib/capybara/selector/definition/frame.rb +17 -0
- data/lib/capybara/selector/definition/id.rb +6 -0
- data/lib/capybara/selector/definition/label.rb +62 -0
- data/lib/capybara/selector/definition/link.rb +54 -0
- data/lib/capybara/selector/definition/link_or_button.rb +16 -0
- data/lib/capybara/selector/definition/option.rb +27 -0
- data/lib/capybara/selector/definition/radio_button.rb +27 -0
- data/lib/capybara/selector/definition/select.rb +81 -0
- data/lib/capybara/selector/definition/table.rb +109 -0
- data/lib/capybara/selector/definition/table_row.rb +21 -0
- data/lib/capybara/selector/definition/xpath.rb +5 -0
- data/lib/capybara/selector/filter_set.rb +13 -9
- data/lib/capybara/selector/filters/base.rb +11 -2
- data/lib/capybara/selector/filters/locator_filter.rb +13 -3
- data/lib/capybara/selector/regexp_disassembler.rb +9 -2
- data/lib/capybara/selector/selector.rb +43 -448
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
- data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
- data/lib/capybara/selenium/driver.rb +125 -56
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +73 -17
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +41 -2
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +14 -1
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +14 -5
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +67 -45
- data/lib/capybara/selenium/extensions/html5_drag.rb +152 -36
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/logger_suppressor.rb +34 -0
- data/lib/capybara/selenium/node.rb +227 -56
- data/lib/capybara/selenium/nodes/chrome_node.rb +93 -8
- data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +37 -59
- data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
- data/lib/capybara/selenium/nodes/safari_node.rb +27 -54
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +18 -0
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +45 -0
- data/lib/capybara/server.rb +19 -3
- data/lib/capybara/server/animation_disabler.rb +2 -2
- data/lib/capybara/server/checker.rb +6 -2
- data/lib/capybara/server/middleware.rb +23 -13
- data/lib/capybara/session.rb +124 -106
- data/lib/capybara/session/config.rb +12 -10
- data/lib/capybara/session/matchers.rb +6 -6
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +94 -5
- data/lib/capybara/spec/session/all_spec.rb +84 -6
- data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
- data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
- data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
- data/lib/capybara/spec/session/attach_file_spec.rb +14 -6
- data/lib/capybara/spec/session/check_spec.rb +10 -4
- data/lib/capybara/spec/session/choose_spec.rb +8 -2
- data/lib/capybara/spec/session/click_button_spec.rb +44 -1
- data/lib/capybara/spec/session/click_link_spec.rb +11 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +12 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +37 -2
- data/lib/capybara/spec/session/find_spec.rb +60 -6
- data/lib/capybara/spec/session/first_spec.rb +1 -1
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +14 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +12 -1
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_button_spec.rb +16 -0
- data/lib/capybara/spec/session/has_css_spec.rb +35 -6
- data/lib/capybara/spec/session/has_current_path_spec.rb +6 -4
- 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_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +51 -5
- data/lib/capybara/spec/session/has_text_spec.rb +47 -0
- data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
- data/lib/capybara/spec/session/node_spec.rb +574 -16
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
- data/lib/capybara/spec/session/scroll_spec.rb +1 -1
- data/lib/capybara/spec/session/select_spec.rb +5 -10
- data/lib/capybara/spec/session/selectors_spec.rb +24 -3
- data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
- data/lib/capybara/spec/session/unselect_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_spec.rb +10 -9
- data/lib/capybara/spec/spec_helper.rb +7 -2
- data/lib/capybara/spec/test_app.rb +26 -21
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +25 -4
- data/lib/capybara/spec/views/frame_child.erb +2 -1
- data/lib/capybara/spec/views/frame_one.erb +1 -0
- data/lib/capybara/spec/views/obscured.erb +9 -9
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/with_animation.erb +29 -1
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_html.erb +28 -2
- data/lib/capybara/spec/views/with_js.erb +2 -1
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +10 -10
- data/spec/basic_node_spec.rb +6 -6
- 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 +12 -2
- data/spec/minitest_spec_spec.rb +56 -45
- data/spec/rack_test_spec.rb +25 -12
- data/spec/regexp_dissassembler_spec.rb +53 -39
- data/spec/result_spec.rb +50 -54
- data/spec/rspec/features_spec.rb +1 -0
- data/spec/rspec/shared_spec_matchers.rb +78 -62
- data/spec/rspec_spec.rb +5 -5
- data/spec/sauce_spec_chrome.rb +1 -0
- data/spec/selector_spec.rb +26 -16
- data/spec/selenium_spec_chrome.rb +84 -5
- data/spec/selenium_spec_chrome_remote.rb +23 -8
- data/spec/selenium_spec_edge.rb +23 -8
- data/spec/selenium_spec_firefox.rb +16 -21
- data/spec/selenium_spec_firefox_remote.rb +4 -13
- data/spec/selenium_spec_ie.rb +23 -15
- data/spec/selenium_spec_safari.rb +17 -17
- data/spec/server_spec.rb +87 -42
- data/spec/session_spec.rb +11 -4
- data/spec/shared_selenium_node.rb +83 -0
- data/spec/shared_selenium_session.rb +62 -72
- data/spec/spec_helper.rb +43 -5
- metadata +114 -16
@@ -5,179 +5,248 @@ require 'minitest/spec'
|
|
5
5
|
module Capybara
|
6
6
|
module Minitest
|
7
7
|
module Expectations
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
##
|
9
|
+
# Expectation that there is an ancestor
|
10
|
+
#
|
11
|
+
# @!method must_have_ancestor
|
12
|
+
# See {Capybara::Node::Matchers#has_ancestor?}
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
%w[assert_none_of_selectors must_have_none_of_selectors],
|
19
|
-
%w[assert_any_of_selectors must_have_any_of_selectors],
|
20
|
-
%w[assert_matches_style must_match_style]] +
|
21
|
-
%w[selector xpath css].flat_map do |assertion|
|
22
|
-
[%W[assert_matches_#{assertion} must_match_#{assertion}],
|
23
|
-
%W[refute_matches_#{assertion} wont_match_#{assertion}]]
|
24
|
-
end).each do |(meth, new_name)|
|
25
|
-
class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
|
26
|
-
def #{new_name} *args, &block
|
27
|
-
::Minitest::Expectation.new(self, ::Minitest::Spec.current).#{new_name}(*args, &block)
|
28
|
-
end
|
29
|
-
ASSERTION
|
14
|
+
##
|
15
|
+
# Expectation that there is button
|
16
|
+
#
|
17
|
+
# @!method must_have_button
|
18
|
+
# See {Capybara::Node::Matchers#has_button?}
|
30
19
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
# rubocop:enable Style/MultilineBlockChain
|
20
|
+
##
|
21
|
+
# Expectation that there is no button
|
22
|
+
#
|
23
|
+
# @!method wont_have_button
|
24
|
+
# See {Capybara::Node::Matchers#has_no_button?}
|
38
25
|
|
39
26
|
##
|
40
|
-
#
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
27
|
+
# Expectation that there is checked_field
|
28
|
+
#
|
29
|
+
# @!method must_have_checked_field
|
30
|
+
# See {Capybara::Node::Matchers#has_checked_field?}
|
45
31
|
|
46
32
|
##
|
47
|
-
# Expectation that there is
|
33
|
+
# Expectation that there is no checked_field
|
48
34
|
#
|
49
|
-
# @!method
|
50
|
-
#
|
35
|
+
# @!method wont_have_checked_field
|
36
|
+
# See {Capybara::Node::Matchers#has_no_checked_field?}
|
51
37
|
|
52
38
|
##
|
53
|
-
# Expectation that there is
|
39
|
+
# Expectation that there is unchecked_field
|
54
40
|
#
|
55
|
-
# @!method
|
56
|
-
#
|
41
|
+
# @!method must_have_unchecked_field
|
42
|
+
# See {Capybara::Node::Matchers#has_unchecked_field?}
|
57
43
|
|
58
44
|
##
|
59
|
-
# Expectation that there is
|
45
|
+
# Expectation that there is no unchecked_field
|
60
46
|
#
|
61
|
-
# @!method
|
62
|
-
#
|
47
|
+
# @!method wont_have_unchecked_field
|
48
|
+
# See {Capybara::Node::Matchers#has_no_unchecked_field?}
|
63
49
|
|
64
50
|
##
|
65
|
-
# Expectation that
|
51
|
+
# Expectation that page content does match
|
66
52
|
#
|
67
|
-
# @!method
|
68
|
-
#
|
53
|
+
# @!method must_have_content
|
54
|
+
# See {Capybara::Node::Matchers#has_content?}
|
69
55
|
|
70
56
|
##
|
71
|
-
# Expectation that
|
57
|
+
# Expectation that page content does not match
|
72
58
|
#
|
73
|
-
# @!method
|
74
|
-
#
|
59
|
+
# @!method wont_have_content
|
60
|
+
# See {Capybara::Node::Matchers#has_no_content?}
|
75
61
|
|
76
62
|
##
|
77
|
-
# Expectation that there is
|
63
|
+
# Expectation that there is css
|
78
64
|
#
|
79
|
-
# @!method
|
80
|
-
#
|
65
|
+
# @!method must_have_css
|
66
|
+
# See {Capybara::Node::Matchers#has_css?}
|
81
67
|
|
82
68
|
##
|
83
|
-
# Expectation that there is
|
69
|
+
# Expectation that there is no css
|
84
70
|
#
|
85
|
-
# @!method
|
86
|
-
#
|
71
|
+
# @!method wont_have_css
|
72
|
+
# See {Capybara::Node::Matchers#has_no_css?}
|
87
73
|
|
88
74
|
##
|
89
|
-
# Expectation that
|
75
|
+
# Expectation that current path matches
|
90
76
|
#
|
91
|
-
# @!method
|
92
|
-
#
|
77
|
+
# @!method must_have_current_path
|
78
|
+
# See {Capybara::SessionMatchers#has_current_path?}
|
79
|
+
|
80
|
+
##
|
81
|
+
# Expectation that current page does not match
|
82
|
+
#
|
83
|
+
# @!method wont_have_current_path
|
84
|
+
# See {Capybara::SessionMatchers#has_no_current_path?}
|
93
85
|
|
94
86
|
##
|
95
87
|
# Expectation that there is field
|
96
88
|
#
|
97
89
|
# @!method must_have_field
|
98
|
-
#
|
90
|
+
# See {Capybara::Node::Matchers#has_field?}
|
99
91
|
|
100
92
|
##
|
101
93
|
# Expectation that there is no field
|
102
94
|
#
|
103
95
|
# @!method wont_have_field
|
104
|
-
#
|
96
|
+
# See {Capybara::Node::Matchers#has_no_field?}
|
105
97
|
|
106
98
|
##
|
107
|
-
# Expectation that there is
|
99
|
+
# Expectation that there is link
|
108
100
|
#
|
109
|
-
# @!method
|
110
|
-
#
|
101
|
+
# @!method must_have_link
|
102
|
+
# See {Capybara::Node::Matchers#has_link?}
|
111
103
|
|
112
104
|
##
|
113
|
-
# Expectation that there is no
|
105
|
+
# Expectation that there is no link
|
114
106
|
#
|
115
|
-
# @!method
|
107
|
+
# @!method wont_have_link
|
108
|
+
# See {Capybara::Node::Matchers#has_no_link?}
|
116
109
|
|
117
110
|
##
|
118
|
-
# Expectation that
|
111
|
+
# Expectation that page text does match
|
119
112
|
#
|
120
|
-
# @!method
|
121
|
-
#
|
113
|
+
# @!method must_have_text
|
114
|
+
# See {Capybara::Node::Matchers#has_text?}
|
122
115
|
|
123
116
|
##
|
124
|
-
# Expectation that
|
117
|
+
# Expectation that page text does not match
|
118
|
+
#
|
119
|
+
# @!method wont_have_text
|
120
|
+
# See {Capybara::Node::Matchers#has_no_text?}
|
121
|
+
|
122
|
+
##
|
123
|
+
# Expectation that page title does match
|
125
124
|
#
|
126
|
-
# @!method
|
125
|
+
# @!method must_have_title
|
126
|
+
# See {Capybara::Node::DocumentMatchers#has_title?}
|
127
|
+
|
128
|
+
##
|
129
|
+
# Expectation that page title does not match
|
130
|
+
#
|
131
|
+
# @!method wont_have_title
|
132
|
+
# See {Capybara::Node::DocumentMatchers#has_no_title?}
|
127
133
|
|
128
134
|
##
|
129
135
|
# Expectation that there is select
|
130
136
|
#
|
131
137
|
# @!method must_have_select
|
132
|
-
#
|
138
|
+
# See {Capybara::Node::Matchers#has_select?}
|
133
139
|
|
134
140
|
##
|
135
141
|
# Expectation that there is no select
|
136
142
|
#
|
137
143
|
# @!method wont_have_select
|
138
|
-
#
|
144
|
+
# See {Capybara::Node::Matchers#has_no_select?}
|
139
145
|
|
140
146
|
##
|
141
|
-
# Expectation that there is
|
147
|
+
# Expectation that there is a selector
|
142
148
|
#
|
143
|
-
# @!method
|
144
|
-
#
|
149
|
+
# @!method must_have_selector
|
150
|
+
# See {Capybara::Node::Matchers#has_selector?}
|
145
151
|
|
146
152
|
##
|
147
|
-
# Expectation that there is no
|
153
|
+
# Expectation that there is no selector
|
148
154
|
#
|
149
|
-
# @!method
|
150
|
-
#
|
155
|
+
# @!method wont_have_selector
|
156
|
+
# See {Capybara::Node::Matchers#has_no_selector?}
|
151
157
|
|
152
158
|
##
|
153
|
-
# Expectation that
|
159
|
+
# Expectation that all of the provided selectors are present
|
154
160
|
#
|
155
|
-
# @!method
|
156
|
-
#
|
161
|
+
# @!method must_have_all_of_selectors
|
162
|
+
# See {Capybara::Node::Matchers#assert_all_of_selectors}
|
157
163
|
|
158
164
|
##
|
159
|
-
# Expectation that
|
165
|
+
# Expectation that none of the provided selectors are present
|
160
166
|
#
|
161
|
-
# @!method
|
162
|
-
#
|
167
|
+
# @!method must_have_none_of_selectors
|
168
|
+
# See {Capybara::Node::Matchers#assert_none_of_selectors}
|
163
169
|
|
164
170
|
##
|
165
|
-
# Expectation that
|
171
|
+
# Expectation that any of the provided selectors are present
|
166
172
|
#
|
167
|
-
# @!method
|
168
|
-
#
|
173
|
+
# @!method must_have_any_of_selectors
|
174
|
+
# See {Capybara::Node::Matchers#assert_any_of_selectors}
|
169
175
|
|
170
176
|
##
|
171
|
-
# Expectation that
|
177
|
+
# Expectation that there is a sibling
|
172
178
|
#
|
173
|
-
# @!method
|
174
|
-
#
|
179
|
+
# @!method must_have_sibling
|
180
|
+
# See {Capybara::Node::Matchers#has_sibling?}
|
175
181
|
|
176
182
|
##
|
177
183
|
# Expectation that element has style
|
178
184
|
#
|
179
185
|
# @!method must_match_style
|
180
|
-
#
|
186
|
+
# See {Capybara::Node::Matchers#matches_style?}
|
187
|
+
|
188
|
+
##
|
189
|
+
# Expectation that there is table
|
190
|
+
#
|
191
|
+
# @!method must_have_table
|
192
|
+
# See {Capybara::Node::Matchers#has_table?}
|
193
|
+
|
194
|
+
##
|
195
|
+
# Expectation that there is no table
|
196
|
+
#
|
197
|
+
# @!method wont_have_table
|
198
|
+
# See {Capybara::Node::Matchers#has_no_table?}
|
199
|
+
|
200
|
+
##
|
201
|
+
# Expectation that there is xpath
|
202
|
+
#
|
203
|
+
# @!method must_have_xpath
|
204
|
+
# See {Capybara::Node::Matchers#has_xpath?}
|
205
|
+
|
206
|
+
##
|
207
|
+
# Expectation that there is no xpath
|
208
|
+
#
|
209
|
+
# @!method wont_have_xpath
|
210
|
+
# See {Capybara::Node::Matchers#has_no_xpath?}
|
211
|
+
|
212
|
+
%w[text content title current_path].each do |assertion|
|
213
|
+
infect_an_assertion "assert_#{assertion}", "must_have_#{assertion}", :reverse
|
214
|
+
infect_an_assertion "refute_#{assertion}", "wont_have_#{assertion}", :reverse
|
215
|
+
end
|
216
|
+
|
217
|
+
# rubocop:disable Style/MultilineBlockChain
|
218
|
+
(%w[selector xpath css link button field select table checked_field unchecked_field
|
219
|
+
ancestor sibling].flat_map do |assertion|
|
220
|
+
[%W[assert_#{assertion} must_have_#{assertion}],
|
221
|
+
%W[refute_#{assertion} wont_have_#{assertion}]]
|
222
|
+
end + [%w[assert_all_of_selectors must_have_all_of_selectors],
|
223
|
+
%w[assert_none_of_selectors must_have_none_of_selectors],
|
224
|
+
%w[assert_any_of_selectors must_have_any_of_selectors],
|
225
|
+
%w[assert_matches_style must_match_style]] +
|
226
|
+
%w[selector xpath css].flat_map do |assertion|
|
227
|
+
[%W[assert_matches_#{assertion} must_match_#{assertion}],
|
228
|
+
%W[refute_matches_#{assertion} wont_match_#{assertion}]]
|
229
|
+
end).each do |(meth, new_name)|
|
230
|
+
class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
|
231
|
+
def #{new_name} *args, &block
|
232
|
+
::Minitest::Expectation.new(self, ::Minitest::Spec.current).#{new_name}(*args, &block)
|
233
|
+
end
|
234
|
+
ASSERTION
|
235
|
+
|
236
|
+
::Minitest::Expectation.class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
|
237
|
+
def #{new_name} *args, &block
|
238
|
+
ctx.#{meth}(target, *args, &block)
|
239
|
+
end
|
240
|
+
ASSERTION
|
241
|
+
end
|
242
|
+
# rubocop:enable Style/MultilineBlockChain
|
243
|
+
|
244
|
+
##
|
245
|
+
# @deprecated
|
246
|
+
def must_have_style(*args, &block)
|
247
|
+
warn 'must_have_style is deprecated, please use must_match_style'
|
248
|
+
must_match_style(*args, &block)
|
249
|
+
end
|
181
250
|
end
|
182
251
|
end
|
183
252
|
end
|
@@ -6,62 +6,63 @@ module Capybara
|
|
6
6
|
# @!macro waiting_behavior
|
7
7
|
# If the driver is capable of executing JavaScript, this method will wait for a set amount of time
|
8
8
|
# and continuously retry finding the element until either the element is found or the time
|
9
|
-
# expires. The length of time
|
9
|
+
# expires. The length of time this method will wait is controlled through {Capybara.configure default_max_wait_time}.
|
10
10
|
#
|
11
|
-
# @option options [false, true, Numeric] wait
|
11
|
+
# @option options [false, true, Numeric] wait
|
12
|
+
# Maximum time to wait for matching element to appear. Defaults to {Capybara.configure default_max_wait_time}.
|
12
13
|
|
13
14
|
##
|
14
15
|
#
|
15
|
-
# Finds a button or link and clicks it.
|
16
|
-
# {
|
16
|
+
# Finds a button or link and clicks it. See {#click_button} and
|
17
|
+
# {#click_link} for what locator will match against for each type of element.
|
17
18
|
#
|
18
19
|
# @overload click_link_or_button([locator], **options)
|
19
20
|
# @macro waiting_behavior
|
20
|
-
# @param [String] locator See {
|
21
|
+
# @param [String] locator See {#click_button} and {#click_link}
|
21
22
|
#
|
22
23
|
# @return [Capybara::Node::Element] The element clicked
|
23
24
|
#
|
24
25
|
def click_link_or_button(locator = nil, **options)
|
25
|
-
find(:link_or_button, locator, options).click
|
26
|
+
find(:link_or_button, locator, **options).click
|
26
27
|
end
|
27
28
|
alias_method :click_on, :click_link_or_button
|
28
29
|
|
29
30
|
##
|
30
31
|
#
|
31
|
-
# Finds a link by id, Capybara.test_id attribute, text or title and clicks it. Also looks at image
|
32
|
+
# Finds a link by id, {Capybara.configure test_id} attribute, text or title and clicks it. Also looks at image
|
32
33
|
# alt text inside the link.
|
33
34
|
#
|
34
35
|
# @overload click_link([locator], **options)
|
35
36
|
# @macro waiting_behavior
|
36
|
-
# @param [String] locator text, id, Capybara.test_id attribute, title or nested image's alt attribute
|
37
|
-
# @param options
|
37
|
+
# @param [String] locator text, id, {Capybara.configure test_id} attribute, title or nested image's alt attribute
|
38
|
+
# @param [Hash] options See {Capybara::Node::Finders#find_link}
|
38
39
|
#
|
39
40
|
# @return [Capybara::Node::Element] The element clicked
|
40
41
|
def click_link(locator = nil, **options)
|
41
|
-
find(:link, locator, options).click
|
42
|
+
find(:link, locator, **options).click
|
42
43
|
end
|
43
44
|
|
44
45
|
##
|
45
46
|
#
|
46
47
|
# Finds a button on the page and clicks it.
|
47
|
-
# This can be any
|
48
|
-
#
|
49
|
-
# by their text content, and image
|
48
|
+
# This can be any `<input>` element of type submit, reset, image, button or it can be a
|
49
|
+
# `<button>` element. All buttons can be found by their id, name, {Capybara.configure test_id} attribute, value, or title. `<button>` elements can also be found
|
50
|
+
# by their text content, and image `<input>` elements by their alt attribute.
|
50
51
|
#
|
51
52
|
# @overload click_button([locator], **options)
|
52
53
|
# @macro waiting_behavior
|
53
54
|
# @param [String] locator Which button to find
|
54
|
-
# @param options
|
55
|
+
# @param [Hash] options See {Capybara::Node::Finders#find_button}
|
55
56
|
# @return [Capybara::Node::Element] The element clicked
|
56
57
|
def click_button(locator = nil, **options)
|
57
|
-
find(:button, locator, options).click
|
58
|
+
find(:button, locator, **options).click
|
58
59
|
end
|
59
60
|
|
60
61
|
##
|
61
62
|
#
|
62
|
-
# Locate a text field or text area and fill it in with the given text
|
63
|
-
# The field can be found via its name, id, Capybara.test_id attribute, or label text.
|
64
|
-
# If no locator is provided will operate on self or a descendant
|
63
|
+
# Locate a text field or text area and fill it in with the given text.
|
64
|
+
# The field can be found via its name, id, {Capybara.configure test_id} attribute, placeholder, or label text.
|
65
|
+
# If no locator is provided this will operate on self or a descendant.
|
65
66
|
#
|
66
67
|
# # will fill in a descendant fillable field with name, id, or label text matching 'Name'
|
67
68
|
# page.fill_in 'Name', with: 'Bob'
|
@@ -73,7 +74,7 @@ module Capybara
|
|
73
74
|
# @overload fill_in([locator], with:, **options)
|
74
75
|
# @param [String] locator Which field to fill in
|
75
76
|
# @param [Hash] options
|
76
|
-
# @param with: [String] The value to
|
77
|
+
# @param with: [String] The value to fill in
|
77
78
|
# @macro waiting_behavior
|
78
79
|
# @option options [String] currently_with The current value property of the field to fill in
|
79
80
|
# @option options [Boolean] multiple Match fields that can have multiple values?
|
@@ -81,23 +82,24 @@ module Capybara
|
|
81
82
|
# @option options [String] name Match fields that match the name attribute
|
82
83
|
# @option options [String] placeholder Match fields that match the placeholder attribute
|
83
84
|
# @option options [String, Array<String>, Regexp] class Match fields that match the class(es) provided
|
84
|
-
# @option options [Hash] fill_options Driver specific options regarding how to fill fields (Defaults come from Capybara.default_set_options)
|
85
|
+
# @option options [Hash] fill_options Driver specific options regarding how to fill fields (Defaults come from {Capybara.configure default_set_options})
|
85
86
|
#
|
86
|
-
# @return [Capybara::Node::Element] The element
|
87
|
+
# @return [Capybara::Node::Element] The element filled in
|
87
88
|
def fill_in(locator = nil, with:, currently_with: nil, fill_options: {}, **find_options)
|
88
89
|
find_options[:with] = currently_with if currently_with
|
89
90
|
find_options[:allow_self] = true if locator.nil?
|
90
|
-
find(:fillable_field, locator, find_options).set(with, fill_options)
|
91
|
+
find(:fillable_field, locator, **find_options).set(with, **fill_options)
|
91
92
|
end
|
92
93
|
|
93
94
|
# @!macro label_click
|
94
|
-
# @option options [Boolean] allow_label_click
|
95
|
+
# @option options [Boolean] allow_label_click
|
96
|
+
# Attempt to click the label to toggle state if element is non-visible. Defaults to {Capybara.configure automatic_label_click}.
|
95
97
|
|
96
98
|
##
|
97
99
|
#
|
98
100
|
# Find a descendant radio button and mark it as checked. The radio button can be found
|
99
|
-
# via name, id or label text. If no locator is
|
100
|
-
# a descendant.
|
101
|
+
# via name, id, {Capybara.configure test_id} attribute or label text. If no locator is
|
102
|
+
# provided this will match against self or a descendant.
|
101
103
|
#
|
102
104
|
# # will choose a descendant radio button with a name, id, or label text matching 'Male'
|
103
105
|
# page.choose('Male')
|
@@ -117,14 +119,14 @@ module Capybara
|
|
117
119
|
#
|
118
120
|
# @return [Capybara::Node::Element] The element chosen or the label clicked
|
119
121
|
def choose(locator = nil, **options)
|
120
|
-
_check_with_label(:radio_button, true, locator, options)
|
122
|
+
_check_with_label(:radio_button, true, locator, **options)
|
121
123
|
end
|
122
124
|
|
123
125
|
##
|
124
126
|
#
|
125
127
|
# Find a descendant check box and mark it as checked. The check box can be found
|
126
|
-
# via name, id or label text. If no locator
|
127
|
-
# self or a descendant.
|
128
|
+
# via name, id, {Capybara.configure test_id} attribute, or label text. If no locator
|
129
|
+
# is provided this will match against self or a descendant.
|
128
130
|
#
|
129
131
|
# # will check a descendant checkbox with a name, id, or label text matching 'German'
|
130
132
|
# page.check('German')
|
@@ -145,14 +147,14 @@ module Capybara
|
|
145
147
|
#
|
146
148
|
# @return [Capybara::Node::Element] The element checked or the label clicked
|
147
149
|
def check(locator = nil, **options)
|
148
|
-
_check_with_label(:checkbox, true, locator, options)
|
150
|
+
_check_with_label(:checkbox, true, locator, **options)
|
149
151
|
end
|
150
152
|
|
151
153
|
##
|
152
154
|
#
|
153
155
|
# Find a descendant check box and uncheck it. The check box can be found
|
154
|
-
# via name, id or label text. If
|
155
|
-
# self or a descendant.
|
156
|
+
# via name, id, {Capybara.configure test_id} attribute, or label text. If
|
157
|
+
# no locator is provided this will match against self or a descendant.
|
156
158
|
#
|
157
159
|
# # will uncheck a descendant checkbox with a name, id, or label text matching 'German'
|
158
160
|
# page.uncheck('German')
|
@@ -173,17 +175,18 @@ module Capybara
|
|
173
175
|
#
|
174
176
|
# @return [Capybara::Node::Element] The element unchecked or the label clicked
|
175
177
|
def uncheck(locator = nil, **options)
|
176
|
-
_check_with_label(:checkbox, false, locator, options)
|
178
|
+
_check_with_label(:checkbox, false, locator, **options)
|
177
179
|
end
|
178
180
|
|
179
181
|
##
|
180
182
|
#
|
181
|
-
# If
|
183
|
+
# If `from` option is present, {#select} finds a select box, or text input with associated datalist,
|
182
184
|
# on the page and selects a particular option from it.
|
183
185
|
# Otherwise it finds an option inside current scope and selects it.
|
184
|
-
# If the select box is a multiple select,
|
186
|
+
# If the select box is a multiple select, {#select} can be called multiple times to select more than
|
185
187
|
# one option.
|
186
|
-
# The select box can be found via its name, id
|
188
|
+
# The select box can be found via its name, id, {Capybara.configure test_id} attribute, or label text.
|
189
|
+
# The option can be found by its text.
|
187
190
|
#
|
188
191
|
# page.select 'March', from: 'Month'
|
189
192
|
#
|
@@ -191,7 +194,7 @@ module Capybara
|
|
191
194
|
# @macro waiting_behavior
|
192
195
|
#
|
193
196
|
# @param value [String] Which option to select
|
194
|
-
# @param from [String] The id, Capybara.test_id
|
197
|
+
# @param from [String] The id, {Capybara.configure test_id} attribute, name or label of the select box
|
195
198
|
#
|
196
199
|
# @return [Capybara::Node::Element] The option element selected
|
197
200
|
def select(value = nil, from: nil, **options)
|
@@ -202,15 +205,16 @@ module Capybara
|
|
202
205
|
if el.respond_to?(:tag_name) && (el.tag_name == 'input')
|
203
206
|
select_datalist_option(el, value)
|
204
207
|
else
|
205
|
-
el.find(:option, value, options).select_option
|
208
|
+
el.find(:option, value, **options).select_option
|
206
209
|
end
|
207
210
|
end
|
208
211
|
|
209
212
|
##
|
210
213
|
#
|
211
214
|
# Find a select box on the page and unselect a particular option from it. If the select
|
212
|
-
# box is a multiple select,
|
213
|
-
# one option. The select box can be found via its name, id
|
215
|
+
# box is a multiple select, {#unselect} can be called multiple times to unselect more than
|
216
|
+
# one option. The select box can be found via its name, id, {Capybara.configure test_id} attribute,
|
217
|
+
# or label text.
|
214
218
|
#
|
215
219
|
# page.unselect 'March', from: 'Month'
|
216
220
|
#
|
@@ -218,22 +222,22 @@ module Capybara
|
|
218
222
|
# @macro waiting_behavior
|
219
223
|
#
|
220
224
|
# @param value [String] Which option to unselect
|
221
|
-
# @param from [String] The id, Capybara.test_id attribute, name or label of the select box
|
225
|
+
# @param from [String] The id, {Capybara.configure test_id} attribute, name or label of the select box
|
222
226
|
#
|
223
227
|
#
|
224
228
|
# @return [Capybara::Node::Element] The option element unselected
|
225
229
|
def unselect(value = nil, from: nil, **options)
|
226
230
|
raise ArgumentError, 'The :from option does not take an element' if from.is_a? Capybara::Node::Element
|
227
231
|
|
228
|
-
scope = from ? find(:select, from, options) : self
|
229
|
-
scope.find(:option, value, options).unselect_option
|
232
|
+
scope = from ? find(:select, from, **options) : self
|
233
|
+
scope.find(:option, value, **options).unselect_option
|
230
234
|
end
|
231
235
|
|
232
236
|
##
|
233
237
|
#
|
234
238
|
# Find a descendant file field on the page and attach a file given its path. There are two ways to use
|
235
|
-
#
|
236
|
-
# In the case of the file field being hidden for
|
239
|
+
# {#attach_file}, in the first method the file field can be found via its name, id,
|
240
|
+
# {Capybara.configure test_id} attribute, or label text. In the case of the file field being hidden for
|
237
241
|
# styling reasons the `make_visible` option can be used to temporarily change the CSS of
|
238
242
|
# the file field, attach the file, and then revert the CSS back to original. If no locator is
|
239
243
|
# passed this will match self or a descendant.
|
@@ -257,19 +261,24 @@ module Capybara
|
|
257
261
|
# @param [String] locator Which field to attach the file to
|
258
262
|
# @param [String, Array<String>] paths The path(s) of the file(s) that will be attached
|
259
263
|
#
|
260
|
-
# @option options [Symbol] match
|
261
|
-
#
|
264
|
+
# @option options [Symbol] match
|
265
|
+
# The matching strategy to use (:one, :first, :prefer_exact, :smart). Defaults to {Capybara.configure match}.
|
266
|
+
# @option options [Boolean] exact
|
267
|
+
# Match the exact label name/contents or accept a partial match. Defaults to {Capybara.configure exact}.
|
262
268
|
# @option options [Boolean] multiple Match field which allows multiple file selection
|
263
269
|
# @option options [String, Regexp] id Match fields that match the id attribute
|
264
270
|
# @option options [String] name Match fields that match the name attribute
|
265
271
|
# @option options [String, Array<String>, Regexp] class Match fields that match the class(es) provided
|
266
|
-
# @option options [true, Hash] make_visible
|
272
|
+
# @option options [true, Hash] make_visible
|
273
|
+
# 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).
|
267
274
|
# @overload attach_file(paths, &blk)
|
268
275
|
# @param [String, Array<String>] paths The path(s) of the file(s) that will be attached
|
269
276
|
# @yield Block whose actions will trigger the system file chooser to be shown
|
270
277
|
# @return [Capybara::Node::Element] The file field element
|
271
278
|
def attach_file(locator = nil, paths, make_visible: nil, **options) # rubocop:disable Style/OptionalArguments
|
272
|
-
|
279
|
+
if locator && block_given?
|
280
|
+
raise ArgumentError, '``#attach_file` does not support passing both a locator and a block'
|
281
|
+
end
|
273
282
|
|
274
283
|
Array(paths).each do |path|
|
275
284
|
raise Capybara::FileNotFound, "cannot attach file, #{path} does not exist" unless File.exist?(path.to_s)
|
@@ -281,16 +290,17 @@ module Capybara
|
|
281
290
|
execute_script CAPTURE_FILE_ELEMENT_SCRIPT
|
282
291
|
yield
|
283
292
|
file_field = evaluate_script 'window._capybara_clicked_file_input'
|
293
|
+
raise ArgumentError, "Capybara was unable to determine the file input you're attaching to" unless file_field
|
284
294
|
rescue ::Capybara::NotSupportedByDriverError
|
285
295
|
warn 'Block mode of `#attach_file` is not supported by the current driver - ignoring.'
|
286
296
|
end
|
287
297
|
end
|
288
298
|
# Allow user to update the CSS style of the file input since they are so often hidden on a page
|
289
299
|
if make_visible
|
290
|
-
ff = file_field || find(:file_field, locator, options.merge(visible: :all))
|
300
|
+
ff = file_field || find(:file_field, locator, **options.merge(visible: :all))
|
291
301
|
while_visible(ff, make_visible) { |el| el.set(paths) }
|
292
302
|
else
|
293
|
-
(file_field || find(:file_field, locator, options)).set(paths)
|
303
|
+
(file_field || find(:file_field, locator, **options)).set(paths)
|
294
304
|
end
|
295
305
|
end
|
296
306
|
|
@@ -298,16 +308,14 @@ module Capybara
|
|
298
308
|
|
299
309
|
def find_select_or_datalist_input(from, options)
|
300
310
|
synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
|
311
|
+
find(:select, from, **options)
|
312
|
+
rescue Capybara::ElementNotFound => select_error # rubocop:disable Naming/RescuedExceptionsVariableName
|
313
|
+
raise if %i[selected with_selected multiple].any? { |option| options.key?(option) }
|
314
|
+
|
301
315
|
begin
|
302
|
-
find(:
|
303
|
-
rescue Capybara::ElementNotFound =>
|
304
|
-
raise
|
305
|
-
|
306
|
-
begin
|
307
|
-
find(:datalist_input, from, options)
|
308
|
-
rescue Capybara::ElementNotFound => dlinput_error
|
309
|
-
raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}"
|
310
|
-
end
|
316
|
+
find(:datalist_input, from, **options)
|
317
|
+
rescue Capybara::ElementNotFound => dlinput_error # rubocop:disable Naming/RescuedExceptionsVariableName
|
318
|
+
raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}"
|
311
319
|
end
|
312
320
|
end
|
313
321
|
end
|
@@ -326,9 +334,13 @@ module Capybara
|
|
326
334
|
end
|
327
335
|
|
328
336
|
def while_visible(element, visible_css)
|
329
|
-
|
337
|
+
if visible_css == true
|
338
|
+
visible_css = { opacity: 1, display: 'block', visibility: 'visible', width: 'auto', height: 'auto' }
|
339
|
+
end
|
330
340
|
_update_style(element, visible_css)
|
331
|
-
|
341
|
+
unless element.visible?
|
342
|
+
raise ExpectationNotMet, 'The style changes in :make_visible did not make the file input visible'
|
343
|
+
end
|
332
344
|
|
333
345
|
begin
|
334
346
|
yield element
|
@@ -345,7 +357,7 @@ module Capybara
|
|
345
357
|
|
346
358
|
def _reset_style(element)
|
347
359
|
element.execute_script(RESET_STYLE_SCRIPT)
|
348
|
-
rescue StandardError # rubocop:disable Lint/
|
360
|
+
rescue StandardError # rubocop:disable Lint/SuppressedException swallow extra errors
|
349
361
|
end
|
350
362
|
|
351
363
|
def _check_with_label(selector, checked, locator,
|
@@ -353,18 +365,16 @@ module Capybara
|
|
353
365
|
options[:allow_self] = true if locator.nil?
|
354
366
|
|
355
367
|
synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
|
368
|
+
el = find(selector, locator, **options)
|
369
|
+
el.set(checked)
|
370
|
+
rescue StandardError => e
|
371
|
+
raise unless allow_label_click && catch_error?(e)
|
372
|
+
|
356
373
|
begin
|
357
|
-
el
|
358
|
-
el.
|
359
|
-
rescue StandardError
|
360
|
-
raise
|
361
|
-
|
362
|
-
begin
|
363
|
-
el ||= find(selector, locator, options.merge(visible: :all))
|
364
|
-
el.session.find(:label, for: el, visible: true).click unless el.checked? == checked
|
365
|
-
rescue StandardError # swallow extra errors - raise original
|
366
|
-
raise err
|
367
|
-
end
|
374
|
+
el ||= find(selector, locator, **options.merge(visible: :all))
|
375
|
+
el.session.find(:label, for: el, visible: true).click unless el.checked? == checked
|
376
|
+
rescue StandardError # swallow extra errors - raise original
|
377
|
+
raise e
|
368
378
|
end
|
369
379
|
end
|
370
380
|
end
|
@@ -393,9 +403,10 @@ module Capybara
|
|
393
403
|
JS
|
394
404
|
|
395
405
|
CAPTURE_FILE_ELEMENT_SCRIPT = <<~'JS'
|
396
|
-
document.addEventListener('click', function(e){
|
406
|
+
document.addEventListener('click', function file_catcher(e){
|
397
407
|
if (e.target.matches("input[type='file']")) {
|
398
408
|
window._capybara_clicked_file_input = e.target;
|
409
|
+
this.removeEventListener('click', file_catcher);
|
399
410
|
e.preventDefault();
|
400
411
|
}
|
401
412
|
})
|