capybara 3.30.0 → 3.35.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +153 -13
- data/README.md +9 -4
- data/lib/capybara.rb +18 -8
- data/lib/capybara/config.rb +4 -6
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +4 -0
- data/lib/capybara/dsl.rb +10 -2
- data/lib/capybara/helpers.rb +25 -1
- data/lib/capybara/minitest.rb +232 -144
- data/lib/capybara/minitest/spec.rb +156 -97
- data/lib/capybara/node/actions.rb +16 -21
- data/lib/capybara/node/base.rb +6 -6
- data/lib/capybara/node/element.rb +14 -13
- data/lib/capybara/node/finders.rb +12 -7
- data/lib/capybara/node/matchers.rb +36 -27
- data/lib/capybara/node/simple.rb +6 -2
- data/lib/capybara/queries/ancestor_query.rb +1 -1
- data/lib/capybara/queries/base_query.rb +2 -1
- data/lib/capybara/queries/current_path_query.rb +14 -4
- data/lib/capybara/queries/selector_query.rb +40 -18
- data/lib/capybara/queries/sibling_query.rb +1 -1
- data/lib/capybara/queries/style_query.rb +1 -1
- data/lib/capybara/queries/text_query.rb +7 -1
- data/lib/capybara/rack_test/browser.rb +9 -3
- data/lib/capybara/rack_test/driver.rb +1 -0
- data/lib/capybara/rack_test/form.rb +1 -1
- data/lib/capybara/rack_test/node.rb +35 -10
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +18 -12
- data/lib/capybara/registrations/patches/puma_ssl.rb +3 -1
- data/lib/capybara/registrations/servers.rb +3 -2
- data/lib/capybara/result.rb +35 -15
- data/lib/capybara/rspec.rb +2 -0
- data/lib/capybara/rspec/matcher_proxies.rb +5 -5
- data/lib/capybara/rspec/matchers.rb +33 -32
- data/lib/capybara/rspec/matchers/base.rb +12 -6
- data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
- data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
- data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +15 -7
- data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
- data/lib/capybara/rspec/matchers/have_text.rb +3 -3
- data/lib/capybara/rspec/matchers/have_title.rb +2 -2
- data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
- data/lib/capybara/rspec/matchers/match_style.rb +7 -2
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +2 -1
- data/lib/capybara/selector.rb +14 -3
- data/lib/capybara/selector/builders/css_builder.rb +1 -1
- data/lib/capybara/selector/builders/xpath_builder.rb +3 -1
- data/lib/capybara/selector/definition.rb +11 -9
- data/lib/capybara/selector/definition/button.rb +26 -14
- data/lib/capybara/selector/definition/css.rb +1 -1
- data/lib/capybara/selector/definition/datalist_input.rb +1 -1
- data/lib/capybara/selector/definition/element.rb +2 -1
- data/lib/capybara/selector/definition/fillable_field.rb +1 -1
- data/lib/capybara/selector/definition/label.rb +2 -2
- data/lib/capybara/selector/definition/link.rb +8 -0
- data/lib/capybara/selector/definition/select.rb +32 -13
- data/lib/capybara/selector/definition/table.rb +1 -1
- data/lib/capybara/selector/definition/table_row.rb +2 -2
- data/lib/capybara/selector/filter_set.rb +2 -2
- data/lib/capybara/selector/selector.rb +9 -1
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
- data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +1 -1
- data/lib/capybara/selenium/driver.rb +52 -7
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +10 -12
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -11
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +3 -3
- data/lib/capybara/selenium/extensions/find.rb +4 -4
- data/lib/capybara/selenium/extensions/html5_drag.rb +24 -8
- data/lib/capybara/selenium/extensions/scroll.rb +8 -10
- data/lib/capybara/selenium/logger_suppressor.rb +8 -2
- data/lib/capybara/selenium/node.rb +96 -16
- data/lib/capybara/selenium/nodes/chrome_node.rb +27 -16
- data/lib/capybara/selenium/nodes/edge_node.rb +1 -1
- data/lib/capybara/selenium/nodes/firefox_node.rb +9 -4
- data/lib/capybara/selenium/nodes/safari_node.rb +1 -1
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +4 -4
- data/lib/capybara/selenium/patches/logs.rb +7 -9
- data/lib/capybara/server/animation_disabler.rb +8 -3
- data/lib/capybara/server/middleware.rb +4 -2
- data/lib/capybara/session.rb +53 -29
- data/lib/capybara/session/config.rb +3 -1
- data/lib/capybara/session/matchers.rb +11 -11
- data/lib/capybara/spec/public/test.js +64 -7
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
- data/lib/capybara/spec/session/all_spec.rb +45 -5
- data/lib/capybara/spec/session/assert_text_spec.rb +5 -5
- data/lib/capybara/spec/session/check_spec.rb +6 -0
- data/lib/capybara/spec/session/click_button_spec.rb +11 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
- data/lib/capybara/spec/session/current_url_spec.rb +11 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
- data/lib/capybara/spec/session/find_spec.rb +11 -8
- data/lib/capybara/spec/session/has_button_spec.rb +51 -0
- data/lib/capybara/spec/session/has_css_spec.rb +14 -10
- data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
- data/lib/capybara/spec/session/has_field_spec.rb +16 -0
- data/lib/capybara/spec/session/has_select_spec.rb +32 -4
- data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
- data/lib/capybara/spec/session/has_text_spec.rb +5 -12
- data/lib/capybara/spec/session/html_spec.rb +1 -1
- data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
- data/lib/capybara/spec/session/node_spec.rb +169 -33
- data/lib/capybara/spec/session/refresh_spec.rb +2 -1
- data/lib/capybara/spec/session/save_page_spec.rb +4 -4
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_spec.rb +8 -8
- data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
- data/lib/capybara/spec/spec_helper.rb +13 -14
- data/lib/capybara/spec/test_app.rb +23 -21
- data/lib/capybara/spec/views/form.erb +36 -3
- data/lib/capybara/spec/views/with_animation.erb +8 -0
- data/lib/capybara/spec/views/with_dragula.erb +3 -1
- data/lib/capybara/spec/views/with_html.erb +2 -2
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +3 -0
- data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +3 -7
- data/spec/basic_node_spec.rb +9 -8
- data/spec/capybara_spec.rb +1 -1
- data/spec/dsl_spec.rb +14 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
- data/spec/minitest_spec.rb +3 -2
- data/spec/rack_test_spec.rb +28 -6
- data/spec/regexp_dissassembler_spec.rb +0 -4
- data/spec/result_spec.rb +40 -29
- data/spec/rspec/features_spec.rb +3 -1
- data/spec/rspec/scenarios_spec.rb +4 -0
- data/spec/rspec/shared_spec_matchers.rb +63 -51
- data/spec/rspec_spec.rb +4 -0
- data/spec/selector_spec.rb +17 -2
- data/spec/selenium_spec_chrome.rb +45 -21
- data/spec/selenium_spec_chrome_remote.rb +7 -1
- data/spec/selenium_spec_firefox.rb +15 -13
- data/spec/server_spec.rb +60 -49
- data/spec/shared_selenium_node.rb +18 -0
- data/spec/shared_selenium_session.rb +98 -7
- data/spec/spec_helper.rb +1 -1
- metadata +50 -14
- data/lib/capybara/spec/session/source_spec.rb +0 -0
|
@@ -8,6 +8,7 @@ class Capybara::RackTest::Browser
|
|
|
8
8
|
|
|
9
9
|
def initialize(driver)
|
|
10
10
|
@driver = driver
|
|
11
|
+
@current_fragment = nil
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def app
|
|
@@ -30,7 +31,9 @@ class Capybara::RackTest::Browser
|
|
|
30
31
|
|
|
31
32
|
def submit(method, path, attributes)
|
|
32
33
|
path = request_path if path.nil? || path.empty?
|
|
33
|
-
|
|
34
|
+
uri = build_uri(path)
|
|
35
|
+
uri.query = '' if method.to_s.casecmp('get').zero?
|
|
36
|
+
process_and_follow_redirects(method, uri.to_s, attributes, 'HTTP_REFERER' => current_url)
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
def follow(method, path, **attributes)
|
|
@@ -40,6 +43,7 @@ class Capybara::RackTest::Browser
|
|
|
40
43
|
end
|
|
41
44
|
|
|
42
45
|
def process_and_follow_redirects(method, path, attributes = {}, env = {})
|
|
46
|
+
@current_fragment = build_uri(path).fragment
|
|
43
47
|
process(method, path, attributes, env)
|
|
44
48
|
|
|
45
49
|
return unless driver.follow_redirects?
|
|
@@ -63,7 +67,7 @@ class Capybara::RackTest::Browser
|
|
|
63
67
|
method = method.downcase
|
|
64
68
|
new_uri = build_uri(path)
|
|
65
69
|
@current_scheme, @current_host, @current_port = new_uri.select(:scheme, :host, :port)
|
|
66
|
-
|
|
70
|
+
@current_fragment = new_uri.fragment || @current_fragment
|
|
67
71
|
reset_cache!
|
|
68
72
|
send(method, new_uri.to_s, attributes, env.merge(options[:headers] || {}))
|
|
69
73
|
end
|
|
@@ -81,7 +85,9 @@ class Capybara::RackTest::Browser
|
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
def current_url
|
|
84
|
-
last_request.url
|
|
88
|
+
uri = build_uri(last_request.url)
|
|
89
|
+
uri.fragment = @current_fragment if @current_fragment
|
|
90
|
+
uri.to_s
|
|
85
91
|
rescue Rack::Test::Error
|
|
86
92
|
''
|
|
87
93
|
end
|
|
@@ -17,6 +17,7 @@ class Capybara::RackTest::Driver < Capybara::Driver::Base
|
|
|
17
17
|
def initialize(app, **options)
|
|
18
18
|
raise ArgumentError, 'rack-test requires a rack application, but none was given' unless app
|
|
19
19
|
|
|
20
|
+
super()
|
|
20
21
|
@app = app
|
|
21
22
|
@options = DEFAULT_OPTIONS.merge(options)
|
|
22
23
|
end
|
|
@@ -6,7 +6,7 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
|
|
|
6
6
|
# That check should be based solely on the form element's 'enctype' attribute value,
|
|
7
7
|
# which should probably be provided to Rack::Test in its non-GET request methods.
|
|
8
8
|
class NilUploadedFile < Rack::Test::UploadedFile
|
|
9
|
-
def initialize
|
|
9
|
+
def initialize # rubocop:disable Lint/MissingSuper
|
|
10
10
|
@empty_file = Tempfile.new('nil_uploaded_file')
|
|
11
11
|
@empty_file.close
|
|
12
12
|
end
|
|
@@ -15,7 +15,7 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def visible_text
|
|
18
|
-
displayed_text.
|
|
18
|
+
displayed_text.squeeze(' ')
|
|
19
19
|
.gsub(/[\ \n]*\n[\ \n]*/, "\n")
|
|
20
20
|
.gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
|
|
21
21
|
.gsub(/[[:space:]&&[^\u00a0]]+\z/, '')
|
|
@@ -45,6 +45,7 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
|
45
45
|
|
|
46
46
|
if radio? then set_radio(value)
|
|
47
47
|
elsif checkbox? then set_checkbox(value)
|
|
48
|
+
elsif range? then set_range(value)
|
|
48
49
|
elsif input_field? then set_input(value)
|
|
49
50
|
elsif textarea? then native['_capybara_raw_value'] = value.to_s
|
|
50
51
|
end
|
|
@@ -76,8 +77,8 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
|
76
77
|
set(!checked?)
|
|
77
78
|
elsif tag_name == 'label'
|
|
78
79
|
click_label
|
|
79
|
-
elsif
|
|
80
|
-
toggle_details
|
|
80
|
+
elsif (details = native.xpath('.//ancestor-or-self::details').last)
|
|
81
|
+
toggle_details(details)
|
|
81
82
|
end
|
|
82
83
|
end
|
|
83
84
|
|
|
@@ -123,9 +124,18 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
|
123
124
|
alias_method "unchecked_#{meth_name}", meth_name
|
|
124
125
|
private "unchecked_#{meth_name}" # rubocop:disable Style/AccessModifierDeclarations
|
|
125
126
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
if RUBY_VERSION >= '2.7'
|
|
128
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
|
129
|
+
def #{meth_name}(...)
|
|
130
|
+
stale_check
|
|
131
|
+
method(:"unchecked_#{meth_name}").call(...)
|
|
132
|
+
end
|
|
133
|
+
METHOD
|
|
134
|
+
else
|
|
135
|
+
define_method meth_name do |*args|
|
|
136
|
+
stale_check
|
|
137
|
+
send("unchecked_#{meth_name}", *args)
|
|
138
|
+
end
|
|
129
139
|
end
|
|
130
140
|
end
|
|
131
141
|
|
|
@@ -199,6 +209,14 @@ private
|
|
|
199
209
|
end
|
|
200
210
|
end
|
|
201
211
|
|
|
212
|
+
def set_range(value) # rubocop:disable Naming/AccessorMethodName
|
|
213
|
+
min, max, step = (native['min'] || 0).to_f, (native['max'] || 100).to_f, (native['step'] || 1).to_f
|
|
214
|
+
value = value.to_f
|
|
215
|
+
value = value.clamp(min, max)
|
|
216
|
+
value = ((value - min) / step).round * step + min
|
|
217
|
+
native['value'] = value.clamp(min, max)
|
|
218
|
+
end
|
|
219
|
+
|
|
202
220
|
def set_input(value) # rubocop:disable Naming/AccessorMethodName
|
|
203
221
|
if text_or_password? && attribute_is_not_blank?(:maxlength)
|
|
204
222
|
# Browser behavior for maxlength="0" is inconsistent, so we stick with
|
|
@@ -238,11 +256,14 @@ private
|
|
|
238
256
|
labelled_control.set(!labelled_control.checked?) if checkbox_or_radio?(labelled_control)
|
|
239
257
|
end
|
|
240
258
|
|
|
241
|
-
def toggle_details
|
|
242
|
-
|
|
243
|
-
|
|
259
|
+
def toggle_details(details = nil)
|
|
260
|
+
details ||= native.xpath('.//ancestor-or-self::details').last
|
|
261
|
+
return unless details
|
|
262
|
+
|
|
263
|
+
if details.has_attribute?('open')
|
|
264
|
+
details.remove_attribute('open')
|
|
244
265
|
else
|
|
245
|
-
|
|
266
|
+
details.set_attribute('open', 'open')
|
|
246
267
|
end
|
|
247
268
|
end
|
|
248
269
|
|
|
@@ -284,6 +305,10 @@ protected
|
|
|
284
305
|
tag_name == 'textarea'
|
|
285
306
|
end
|
|
286
307
|
|
|
308
|
+
def range?
|
|
309
|
+
input_field? && type == 'range'
|
|
310
|
+
end
|
|
311
|
+
|
|
287
312
|
OPTION_OWNER_XPATH = XPath.parent(:optgroup, :select, :datalist).to_s.freeze
|
|
288
313
|
DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
|
|
289
314
|
x.parent(:fieldset)[
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Capybara
|
|
4
|
+
# @api private
|
|
5
|
+
class RegistrationContainer
|
|
6
|
+
def names
|
|
7
|
+
@registered.keys
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def [](name)
|
|
11
|
+
@registered[name]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def []=(name, value)
|
|
15
|
+
Capybara::Helpers.warn 'DEPRECATED: Directly setting drivers/servers is deprecated, please use Capybara.register_driver/register_server instead'
|
|
16
|
+
@registered[name] = value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def method_missing(method_name, *args, **options, &block)
|
|
20
|
+
if @registered.respond_to?(method_name)
|
|
21
|
+
Capybara::Helpers.warn "DEPRECATED: Calling '#{method_name}' on the drivers/servers container is deprecated without replacement"
|
|
22
|
+
# RUBY 2.6 will send an empty hash rather than nothing with **options so fix that
|
|
23
|
+
return @registered.public_send(method_name, *args, &block) if options.empty?
|
|
24
|
+
|
|
25
|
+
return @registered.public_send(method_name, *args, **options, &block)
|
|
26
|
+
end
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def respond_to_missing?(method_name, include_all)
|
|
31
|
+
@registered.respond_to?(method_name) || super
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def initialize
|
|
37
|
+
@registered = {}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def register(name, block)
|
|
41
|
+
@registered[name] = block
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -9,28 +9,34 @@ Capybara.register_driver :selenium do |app|
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
Capybara.register_driver :selenium_headless do |app|
|
|
12
|
-
Capybara::Selenium::Driver.load_selenium
|
|
13
|
-
|
|
14
|
-
browser_options.
|
|
15
|
-
|
|
12
|
+
version = Capybara::Selenium::Driver.load_selenium
|
|
13
|
+
options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
|
|
14
|
+
browser_options = ::Selenium::WebDriver::Firefox::Options.new.tap do |opts|
|
|
15
|
+
opts.add_argument '-headless'
|
|
16
|
+
end
|
|
17
|
+
Capybara::Selenium::Driver.new(app, **Hash[:browser => :firefox, options_key => browser_options])
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
Capybara.register_driver :selenium_chrome do |app|
|
|
19
|
-
Capybara::Selenium::Driver.load_selenium
|
|
21
|
+
version = Capybara::Selenium::Driver.load_selenium
|
|
22
|
+
options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
|
|
20
23
|
browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts|
|
|
21
24
|
# Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
|
|
22
|
-
opts.
|
|
25
|
+
opts.add_argument('--disable-site-isolation-trials')
|
|
23
26
|
end
|
|
24
|
-
|
|
27
|
+
|
|
28
|
+
Capybara::Selenium::Driver.new(app, **Hash[:browser => :chrome, options_key => browser_options])
|
|
25
29
|
end
|
|
26
30
|
|
|
27
31
|
Capybara.register_driver :selenium_chrome_headless do |app|
|
|
28
|
-
Capybara::Selenium::Driver.load_selenium
|
|
32
|
+
version = Capybara::Selenium::Driver.load_selenium
|
|
33
|
+
options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
|
|
29
34
|
browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts|
|
|
30
|
-
opts.
|
|
31
|
-
opts.
|
|
35
|
+
opts.add_argument('--headless')
|
|
36
|
+
opts.add_argument('--disable-gpu') if Gem.win_platform?
|
|
32
37
|
# Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
|
|
33
|
-
opts.
|
|
38
|
+
opts.add_argument('--disable-site-isolation-trials')
|
|
34
39
|
end
|
|
35
|
-
|
|
40
|
+
|
|
41
|
+
Capybara::Selenium::Driver.new(app, **Hash[:browser => :chrome, options_key => browser_options])
|
|
36
42
|
end
|
|
@@ -4,12 +4,14 @@ module Puma
|
|
|
4
4
|
module MiniSSL
|
|
5
5
|
class Socket
|
|
6
6
|
def read_nonblock(size, *_)
|
|
7
|
+
wait_states = %i[wait_readable wait_writable]
|
|
8
|
+
|
|
7
9
|
loop do
|
|
8
10
|
output = engine_read_all
|
|
9
11
|
return output if output
|
|
10
12
|
|
|
11
13
|
data = @socket.read_nonblock(size, exception: false)
|
|
12
|
-
raise IO::EAGAINWaitReadable if
|
|
14
|
+
raise IO::EAGAINWaitReadable if wait_states.include? data
|
|
13
15
|
return nil if data.nil?
|
|
14
16
|
|
|
15
17
|
@engine.inject(data)
|
|
@@ -7,7 +7,7 @@ end
|
|
|
7
7
|
Capybara.register_server :webrick do |app, port, host, **options|
|
|
8
8
|
require 'rack/handler/webrick'
|
|
9
9
|
options = { Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log.new(nil, 0) }.merge(options)
|
|
10
|
-
Rack::Handler::WEBrick.run(app, options)
|
|
10
|
+
Rack::Handler::WEBrick.run(app, **options)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
Capybara.register_server :puma do |app, port, host, **options|
|
|
@@ -28,10 +28,11 @@ Capybara.register_server :puma do |app, port, host, **options|
|
|
|
28
28
|
options = default_options.merge(options)
|
|
29
29
|
|
|
30
30
|
conf = Rack::Handler::Puma.config(app, options)
|
|
31
|
+
conf.clamp
|
|
31
32
|
events = conf.options[:Silent] ? ::Puma::Events.strings : ::Puma::Events.stdio
|
|
32
33
|
|
|
33
34
|
puma_ver = Gem::Version.new(Puma::Const::PUMA_VERSION)
|
|
34
|
-
require_relative 'patches/puma_ssl' if
|
|
35
|
+
require_relative 'patches/puma_ssl' if Gem::Requirement.new('>=4.0.0', '< 4.1.0').satisfied_by?(puma_ver)
|
|
35
36
|
|
|
36
37
|
events.log 'Capybara starting Puma...'
|
|
37
38
|
events.log "* Version #{Puma::Const::PUMA_VERSION} , codename: #{Puma::Const::CODE_NAME}"
|
data/lib/capybara/result.rb
CHANGED
|
@@ -31,6 +31,7 @@ module Capybara
|
|
|
31
31
|
@filter_errors = []
|
|
32
32
|
@results_enum = lazy_select_elements { |node| query.matches_filters?(node, @filter_errors) }
|
|
33
33
|
@query = query
|
|
34
|
+
@allow_reload = false
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
def_delegators :full_results, :size, :length, :last, :values_at, :inspect, :sample
|
|
@@ -38,12 +39,12 @@ module Capybara
|
|
|
38
39
|
alias index find_index
|
|
39
40
|
|
|
40
41
|
def each(&block)
|
|
41
|
-
return enum_for(:each) unless
|
|
42
|
+
return enum_for(:each) unless block
|
|
42
43
|
|
|
43
44
|
@result_cache.each(&block)
|
|
44
45
|
loop do
|
|
45
46
|
next_result = @results_enum.next
|
|
46
|
-
|
|
47
|
+
add_to_cache(next_result)
|
|
47
48
|
yield next_result
|
|
48
49
|
end
|
|
49
50
|
self
|
|
@@ -53,13 +54,18 @@ module Capybara
|
|
|
53
54
|
idx, length = args
|
|
54
55
|
max_idx = case idx
|
|
55
56
|
when Integer
|
|
56
|
-
if
|
|
57
|
-
length.nil? ? idx : idx + length - 1
|
|
58
|
-
else
|
|
57
|
+
if idx.negative?
|
|
59
58
|
nil
|
|
59
|
+
else
|
|
60
|
+
length.nil? ? idx : idx + length - 1
|
|
60
61
|
end
|
|
61
62
|
when Range
|
|
62
|
-
|
|
63
|
+
# idx.max is broken with beginless ranges
|
|
64
|
+
# idx.end && idx.max # endless range will have end == nil
|
|
65
|
+
max = idx.end
|
|
66
|
+
max = nil if max&.negative?
|
|
67
|
+
max -= 1 if max && idx.exclude_end?
|
|
68
|
+
max
|
|
63
69
|
end
|
|
64
70
|
|
|
65
71
|
if max_idx.nil?
|
|
@@ -85,16 +91,14 @@ module Capybara
|
|
|
85
91
|
return load_up_to(count + 1) <=> count
|
|
86
92
|
end
|
|
87
93
|
|
|
88
|
-
if min && (min = Integer(min))
|
|
89
|
-
return -1 if load_up_to(min) < min
|
|
90
|
-
end
|
|
94
|
+
return -1 if min && (min = Integer(min)) && (load_up_to(min) < min)
|
|
91
95
|
|
|
92
|
-
if max && (max = Integer(max))
|
|
93
|
-
return 1 if load_up_to(max + 1) > max
|
|
94
|
-
end
|
|
96
|
+
return 1 if max && (max = Integer(max)) && (load_up_to(max + 1) > max)
|
|
95
97
|
|
|
96
98
|
if between
|
|
97
|
-
min, max = between.
|
|
99
|
+
min, max = (between.begin && between.min) || 1, between.end
|
|
100
|
+
max -= 1 if max && between.exclude_end?
|
|
101
|
+
|
|
98
102
|
size = load_up_to(max ? max + 1 : min)
|
|
99
103
|
return size <=> min unless between.include?(size)
|
|
100
104
|
end
|
|
@@ -130,13 +134,26 @@ module Capybara
|
|
|
130
134
|
@elements.length
|
|
131
135
|
end
|
|
132
136
|
|
|
137
|
+
##
|
|
138
|
+
# @api private
|
|
139
|
+
#
|
|
140
|
+
def allow_reload!
|
|
141
|
+
@allow_reload = true
|
|
142
|
+
self
|
|
143
|
+
end
|
|
144
|
+
|
|
133
145
|
private
|
|
134
146
|
|
|
147
|
+
def add_to_cache(elem)
|
|
148
|
+
elem.allow_reload!(@result_cache.size) if @allow_reload
|
|
149
|
+
@result_cache << elem
|
|
150
|
+
end
|
|
151
|
+
|
|
135
152
|
def load_up_to(num)
|
|
136
153
|
loop do
|
|
137
154
|
break if @result_cache.size >= num
|
|
138
155
|
|
|
139
|
-
@
|
|
156
|
+
add_to_cache(@results_enum.next)
|
|
140
157
|
end
|
|
141
158
|
@result_cache.size
|
|
142
159
|
end
|
|
@@ -150,10 +167,13 @@ module Capybara
|
|
|
150
167
|
@rest ||= @elements - full_results
|
|
151
168
|
end
|
|
152
169
|
|
|
153
|
-
if
|
|
170
|
+
if RUBY_PLATFORM == 'java'
|
|
154
171
|
# JRuby < 9.2.8.0 has an issue with lazy enumerators which
|
|
155
172
|
# causes a concurrency issue with network requests here
|
|
156
173
|
# https://github.com/jruby/jruby/issues/4212
|
|
174
|
+
# while JRuby >= 9.2.8.0 leaks threads when using lazy enumerators
|
|
175
|
+
# https://github.com/teamcapybara/capybara/issues/2349
|
|
176
|
+
# so disable the use and JRuby users will need to pay a performance penalty
|
|
157
177
|
def lazy_select_elements(&block)
|
|
158
178
|
@elements.select(&block).to_enum # non-lazy evaluation
|
|
159
179
|
end
|
data/lib/capybara/rspec.rb
CHANGED
|
@@ -9,6 +9,8 @@ require 'capybara/rspec/matcher_proxies'
|
|
|
9
9
|
RSpec.configure do |config|
|
|
10
10
|
config.include Capybara::DSL, type: :feature
|
|
11
11
|
config.include Capybara::RSpecMatchers, type: :feature
|
|
12
|
+
config.include Capybara::DSL, type: :system
|
|
13
|
+
config.include Capybara::RSpecMatchers, type: :system
|
|
12
14
|
config.include Capybara::RSpecMatchers, type: :view
|
|
13
15
|
|
|
14
16
|
# The before and after blocks must run instantaneously, because Capybara
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
module Capybara
|
|
4
4
|
module RSpecMatcherProxies
|
|
5
|
-
def all(*args, &block)
|
|
5
|
+
def all(*args, **kwargs, &block)
|
|
6
6
|
if defined?(::RSpec::Matchers::BuiltIn::All) && args.first.respond_to?(:matches?)
|
|
7
7
|
::RSpec::Matchers::BuiltIn::All.new(*args)
|
|
8
8
|
else
|
|
9
|
-
find_all(*args, &block)
|
|
9
|
+
find_all(*args, **kwargs, &block)
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def within(*args, &block)
|
|
14
|
-
if
|
|
15
|
-
within_element(*args, &block)
|
|
13
|
+
def within(*args, **kwargs, &block)
|
|
14
|
+
if block
|
|
15
|
+
within_element(*args, **kwargs, &block)
|
|
16
16
|
else
|
|
17
17
|
be_within(*args)
|
|
18
18
|
end
|
|
@@ -15,45 +15,45 @@ module Capybara
|
|
|
15
15
|
# RSpec matcher for whether the element(s) matching a given selector exist.
|
|
16
16
|
#
|
|
17
17
|
# @see Capybara::Node::Matchers#assert_selector
|
|
18
|
-
def have_selector(*args, &optional_filter_block)
|
|
19
|
-
Matchers::HaveSelector.new(*args, &optional_filter_block)
|
|
18
|
+
def have_selector(*args, **kw_args, &optional_filter_block)
|
|
19
|
+
Matchers::HaveSelector.new(*args, **kw_args, &optional_filter_block)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
# RSpec matcher for whether the element(s) matching a group of selectors exist.
|
|
23
23
|
#
|
|
24
24
|
# @see Capybara::Node::Matchers#assert_all_of_selectors
|
|
25
|
-
def have_all_of_selectors(*args, &optional_filter_block)
|
|
26
|
-
Matchers::HaveAllSelectors.new(*args, &optional_filter_block)
|
|
25
|
+
def have_all_of_selectors(*args, **kw_args, &optional_filter_block)
|
|
26
|
+
Matchers::HaveAllSelectors.new(*args, **kw_args, &optional_filter_block)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
# RSpec matcher for whether no element(s) matching a group of selectors exist.
|
|
30
30
|
#
|
|
31
31
|
# @see Capybara::Node::Matchers#assert_none_of_selectors
|
|
32
|
-
def have_none_of_selectors(*args, &optional_filter_block)
|
|
33
|
-
Matchers::HaveNoSelectors.new(*args, &optional_filter_block)
|
|
32
|
+
def have_none_of_selectors(*args, **kw_args, &optional_filter_block)
|
|
33
|
+
Matchers::HaveNoSelectors.new(*args, **kw_args, &optional_filter_block)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
# RSpec matcher for whether the element(s) matching any of a group of selectors exist.
|
|
37
37
|
#
|
|
38
38
|
# @see Capybara::Node::Matchers#assert_any_of_selectors
|
|
39
|
-
def have_any_of_selectors(*args, &optional_filter_block)
|
|
40
|
-
Matchers::HaveAnySelectors.new(*args, &optional_filter_block)
|
|
39
|
+
def have_any_of_selectors(*args, **kw_args, &optional_filter_block)
|
|
40
|
+
Matchers::HaveAnySelectors.new(*args, **kw_args, &optional_filter_block)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
# RSpec matcher for whether the current element matches a given selector.
|
|
44
44
|
#
|
|
45
45
|
# @see Capybara::Node::Matchers#assert_matches_selector
|
|
46
|
-
def match_selector(*args, &optional_filter_block)
|
|
47
|
-
Matchers::MatchSelector.new(*args, &optional_filter_block)
|
|
46
|
+
def match_selector(*args, **kw_args, &optional_filter_block)
|
|
47
|
+
Matchers::MatchSelector.new(*args, **kw_args, &optional_filter_block)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
%i[css xpath].each do |selector|
|
|
51
51
|
define_method "have_#{selector}" do |expr, **options, &optional_filter_block|
|
|
52
|
-
Matchers::HaveSelector.new(selector, expr, options, &optional_filter_block)
|
|
52
|
+
Matchers::HaveSelector.new(selector, expr, **options, &optional_filter_block)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
define_method "match_#{selector}" do |expr, **options, &optional_filter_block|
|
|
56
|
-
Matchers::MatchSelector.new(selector, expr, options, &optional_filter_block)
|
|
56
|
+
Matchers::MatchSelector.new(selector, expr, **options, &optional_filter_block)
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -79,7 +79,7 @@ module Capybara
|
|
|
79
79
|
|
|
80
80
|
%i[link button field select table].each do |selector|
|
|
81
81
|
define_method "have_#{selector}" do |locator = nil, **options, &optional_filter_block|
|
|
82
|
-
Matchers::HaveSelector.new(selector, locator, options, &optional_filter_block)
|
|
82
|
+
Matchers::HaveSelector.new(selector, locator, **options, &optional_filter_block)
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
|
|
@@ -94,7 +94,7 @@ module Capybara
|
|
|
94
94
|
# @see Capybara::Node::Matchers#has_button?
|
|
95
95
|
|
|
96
96
|
# @!method have_field(locator = nil, **options, &optional_filter_block)
|
|
97
|
-
# RSpec matcher for
|
|
97
|
+
# RSpec matcher for form fields.
|
|
98
98
|
#
|
|
99
99
|
# @see Capybara::Node::Matchers#has_field?
|
|
100
100
|
|
|
@@ -110,7 +110,7 @@ module Capybara
|
|
|
110
110
|
|
|
111
111
|
%i[checked unchecked].each do |state|
|
|
112
112
|
define_method "have_#{state}_field" do |locator = nil, **options, &optional_filter_block|
|
|
113
|
-
Matchers::HaveSelector.new(:field, locator, options.merge(state => true), &optional_filter_block)
|
|
113
|
+
Matchers::HaveSelector.new(:field, locator, **options.merge(state => true), &optional_filter_block)
|
|
114
114
|
end
|
|
115
115
|
end
|
|
116
116
|
|
|
@@ -127,64 +127,65 @@ module Capybara
|
|
|
127
127
|
# RSpec matcher for text content.
|
|
128
128
|
#
|
|
129
129
|
# @see Capybara::Node::Matchers#assert_text
|
|
130
|
-
def have_text(*args)
|
|
131
|
-
Matchers::HaveText.new(*args)
|
|
130
|
+
def have_text(text_or_type, *args, **options)
|
|
131
|
+
Matchers::HaveText.new(text_or_type, *args, **options)
|
|
132
132
|
end
|
|
133
133
|
alias_method :have_content, :have_text
|
|
134
134
|
|
|
135
135
|
def have_title(title, **options)
|
|
136
|
-
Matchers::HaveTitle.new(title, options)
|
|
136
|
+
Matchers::HaveTitle.new(title, **options)
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
# RSpec matcher for the current path.
|
|
140
140
|
#
|
|
141
141
|
# @see Capybara::SessionMatchers#assert_current_path
|
|
142
|
-
def have_current_path(path, **options)
|
|
143
|
-
Matchers::HaveCurrentPath.new(path, options)
|
|
142
|
+
def have_current_path(path, **options, &optional_filter_block)
|
|
143
|
+
Matchers::HaveCurrentPath.new(path, **options, &optional_filter_block)
|
|
144
144
|
end
|
|
145
145
|
|
|
146
146
|
# RSpec matcher for element style.
|
|
147
147
|
#
|
|
148
148
|
# @see Capybara::Node::Matchers#matches_style?
|
|
149
|
-
def match_style(styles, **options)
|
|
150
|
-
|
|
149
|
+
def match_style(styles = nil, **options)
|
|
150
|
+
styles, options = options, {} if styles.nil?
|
|
151
|
+
Matchers::MatchStyle.new(styles, **options)
|
|
151
152
|
end
|
|
152
153
|
|
|
153
154
|
##
|
|
154
155
|
# @deprecated
|
|
155
156
|
#
|
|
156
|
-
def have_style(styles, **options)
|
|
157
|
-
warn
|
|
157
|
+
def have_style(styles = nil, **options)
|
|
158
|
+
Capybara::Helpers.warn "DEPRECATED: have_style is deprecated, please use match_style : #{Capybara::Helpers.filter_backtrace(caller)}"
|
|
158
159
|
match_style(styles, **options)
|
|
159
160
|
end
|
|
160
161
|
|
|
161
162
|
%w[selector css xpath text title current_path link button
|
|
162
163
|
field checked_field unchecked_field select table
|
|
163
164
|
sibling ancestor].each do |matcher_type|
|
|
164
|
-
define_method "have_no_#{matcher_type}" do |*args, &optional_filter_block|
|
|
165
|
-
Matchers::NegatedMatcher.new(send("have_#{matcher_type}", *args, &optional_filter_block))
|
|
165
|
+
define_method "have_no_#{matcher_type}" do |*args, **kw_args, &optional_filter_block|
|
|
166
|
+
Matchers::NegatedMatcher.new(send("have_#{matcher_type}", *args, **kw_args, &optional_filter_block))
|
|
166
167
|
end
|
|
167
168
|
end
|
|
168
169
|
alias_method :have_no_content, :have_no_text
|
|
169
170
|
|
|
170
171
|
%w[selector css xpath].each do |matcher_type|
|
|
171
|
-
define_method "not_match_#{matcher_type}" do |*args, &optional_filter_block|
|
|
172
|
-
Matchers::NegatedMatcher.new(send("match_#{matcher_type}", *args, &optional_filter_block))
|
|
172
|
+
define_method "not_match_#{matcher_type}" do |*args, **kw_args, &optional_filter_block|
|
|
173
|
+
Matchers::NegatedMatcher.new(send("match_#{matcher_type}", *args, **kw_args, &optional_filter_block))
|
|
173
174
|
end
|
|
174
175
|
end
|
|
175
176
|
|
|
176
177
|
# RSpec matcher for whether sibling element(s) matching a given selector exist.
|
|
177
178
|
#
|
|
178
179
|
# @see Capybara::Node::Matchers#assert_sibling
|
|
179
|
-
def have_sibling(*args, &optional_filter_block)
|
|
180
|
-
Matchers::HaveSibling.new(*args, &optional_filter_block)
|
|
180
|
+
def have_sibling(*args, **kw_args, &optional_filter_block)
|
|
181
|
+
Matchers::HaveSibling.new(*args, **kw_args, &optional_filter_block)
|
|
181
182
|
end
|
|
182
183
|
|
|
183
184
|
# RSpec matcher for whether ancestor element(s) matching a given selector exist.
|
|
184
185
|
#
|
|
185
186
|
# @see Capybara::Node::Matchers#assert_ancestor
|
|
186
|
-
def have_ancestor(*args, &optional_filter_block)
|
|
187
|
-
Matchers::HaveAncestor.new(*args, &optional_filter_block)
|
|
187
|
+
def have_ancestor(*args, **kw_args, &optional_filter_block)
|
|
188
|
+
Matchers::HaveAncestor.new(*args, **kw_args, &optional_filter_block)
|
|
188
189
|
end
|
|
189
190
|
|
|
190
191
|
##
|