capybara 2.18.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +55 -1
- data/README.md +18 -17
- data/lib/capybara/config.rb +11 -58
- data/lib/capybara/cucumber.rb +2 -3
- data/lib/capybara/driver/base.rb +15 -16
- data/lib/capybara/driver/node.rb +5 -4
- data/lib/capybara/dsl.rb +1 -0
- data/lib/capybara/helpers.rb +19 -29
- data/lib/capybara/minitest/spec.rb +15 -14
- data/lib/capybara/minitest.rb +139 -138
- data/lib/capybara/node/actions.rb +60 -81
- data/lib/capybara/node/base.rb +11 -18
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +8 -8
- data/lib/capybara/node/element.rb +30 -40
- data/lib/capybara/node/finders.rb +62 -70
- data/lib/capybara/node/matchers.rb +50 -71
- data/lib/capybara/node/simple.rb +11 -17
- data/lib/capybara/queries/ancestor_query.rb +11 -7
- data/lib/capybara/queries/base_query.rb +22 -18
- data/lib/capybara/queries/current_path_query.rb +8 -24
- data/lib/capybara/queries/match_query.rb +3 -7
- data/lib/capybara/queries/selector_query.rb +92 -95
- data/lib/capybara/queries/sibling_query.rb +4 -4
- data/lib/capybara/queries/text_query.rb +35 -35
- data/lib/capybara/queries/title_query.rb +8 -11
- data/lib/capybara/rack_test/browser.rb +15 -18
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +6 -10
- data/lib/capybara/rack_test/form.rb +50 -40
- data/lib/capybara/rack_test/node.rb +93 -63
- data/lib/capybara/rails.rb +2 -6
- data/lib/capybara/result.rb +22 -22
- data/lib/capybara/rspec/compound.rb +5 -10
- data/lib/capybara/rspec/features.rb +17 -48
- data/lib/capybara/rspec/matcher_proxies.rb +31 -15
- data/lib/capybara/rspec/matchers.rb +70 -61
- data/lib/capybara/rspec.rb +5 -10
- data/lib/capybara/selector/css.rb +6 -11
- data/lib/capybara/selector/filter.rb +1 -17
- data/lib/capybara/selector/filter_set.rb +18 -15
- data/lib/capybara/selector/filters/base.rb +7 -6
- data/lib/capybara/selector/filters/expression_filter.rb +6 -23
- data/lib/capybara/selector/filters/node_filter.rb +2 -12
- data/lib/capybara/selector/selector.rb +28 -34
- data/lib/capybara/selector.rb +129 -117
- data/lib/capybara/selenium/driver.rb +131 -125
- data/lib/capybara/selenium/node.rb +197 -115
- data/lib/capybara/server.rb +3 -2
- data/lib/capybara/session/config.rb +47 -67
- data/lib/capybara/session/matchers.rb +8 -7
- data/lib/capybara/session.rb +138 -224
- data/lib/capybara/spec/public/test.js +25 -4
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -0
- data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -2
- data/lib/capybara/spec/session/accept_prompt_spec.rb +1 -0
- data/lib/capybara/spec/session/all_spec.rb +31 -18
- data/lib/capybara/spec/session/ancestor_spec.rb +6 -8
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +6 -5
- data/lib/capybara/spec/session/assert_current_path.rb +12 -11
- data/lib/capybara/spec/session/assert_selector.rb +1 -0
- data/lib/capybara/spec/session/assert_text.rb +23 -23
- data/lib/capybara/spec/session/assert_title.rb +13 -3
- data/lib/capybara/spec/session/attach_file_spec.rb +51 -30
- data/lib/capybara/spec/session/body_spec.rb +1 -0
- data/lib/capybara/spec/session/check_spec.rb +7 -6
- data/lib/capybara/spec/session/choose_spec.rb +5 -4
- data/lib/capybara/spec/session/click_button_spec.rb +24 -32
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +8 -7
- data/lib/capybara/spec/session/click_link_spec.rb +8 -7
- data/lib/capybara/spec/session/current_scope_spec.rb +4 -3
- data/lib/capybara/spec/session/current_url_spec.rb +17 -6
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +1 -1
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +1 -0
- data/lib/capybara/spec/session/element/assert_match_selector.rb +1 -1
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +1 -1
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +5 -5
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +3 -2
- data/lib/capybara/spec/session/evaluate_script_spec.rb +4 -3
- data/lib/capybara/spec/session/execute_script_spec.rb +4 -3
- data/lib/capybara/spec/session/fill_in_spec.rb +30 -5
- data/lib/capybara/spec/session/find_button_spec.rb +4 -3
- data/lib/capybara/spec/session/find_by_id_spec.rb +2 -1
- data/lib/capybara/spec/session/find_field_spec.rb +9 -15
- data/lib/capybara/spec/session/find_link_spec.rb +6 -5
- data/lib/capybara/spec/session/find_spec.rb +37 -31
- data/lib/capybara/spec/session/first_spec.rb +60 -33
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +9 -16
- data/lib/capybara/spec/session/go_back_spec.rb +1 -0
- data/lib/capybara/spec/session/go_forward_spec.rb +1 -0
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +15 -15
- data/lib/capybara/spec/session/has_button_spec.rb +2 -1
- data/lib/capybara/spec/session/has_css_spec.rb +3 -2
- data/lib/capybara/spec/session/has_current_path_spec.rb +12 -28
- data/lib/capybara/spec/session/has_field_spec.rb +4 -3
- data/lib/capybara/spec/session/has_link_spec.rb +1 -0
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +17 -17
- data/lib/capybara/spec/session/has_select_spec.rb +30 -29
- data/lib/capybara/spec/session/has_selector_spec.rb +5 -4
- data/lib/capybara/spec/session/has_table_spec.rb +2 -1
- data/lib/capybara/spec/session/has_text_spec.rb +9 -13
- data/lib/capybara/spec/session/has_title_spec.rb +1 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +1 -0
- data/lib/capybara/spec/session/headers.rb +2 -1
- data/lib/capybara/spec/session/html_spec.rb +1 -0
- data/lib/capybara/spec/session/node_spec.rb +91 -56
- data/lib/capybara/spec/session/node_wrapper_spec.rb +36 -0
- data/lib/capybara/spec/session/refresh_spec.rb +6 -2
- data/lib/capybara/spec/session/reset_session_spec.rb +19 -0
- data/lib/capybara/spec/session/response_code.rb +1 -0
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -11
- data/lib/capybara/spec/session/save_page_spec.rb +1 -17
- data/lib/capybara/spec/session/save_screenshot_spec.rb +3 -3
- data/lib/capybara/spec/session/select_spec.rb +20 -20
- data/lib/capybara/spec/session/selectors_spec.rb +2 -2
- data/lib/capybara/spec/session/sibling_spec.rb +1 -1
- data/lib/capybara/spec/session/text_spec.rb +17 -3
- data/lib/capybara/spec/session/title_spec.rb +11 -1
- data/lib/capybara/spec/session/uncheck_spec.rb +4 -3
- data/lib/capybara/spec/session/unselect_spec.rb +6 -5
- data/lib/capybara/spec/session/visit_spec.rb +9 -3
- data/lib/capybara/spec/session/window/become_closed_spec.rb +2 -1
- data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +2 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -1
- data/lib/capybara/spec/session/window/window_spec.rb +12 -12
- data/lib/capybara/spec/session/window/windows_spec.rb +2 -3
- data/lib/capybara/spec/session/window/within_window_spec.rb +15 -71
- data/lib/capybara/spec/session/within_spec.rb +1 -0
- data/lib/capybara/spec/spec_helper.rb +34 -18
- data/lib/capybara/spec/test_app.rb +17 -9
- data/lib/capybara/spec/views/form.erb +7 -0
- data/lib/capybara/spec/views/with_html.erb +23 -1
- data/lib/capybara/spec/views/within_frames.erb +4 -1
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +6 -10
- data/lib/capybara.rb +28 -25
- data/spec/basic_node_spec.rb +1 -0
- data/spec/capybara_spec.rb +11 -50
- data/spec/dsl_spec.rb +5 -13
- data/spec/filter_set_spec.rb +5 -4
- data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +3 -2
- data/spec/minitest_spec.rb +4 -3
- data/spec/minitest_spec_spec.rb +3 -2
- data/spec/per_session_config_spec.rb +9 -8
- data/spec/rack_test_spec.rb +21 -20
- data/spec/result_spec.rb +17 -16
- data/spec/rspec/features_spec.rb +17 -14
- data/spec/rspec/scenarios_spec.rb +5 -7
- data/spec/rspec/shared_spec_matchers.rb +96 -99
- data/spec/rspec/views_spec.rb +2 -1
- data/spec/rspec_matchers_spec.rb +18 -2
- data/spec/rspec_spec.rb +11 -15
- data/spec/selector_spec.rb +5 -6
- data/spec/selenium_spec_chrome.rb +9 -4
- data/spec/selenium_spec_edge.rb +27 -0
- data/spec/selenium_spec_ie.rb +31 -0
- data/spec/selenium_spec_marionette.rb +28 -12
- data/spec/server_spec.rb +33 -33
- data/spec/session_spec.rb +2 -1
- data/spec/shared_selenium_session.rb +36 -22
- data/spec/spec_helper.rb +3 -6
- metadata +68 -85
- data/lib/capybara/query.rb +0 -7
- data/spec/selenium_spec_firefox.rb +0 -68
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Capybara
|
3
4
|
module RSpecMatcherProxies
|
4
|
-
def all(*args)
|
5
|
+
def all(*args, &block)
|
5
6
|
if defined?(::RSpec::Matchers::BuiltIn::All) && args.first.respond_to?(:matches?)
|
6
7
|
::RSpec::Matchers::BuiltIn::All.new(*args)
|
7
8
|
else
|
8
|
-
find_all(*args)
|
9
|
+
find_all(*args, &block)
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
@@ -18,28 +19,43 @@ module Capybara
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
|
-
module
|
22
|
-
|
23
|
-
remove_method :included
|
24
|
-
|
22
|
+
module DSLRSpecProxyInstaller
|
23
|
+
module ClassMethods
|
25
24
|
def included(base)
|
26
|
-
|
27
|
-
|
28
|
-
if defined?(::RSpec::Matchers) && base.include?(::RSpec::Matchers)
|
29
|
-
base.send(:include, ::Capybara::RSpecMatcherProxies)
|
25
|
+
if defined?(::RSpec::Matchers)
|
26
|
+
base.include(::Capybara::RSpecMatcherProxies) if base.include?(::RSpec::Matchers)
|
30
27
|
end
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.prepended(base)
|
33
|
+
class <<base
|
34
|
+
prepend ClassMethods
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
31
38
|
|
39
|
+
module RSpecMatcherProxyInstaller
|
40
|
+
module ClassMethods
|
41
|
+
def included(base)
|
42
|
+
base.include(::Capybara::RSpecMatcherProxies) if base.include?(::Capybara::DSL)
|
32
43
|
super
|
33
44
|
end
|
34
45
|
end
|
46
|
+
|
47
|
+
def self.prepended(base)
|
48
|
+
class <<base
|
49
|
+
prepend ClassMethods
|
50
|
+
end
|
51
|
+
end
|
35
52
|
end
|
53
|
+
|
54
|
+
DSL.prepend ::Capybara::DSLRSpecProxyInstaller
|
36
55
|
end
|
37
56
|
|
38
57
|
if defined?(::RSpec::Matchers)
|
39
|
-
module
|
40
|
-
|
41
|
-
base.send(:include, ::Capybara::RSpecMatcherProxies) if base.include?(::Capybara::DSL)
|
42
|
-
super
|
43
|
-
end
|
58
|
+
module ::RSpec::Matchers
|
59
|
+
prepend ::Capybara::RSpecMatcherProxyInstaller
|
44
60
|
end
|
45
61
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Capybara
|
3
4
|
module RSpecMatchers
|
4
5
|
class Matcher
|
5
|
-
if defined?(::RSpec::Expectations::Version)
|
6
|
+
if defined?(::RSpec::Expectations::Version)
|
6
7
|
require 'capybara/rspec/compound'
|
7
8
|
include ::Capybara::RSpecMatchers::Compound
|
8
9
|
end
|
@@ -10,18 +11,15 @@ module Capybara
|
|
10
11
|
attr_reader :failure_message, :failure_message_when_negated
|
11
12
|
|
12
13
|
def wrap(actual)
|
13
|
-
|
14
|
+
actual = actual.to_capybara_node if actual.respond_to?(:to_capybara_node)
|
15
|
+
@context_el = if actual.respond_to?(:has_selector?)
|
14
16
|
actual
|
15
17
|
else
|
16
18
|
Capybara.string(actual.to_s)
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
|
-
|
21
|
-
def failure_message_for_should; failure_message end
|
22
|
-
def failure_message_for_should_not; failure_message_when_negated end
|
23
|
-
|
24
|
-
private
|
22
|
+
private
|
25
23
|
|
26
24
|
def wrap_matches?(actual)
|
27
25
|
yield(wrap(actual))
|
@@ -65,11 +63,11 @@ module Capybara
|
|
65
63
|
end
|
66
64
|
|
67
65
|
def matches?(actual)
|
68
|
-
wrap_matches?(actual){ |el| el.assert_selector(*@args, &@filter_block) }
|
66
|
+
wrap_matches?(actual) { |el| el.assert_selector(*@args, &@filter_block) }
|
69
67
|
end
|
70
68
|
|
71
69
|
def does_not_match?(actual)
|
72
|
-
wrap_does_not_match?(actual){ |el| el.assert_no_selector(*@args, &@filter_block) }
|
70
|
+
wrap_does_not_match?(actual) { |el| el.assert_no_selector(*@args, &@filter_block) }
|
73
71
|
end
|
74
72
|
|
75
73
|
def description
|
@@ -88,10 +86,10 @@ module Capybara
|
|
88
86
|
end
|
89
87
|
|
90
88
|
def matches?(actual)
|
91
|
-
wrap_matches?(actual){ |el| el.assert_all_of_selectors(*@args, &@filter_block) }
|
89
|
+
wrap_matches?(actual) { |el| el.assert_all_of_selectors(*@args, &@filter_block) }
|
92
90
|
end
|
93
91
|
|
94
|
-
def does_not_match?(
|
92
|
+
def does_not_match?(_actual)
|
95
93
|
raise ArgumentError, "The have_all_selectors matcher does not support use with not_to/should_not"
|
96
94
|
end
|
97
95
|
|
@@ -107,10 +105,10 @@ module Capybara
|
|
107
105
|
end
|
108
106
|
|
109
107
|
def matches?(actual)
|
110
|
-
wrap_matches?(actual){ |el| el.assert_none_of_selectors(*@args, &@filter_block) }
|
108
|
+
wrap_matches?(actual) { |el| el.assert_none_of_selectors(*@args, &@filter_block) }
|
111
109
|
end
|
112
110
|
|
113
|
-
def does_not_match?(
|
111
|
+
def does_not_match?(_actual)
|
114
112
|
raise ArgumentError, "The have_none_of_selectors matcher does not support use with not_to/should_not"
|
115
113
|
end
|
116
114
|
|
@@ -138,15 +136,9 @@ module Capybara
|
|
138
136
|
end
|
139
137
|
|
140
138
|
class HaveText < Matcher
|
141
|
-
attr_reader :type, :content, :options
|
142
|
-
|
143
139
|
def initialize(*args)
|
144
140
|
@args = args.dup
|
145
|
-
|
146
|
-
# are set just for backwards compatability
|
147
|
-
@type = args.shift if args.first.is_a?(Symbol)
|
148
|
-
@content = args.shift
|
149
|
-
@options = (args.first.is_a?(Hash))? args.first : {}
|
141
|
+
@content = args[0].is_a?(Symbol) ? args[1] : args[0]
|
150
142
|
end
|
151
143
|
|
152
144
|
def matches?(actual)
|
@@ -158,18 +150,15 @@ module Capybara
|
|
158
150
|
end
|
159
151
|
|
160
152
|
def description
|
161
|
-
"text #{format(content)}"
|
153
|
+
"text #{format(@content)}"
|
162
154
|
end
|
163
155
|
|
164
156
|
def format(content)
|
165
|
-
content = Capybara::Helpers.normalize_whitespace(content) unless content.is_a? Regexp
|
166
157
|
content.inspect
|
167
158
|
end
|
168
159
|
end
|
169
160
|
|
170
161
|
class HaveTitle < Matcher
|
171
|
-
attr_reader :title
|
172
|
-
|
173
162
|
def initialize(*args)
|
174
163
|
@args = args
|
175
164
|
|
@@ -186,17 +175,13 @@ module Capybara
|
|
186
175
|
end
|
187
176
|
|
188
177
|
def description
|
189
|
-
"have title #{title.inspect}"
|
178
|
+
"have title #{@title.inspect}"
|
190
179
|
end
|
191
180
|
end
|
192
181
|
|
193
182
|
class HaveCurrentPath < Matcher
|
194
|
-
attr_reader :current_path
|
195
|
-
|
196
183
|
def initialize(*args)
|
197
184
|
@args = args
|
198
|
-
|
199
|
-
# are set just for backwards compatability
|
200
185
|
@current_path = args.first
|
201
186
|
end
|
202
187
|
|
@@ -209,7 +194,33 @@ module Capybara
|
|
209
194
|
end
|
210
195
|
|
211
196
|
def description
|
212
|
-
"have current path #{current_path.inspect}"
|
197
|
+
"have current path #{@current_path.inspect}"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
class NegatedMatcher
|
202
|
+
def initialize(matcher)
|
203
|
+
@matcher = matcher
|
204
|
+
end
|
205
|
+
|
206
|
+
def matches?(actual)
|
207
|
+
@matcher.does_not_match?(actual)
|
208
|
+
end
|
209
|
+
|
210
|
+
def does_not_match?(actual)
|
211
|
+
@matcher.matches?(actual)
|
212
|
+
end
|
213
|
+
|
214
|
+
def description
|
215
|
+
"not #{@matcher.description}"
|
216
|
+
end
|
217
|
+
|
218
|
+
def failure_message
|
219
|
+
@matcher.failure_message_when_negated
|
220
|
+
end
|
221
|
+
|
222
|
+
def failure_message_when_negated
|
223
|
+
@matcher.failure_message
|
213
224
|
end
|
214
225
|
end
|
215
226
|
|
@@ -236,10 +247,6 @@ module Capybara
|
|
236
247
|
def failure_message_when_negated
|
237
248
|
"expected #{@window.inspect} not to become closed after #{@wait_time} seconds"
|
238
249
|
end
|
239
|
-
|
240
|
-
# RSpec 2 compatibility:
|
241
|
-
alias_method :failure_message_for_should, :failure_message
|
242
|
-
alias_method :failure_message_for_should_not, :failure_message_when_negated
|
243
250
|
end
|
244
251
|
|
245
252
|
# RSpec matcher for whether the element(s) matching a given selector exist
|
@@ -265,107 +272,109 @@ module Capybara
|
|
265
272
|
def match_selector(*args, &optional_filter_block)
|
266
273
|
MatchSelector.new(*args, &optional_filter_block)
|
267
274
|
end
|
268
|
-
# defined_negated_matcher was added in RSpec 3.1 - it's syntactic sugar only since a user can do
|
269
|
-
# expect(page).not_to match_selector, so not sure we really need to support not_match_selector for prior to RSpec 3.1
|
270
|
-
::RSpec::Matchers.define_negated_matcher :not_match_selector, :match_selector if defined?(::RSpec::Expectations::Version) && (Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.1'))
|
271
|
-
|
272
275
|
|
273
276
|
# RSpec matcher for whether elements(s) matching a given xpath selector exist
|
274
277
|
# See {Capybara::Node::Matchers#has_xpath?}
|
275
|
-
def have_xpath(xpath, options
|
278
|
+
def have_xpath(xpath, **options, &optional_filter_block)
|
276
279
|
HaveSelector.new(:xpath, xpath, options, &optional_filter_block)
|
277
280
|
end
|
278
281
|
|
279
282
|
# RSpec matcher for whether the current element matches a given xpath selector
|
280
|
-
def match_xpath(xpath, options
|
283
|
+
def match_xpath(xpath, **options, &optional_filter_block)
|
281
284
|
MatchSelector.new(:xpath, xpath, options, &optional_filter_block)
|
282
285
|
end
|
283
286
|
|
284
287
|
# RSpec matcher for whether elements(s) matching a given css selector exist
|
285
288
|
# See {Capybara::Node::Matchers#has_css?}
|
286
|
-
def have_css(css, options
|
289
|
+
def have_css(css, **options, &optional_filter_block)
|
287
290
|
HaveSelector.new(:css, css, options, &optional_filter_block)
|
288
291
|
end
|
289
292
|
|
290
293
|
# RSpec matcher for whether the current element matches a given css selector
|
291
|
-
def match_css(css, options
|
294
|
+
def match_css(css, **options, &optional_filter_block)
|
292
295
|
MatchSelector.new(:css, css, options, &optional_filter_block)
|
293
296
|
end
|
294
297
|
|
295
|
-
# RSpec matcher for text
|
298
|
+
# RSpec matcher for text content
|
296
299
|
# See {Capybara::SessionMatchers#assert_text}
|
297
300
|
def have_text(*args)
|
298
301
|
HaveText.new(*args)
|
299
302
|
end
|
300
303
|
alias_method :have_content, :have_text
|
301
304
|
|
302
|
-
def have_title(title, options
|
305
|
+
def have_title(title, **options)
|
303
306
|
HaveTitle.new(title, options)
|
304
307
|
end
|
305
308
|
|
306
309
|
# RSpec matcher for the current path
|
307
310
|
# See {Capybara::SessionMatchers#assert_current_path}
|
308
|
-
def have_current_path(path, options
|
311
|
+
def have_current_path(path, **options)
|
309
312
|
HaveCurrentPath.new(path, options)
|
310
313
|
end
|
311
314
|
|
312
315
|
# RSpec matcher for links
|
313
316
|
# See {Capybara::Node::Matchers#has_link?}
|
314
|
-
def have_link(locator=nil, options
|
315
|
-
locator, options = nil, locator if locator.is_a? Hash
|
317
|
+
def have_link(locator = nil, **options, &optional_filter_block)
|
316
318
|
HaveSelector.new(:link, locator, options, &optional_filter_block)
|
317
319
|
end
|
318
320
|
|
319
321
|
# RSpec matcher for buttons
|
320
322
|
# See {Capybara::Node::Matchers#has_button?}
|
321
|
-
def have_button(locator=nil, options
|
322
|
-
locator, options = nil, locator if locator.is_a? Hash
|
323
|
+
def have_button(locator = nil, **options, &optional_filter_block)
|
323
324
|
HaveSelector.new(:button, locator, options, &optional_filter_block)
|
324
325
|
end
|
325
326
|
|
326
327
|
# RSpec matcher for links
|
327
328
|
# See {Capybara::Node::Matchers#has_field?}
|
328
|
-
def have_field(locator=nil, options
|
329
|
-
locator, options = nil, locator if locator.is_a? Hash
|
329
|
+
def have_field(locator = nil, **options, &optional_filter_block)
|
330
330
|
HaveSelector.new(:field, locator, options, &optional_filter_block)
|
331
331
|
end
|
332
332
|
|
333
333
|
# RSpec matcher for checked fields
|
334
334
|
# See {Capybara::Node::Matchers#has_checked_field?}
|
335
|
-
def have_checked_field(locator=nil, options
|
336
|
-
locator, options = nil, locator if locator.is_a? Hash
|
335
|
+
def have_checked_field(locator = nil, **options, &optional_filter_block)
|
337
336
|
HaveSelector.new(:field, locator, options.merge(checked: true), &optional_filter_block)
|
338
337
|
end
|
339
338
|
|
340
339
|
# RSpec matcher for unchecked fields
|
341
340
|
# See {Capybara::Node::Matchers#has_unchecked_field?}
|
342
|
-
def have_unchecked_field(locator=nil, options
|
343
|
-
locator, options = nil, locator if locator.is_a? Hash
|
341
|
+
def have_unchecked_field(locator = nil, **options, &optional_filter_block)
|
344
342
|
HaveSelector.new(:field, locator, options.merge(unchecked: true), &optional_filter_block)
|
345
343
|
end
|
346
344
|
|
347
345
|
# RSpec matcher for select elements
|
348
346
|
# See {Capybara::Node::Matchers#has_select?}
|
349
|
-
def have_select(locator=nil, options
|
350
|
-
locator, options = nil, locator if locator.is_a? Hash
|
347
|
+
def have_select(locator = nil, **options, &optional_filter_block)
|
351
348
|
HaveSelector.new(:select, locator, options, &optional_filter_block)
|
352
349
|
end
|
353
350
|
|
354
351
|
# RSpec matcher for table elements
|
355
352
|
# See {Capybara::Node::Matchers#has_table?}
|
356
|
-
def have_table(locator=nil, options
|
357
|
-
locator, options = nil, locator if locator.is_a? Hash
|
353
|
+
def have_table(locator = nil, **options, &optional_filter_block)
|
358
354
|
HaveSelector.new(:table, locator, options, &optional_filter_block)
|
359
355
|
end
|
360
356
|
|
357
|
+
%w[selector css xpath text title current_path link button field checked_field unchecked_field select table].each do |matcher_type|
|
358
|
+
define_method "have_no_#{matcher_type}" do |*args, &optional_filter_block|
|
359
|
+
NegatedMatcher.new(send("have_#{matcher_type}", *args, &optional_filter_block))
|
360
|
+
end
|
361
|
+
end
|
362
|
+
alias_method :have_no_content, :have_no_text
|
363
|
+
|
364
|
+
%w[selector css xpath].each do |matcher_type|
|
365
|
+
define_method "not_match_#{matcher_type}" do |*args, &optional_filter_block|
|
366
|
+
NegatedMatcher.new(send("match_#{matcher_type}", *args, &optional_filter_block))
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
361
370
|
##
|
362
371
|
# Wait for window to become closed.
|
363
372
|
# @example
|
364
373
|
# expect(window).to become_closed(wait: 0.8)
|
365
374
|
# @param options [Hash] optional param
|
366
375
|
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum wait time
|
367
|
-
def become_closed(options
|
376
|
+
def become_closed(**options)
|
368
377
|
BecomeClosed.new(options)
|
369
378
|
end
|
370
379
|
end
|
371
|
-
end
|
380
|
+
end
|
data/lib/capybara/rspec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'rspec/core'
|
3
4
|
require 'capybara/dsl'
|
4
5
|
require 'capybara/rspec/matchers'
|
@@ -6,14 +7,9 @@ require 'capybara/rspec/features'
|
|
6
7
|
require 'capybara/rspec/matcher_proxies'
|
7
8
|
|
8
9
|
RSpec.configure do |config|
|
9
|
-
config.include Capybara::DSL, :
|
10
|
-
config.include Capybara::RSpecMatchers, :
|
11
|
-
config.include Capybara::RSpecMatchers, :
|
12
|
-
|
13
|
-
# A work-around to support accessing the current example that works in both
|
14
|
-
# RSpec 2 and RSpec 3.
|
15
|
-
fetch_current_example = RSpec.respond_to?(:current_example) ?
|
16
|
-
proc { RSpec.current_example } : proc { |context| context.example }
|
10
|
+
config.include Capybara::DSL, type: :feature
|
11
|
+
config.include Capybara::RSpecMatchers, type: :feature
|
12
|
+
config.include Capybara::RSpecMatchers, type: :view
|
17
13
|
|
18
14
|
# The before and after blocks must run instantaneously, because Capybara
|
19
15
|
# might not actually be used in all examples where it's included.
|
@@ -26,10 +22,9 @@ RSpec.configure do |config|
|
|
26
22
|
|
27
23
|
config.before do
|
28
24
|
if self.class.include?(Capybara::DSL)
|
29
|
-
example =
|
25
|
+
example = RSpec.current_example
|
30
26
|
Capybara.current_driver = Capybara.javascript_driver if example.metadata[:js]
|
31
27
|
Capybara.current_driver = example.metadata[:driver] if example.metadata[:driver]
|
32
28
|
end
|
33
29
|
end
|
34
30
|
end
|
35
|
-
|
@@ -2,24 +2,19 @@ module Capybara
|
|
2
2
|
class Selector
|
3
3
|
class CSS
|
4
4
|
def self.escape(str)
|
5
|
-
out = String.new("")
|
6
5
|
value = str.dup
|
6
|
+
out = "".dup
|
7
7
|
out << value.slice!(0...1) if value =~ /^[-_]/
|
8
|
-
out <<
|
9
|
-
|
10
|
-
else
|
11
|
-
escape_char(value.slice!(0...1))
|
12
|
-
end
|
13
|
-
out << value.gsub(/[^a-zA-Z0-9_-]/) {|c| escape_char c}
|
8
|
+
out << (value[0] =~ NMSTART ? value.slice!(0...1) : escape_char(value.slice!(0...1)))
|
9
|
+
out << value.gsub(/[^a-zA-Z0-9_-]/) { |c| escape_char c }
|
14
10
|
out
|
15
11
|
end
|
16
12
|
|
17
13
|
def self.escape_char(c)
|
18
|
-
|
19
|
-
"\\#{c}"
|
14
|
+
c =~ %r{[ -/:-~]} ? "\\#{c}" : format("\\%06x", c.ord)
|
20
15
|
end
|
21
16
|
|
22
|
-
S = '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
|
17
|
+
S = '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'.freeze
|
23
18
|
H = /[0-9a-fA-F]/
|
24
19
|
UNICODE = /\\#{H}{1,6}[ \t\r\n\f]?/
|
25
20
|
NONASCII = /[#{S}]/
|
@@ -27,4 +22,4 @@ module Capybara
|
|
27
22
|
NMSTART = /[_a-zA-Z]|#{NONASCII}|#{ESCAPE}/
|
28
23
|
end
|
29
24
|
end
|
30
|
-
end
|
25
|
+
end
|
@@ -1,20 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'capybara/selector/filters/node_filter'
|
3
4
|
require 'capybara/selector/filters/expression_filter'
|
4
|
-
|
5
|
-
module Capybara
|
6
|
-
class Selector
|
7
|
-
def self.const_missing(const_name)
|
8
|
-
case const_name
|
9
|
-
when :Filter
|
10
|
-
warn "DEPRECATED: Capybara::Selector::Filter is deprecated, please use Capybara::Selector::Filters::NodeFilter instead"
|
11
|
-
Filters::NodeFilter
|
12
|
-
when :ExpressionFilter
|
13
|
-
warn "DEPRECATED: Capybara::Selector::ExpressionFilter is deprecated, please use Capybara::Selector::Filters::ExpressionFilter instead"
|
14
|
-
Filters::ExpressionFilter
|
15
|
-
else
|
16
|
-
super
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'capybara/selector/filter'
|
3
4
|
|
4
5
|
module Capybara
|
@@ -24,14 +25,10 @@ module Capybara
|
|
24
25
|
descriptions.push block
|
25
26
|
end
|
26
27
|
|
27
|
-
def description(options
|
28
|
-
|
29
|
-
filters.each do |name, filter|
|
30
|
-
options_with_defaults[name] = filter.default if filter.default? && !options_with_defaults.has_key?(name)
|
31
|
-
end
|
32
|
-
|
28
|
+
def description(**options)
|
29
|
+
opts = options_with_defaults(options)
|
33
30
|
@descriptions.map do |desc|
|
34
|
-
desc.call(
|
31
|
+
desc.call(opts).to_s
|
35
32
|
end.join
|
36
33
|
end
|
37
34
|
|
@@ -44,13 +41,12 @@ module Capybara
|
|
44
41
|
end
|
45
42
|
|
46
43
|
def expression_filters
|
47
|
-
filters.select { |_n, f| f.nil? || f.is_a?(Filters::ExpressionFilter)
|
44
|
+
filters.select { |_n, f| f.nil? || f.is_a?(Filters::ExpressionFilter) }.freeze
|
48
45
|
end
|
49
46
|
|
50
47
|
class << self
|
51
|
-
|
52
48
|
def all
|
53
|
-
@filter_sets ||= {}
|
49
|
+
@filter_sets ||= {} # rubocop:disable Naming/MemoizedInstanceVariableName
|
54
50
|
end
|
55
51
|
|
56
52
|
def add(name, &block)
|
@@ -62,13 +58,20 @@ module Capybara
|
|
62
58
|
end
|
63
59
|
end
|
64
60
|
|
65
|
-
|
61
|
+
private
|
62
|
+
|
63
|
+
def options_with_defaults(options)
|
64
|
+
options = options.dup
|
65
|
+
filters.each do |name, filter|
|
66
|
+
options[name] = filter.default if filter.default? && !options.key?(name)
|
67
|
+
end
|
68
|
+
options
|
69
|
+
end
|
66
70
|
|
67
|
-
def add_filter(name, filter_class, *
|
68
|
-
|
69
|
-
types_and_options.each { |k| options[k] = true}
|
71
|
+
def add_filter(name, filter_class, *types, **options, &block)
|
72
|
+
types.each { |k| options[k] = true }
|
70
73
|
filters[name] = filter_class.new(name, block, options)
|
71
74
|
end
|
72
75
|
end
|
73
76
|
end
|
74
|
-
end
|
77
|
+
end
|
@@ -1,17 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Capybara
|
3
4
|
class Selector
|
4
5
|
module Filters
|
5
6
|
class Base
|
6
|
-
def initialize(name, block, options
|
7
|
+
def initialize(name, block, **options)
|
7
8
|
@name = name
|
8
9
|
@block = block
|
9
10
|
@options = options
|
10
|
-
@options[:valid_values] = [true,false] if options[:boolean]
|
11
|
+
@options[:valid_values] = [true, false] if options[:boolean]
|
11
12
|
end
|
12
13
|
|
13
14
|
def default?
|
14
|
-
@options.
|
15
|
+
@options.key?(:default)
|
15
16
|
end
|
16
17
|
|
17
18
|
def default
|
@@ -19,13 +20,13 @@ module Capybara
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def skip?(value)
|
22
|
-
@options.
|
23
|
+
@options.key?(:skip_if) && value == @options[:skip_if]
|
23
24
|
end
|
24
25
|
|
25
|
-
|
26
|
+
private
|
26
27
|
|
27
28
|
def valid_value?(value)
|
28
|
-
!@options.
|
29
|
+
!@options.key?(:valid_values) || Array(@options[:valid_values]).include?(value)
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'capybara/selector/filters/base'
|
3
4
|
|
4
5
|
module Capybara
|
@@ -7,34 +8,16 @@ module Capybara
|
|
7
8
|
class ExpressionFilter < Base
|
8
9
|
def apply_filter(expr, value)
|
9
10
|
return expr if skip?(value)
|
10
|
-
|
11
|
-
if !valid_value?(value)
|
12
|
-
msg = "Invalid value #{value.inspect} passed to expression filter #{@name} - "
|
13
|
-
if default?
|
14
|
-
warn msg + "defaulting to #{default}"
|
15
|
-
value = default
|
16
|
-
else
|
17
|
-
warn msg + "skipping"
|
18
|
-
return expr
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
11
|
+
raise "ArgumentError", "Invalid value #{value.inspect} passed to expression filter #{@name}" unless valid_value?(value)
|
22
12
|
@block.call(expr, value)
|
23
13
|
end
|
24
14
|
end
|
25
15
|
|
26
16
|
class IdentityExpressionFilter < ExpressionFilter
|
27
|
-
def initialize
|
28
|
-
end
|
29
|
-
|
30
|
-
def default?
|
31
|
-
false
|
32
|
-
end
|
33
|
-
|
34
|
-
def apply_filter(expr, _value)
|
35
|
-
return expr
|
36
|
-
end
|
17
|
+
def initialize; end
|
18
|
+
def default?; false; end
|
19
|
+
def apply_filter(expr, _value); expr; end
|
37
20
|
end
|
38
21
|
end
|
39
22
|
end
|
40
|
-
end
|
23
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'capybara/selector/filters/base'
|
3
4
|
|
4
5
|
module Capybara
|
@@ -7,18 +8,7 @@ module Capybara
|
|
7
8
|
class NodeFilter < Base
|
8
9
|
def matches?(node, value)
|
9
10
|
return true if skip?(value)
|
10
|
-
|
11
|
-
if !valid_value?(value)
|
12
|
-
msg = "Invalid value #{value.inspect} passed to filter #{@name} - "
|
13
|
-
if default?
|
14
|
-
warn msg + "defaulting to #{default}"
|
15
|
-
value = default
|
16
|
-
else
|
17
|
-
warn msg + "skipping"
|
18
|
-
return true
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
11
|
+
raise ArgumentError, "Invalid value #{value.inspect} passed to filter #{@name}" unless valid_value?(value)
|
22
12
|
@block.call(node, value)
|
23
13
|
end
|
24
14
|
end
|