capybara 3.23.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 +264 -11
- data/README.md +10 -6
- data/lib/capybara.rb +20 -8
- data/lib/capybara/config.rb +10 -8
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +4 -0
- data/lib/capybara/driver/node.rb +4 -0
- data/lib/capybara/dsl.rb +10 -2
- data/lib/capybara/helpers.rb +28 -2
- data/lib/capybara/minitest.rb +232 -144
- data/lib/capybara/minitest/spec.rb +156 -97
- data/lib/capybara/node/actions.rb +36 -36
- data/lib/capybara/node/base.rb +6 -6
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +3 -3
- data/lib/capybara/node/element.rb +77 -33
- data/lib/capybara/node/finders.rb +24 -17
- data/lib/capybara/node/matchers.rb +79 -64
- data/lib/capybara/node/simple.rb +11 -4
- data/lib/capybara/queries/ancestor_query.rb +6 -10
- data/lib/capybara/queries/base_query.rb +2 -1
- data/lib/capybara/queries/current_path_query.rb +14 -4
- data/lib/capybara/queries/selector_query.rb +259 -23
- data/lib/capybara/queries/sibling_query.rb +5 -11
- data/lib/capybara/queries/style_query.rb +1 -1
- data/lib/capybara/queries/text_query.rb +13 -1
- data/lib/capybara/rack_test/browser.rb +13 -4
- data/lib/capybara/rack_test/driver.rb +2 -1
- data/lib/capybara/rack_test/form.rb +2 -2
- data/lib/capybara/rack_test/node.rb +42 -6
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +18 -12
- data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
- data/lib/capybara/registrations/servers.rb +9 -2
- data/lib/capybara/result.rb +39 -19
- data/lib/capybara/rspec.rb +2 -0
- data/lib/capybara/rspec/matcher_proxies.rb +5 -5
- data/lib/capybara/rspec/matchers.rb +97 -74
- data/lib/capybara/rspec/matchers/base.rb +19 -6
- data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
- data/lib/capybara/rspec/matchers/have_ancestor.rb +5 -7
- data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +15 -10
- data/lib/capybara/rspec/matchers/have_sibling.rb +4 -7
- data/lib/capybara/rspec/matchers/have_text.rb +4 -7
- data/lib/capybara/rspec/matchers/have_title.rb +2 -2
- data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
- data/lib/capybara/rspec/matchers/match_style.rb +7 -2
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/selector.rb +46 -19
- data/lib/capybara/selector/builders/css_builder.rb +10 -6
- data/lib/capybara/selector/builders/xpath_builder.rb +4 -2
- data/lib/capybara/selector/css.rb +1 -1
- data/lib/capybara/selector/definition.rb +13 -11
- data/lib/capybara/selector/definition/button.rb +32 -15
- data/lib/capybara/selector/definition/checkbox.rb +2 -2
- data/lib/capybara/selector/definition/css.rb +3 -1
- data/lib/capybara/selector/definition/datalist_input.rb +2 -2
- data/lib/capybara/selector/definition/datalist_option.rb +1 -1
- data/lib/capybara/selector/definition/element.rb +3 -2
- data/lib/capybara/selector/definition/field.rb +1 -1
- data/lib/capybara/selector/definition/file_field.rb +1 -1
- data/lib/capybara/selector/definition/fillable_field.rb +2 -2
- data/lib/capybara/selector/definition/label.rb +5 -3
- data/lib/capybara/selector/definition/link.rb +8 -0
- data/lib/capybara/selector/definition/option.rb +1 -1
- data/lib/capybara/selector/definition/radio_button.rb +2 -2
- data/lib/capybara/selector/definition/select.rb +33 -14
- data/lib/capybara/selector/definition/table.rb +6 -3
- data/lib/capybara/selector/definition/table_row.rb +2 -2
- data/lib/capybara/selector/filter_set.rb +13 -11
- data/lib/capybara/selector/filters/base.rb +6 -1
- data/lib/capybara/selector/filters/locator_filter.rb +1 -1
- data/lib/capybara/selector/regexp_disassembler.rb +7 -0
- data/lib/capybara/selector/selector.rb +13 -3
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -1
- data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +10 -10
- data/lib/capybara/selenium/driver.rb +86 -24
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +24 -21
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +21 -19
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +17 -1
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +0 -4
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +37 -26
- data/lib/capybara/selenium/extensions/html5_drag.rb +55 -11
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +8 -10
- data/lib/capybara/selenium/logger_suppressor.rb +8 -2
- data/lib/capybara/selenium/node.rb +160 -40
- data/lib/capybara/selenium/nodes/chrome_node.rb +72 -12
- data/lib/capybara/selenium/nodes/edge_node.rb +32 -14
- data/lib/capybara/selenium/nodes/firefox_node.rb +28 -32
- data/lib/capybara/selenium/nodes/safari_node.rb +5 -29
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +4 -4
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +32 -7
- data/lib/capybara/server.rb +19 -3
- data/lib/capybara/server/animation_disabler.rb +8 -3
- data/lib/capybara/server/checker.rb +1 -1
- data/lib/capybara/server/middleware.rb +22 -10
- data/lib/capybara/session.rb +66 -40
- data/lib/capybara/session/config.rb +11 -3
- data/lib/capybara/session/matchers.rb +11 -11
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +75 -7
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
- data/lib/capybara/spec/session/all_spec.rb +60 -5
- data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
- data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
- data/lib/capybara/spec/session/check_spec.rb +6 -0
- data/lib/capybara/spec/session/click_button_spec.rb +16 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
- data/lib/capybara/spec/session/current_url_spec.rb +11 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
- data/lib/capybara/spec/session/find_spec.rb +55 -0
- data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -0
- data/lib/capybara/spec/session/has_button_spec.rb +51 -0
- data/lib/capybara/spec/session/has_css_spec.rb +26 -4
- data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
- data/lib/capybara/spec/session/has_field_spec.rb +34 -0
- data/lib/capybara/spec/session/has_select_spec.rb +32 -4
- data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
- data/lib/capybara/spec/session/has_table_spec.rb +51 -5
- data/lib/capybara/spec/session/has_text_spec.rb +30 -0
- data/lib/capybara/spec/session/html_spec.rb +1 -1
- data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
- data/lib/capybara/spec/session/node_spec.rb +394 -9
- data/lib/capybara/spec/session/refresh_spec.rb +2 -1
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/save_page_spec.rb +4 -4
- data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -15
- data/lib/capybara/spec/session/selectors_spec.rb +16 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_spec.rb +8 -8
- data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
- data/lib/capybara/spec/spec_helper.rb +14 -14
- data/lib/capybara/spec/test_app.rb +27 -21
- data/lib/capybara/spec/views/form.erb +47 -4
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/with_animation.erb +37 -1
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_html.erb +24 -2
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +4 -1
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +3 -7
- data/spec/basic_node_spec.rb +15 -14
- data/spec/capybara_spec.rb +28 -28
- data/spec/dsl_spec.rb +16 -3
- data/spec/filter_set_spec.rb +5 -5
- data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
- data/spec/minitest_spec.rb +3 -2
- data/spec/minitest_spec_spec.rb +46 -46
- data/spec/rack_test_spec.rb +38 -15
- data/spec/regexp_dissassembler_spec.rb +52 -38
- data/spec/result_spec.rb +43 -32
- data/spec/rspec/features_spec.rb +4 -1
- data/spec/rspec/scenarios_spec.rb +4 -0
- data/spec/rspec/shared_spec_matchers.rb +68 -56
- data/spec/rspec_spec.rb +9 -5
- data/spec/selector_spec.rb +32 -17
- data/spec/selenium_spec_chrome.rb +78 -11
- data/spec/selenium_spec_chrome_remote.rb +23 -6
- data/spec/selenium_spec_edge.rb +15 -12
- data/spec/selenium_spec_firefox.rb +24 -19
- data/spec/selenium_spec_firefox_remote.rb +0 -8
- data/spec/selenium_spec_ie.rb +1 -6
- data/spec/server_spec.rb +106 -44
- data/spec/session_spec.rb +5 -5
- data/spec/shared_selenium_node.rb +56 -2
- data/spec/shared_selenium_session.rb +122 -15
- data/spec/spec_helper.rb +2 -2
- metadata +63 -17
- data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -3,25 +3,19 @@
|
|
3
3
|
module Capybara
|
4
4
|
module Queries
|
5
5
|
class SiblingQuery < SelectorQuery
|
6
|
-
def initialize(*args)
|
7
|
-
super
|
8
|
-
@count_options = {}
|
9
|
-
COUNT_KEYS.each do |key|
|
10
|
-
@count_options[key] = @options.delete(key) if @options.key?(key)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
6
|
# @api private
|
15
7
|
def resolve_for(node, exact = nil)
|
16
8
|
@sibling_node = node
|
17
9
|
node.synchronize do
|
18
10
|
match_results = super(node.session.current_scope, exact)
|
19
|
-
|
20
|
-
|
11
|
+
siblings = node.find_xpath((XPath.preceding_sibling + XPath.following_sibling).to_s)
|
12
|
+
.map(&method(:to_element))
|
13
|
+
.select { |el| match_results.include?(el) }
|
14
|
+
Capybara::Result.new(ordered_results(siblings), self)
|
21
15
|
end
|
22
16
|
end
|
23
17
|
|
24
|
-
def description(applied = false)
|
18
|
+
def description(applied = false) # rubocop:disable Style/OptionalBooleanParameter
|
25
19
|
desc = super
|
26
20
|
sibling_query = @sibling_node&.instance_variable_get(:@query)
|
27
21
|
desc += " that is a sibling of #{sibling_query.description}" if sibling_query
|
@@ -6,11 +6,19 @@ module Capybara
|
|
6
6
|
class TextQuery < BaseQuery
|
7
7
|
def initialize(type = nil, expected_text, session_options:, **options) # rubocop:disable Style/OptionalArguments
|
8
8
|
@type = type.nil? ? default_type : type
|
9
|
-
@
|
9
|
+
raise ArgumentError, "#{@type} is not a valid type for a text query" unless valid_types.include?(@type)
|
10
|
+
|
10
11
|
@options = options
|
11
12
|
super(@options)
|
12
13
|
self.session_options = session_options
|
13
14
|
|
15
|
+
if expected_text.nil? && !exact?
|
16
|
+
warn 'Checking for expected text of nil is confusing and/or pointless since it will always match. '\
|
17
|
+
"Please specify a string or regexp instead. #{Capybara::Helpers.filter_backtrace(caller)}"
|
18
|
+
end
|
19
|
+
|
20
|
+
@expected_text = expected_text.is_a?(Regexp) ? expected_text : expected_text.to_s
|
21
|
+
|
14
22
|
@search_regexp = Capybara::Helpers.to_regexp(@expected_text, exact: exact?)
|
15
23
|
|
16
24
|
assert_valid_keys
|
@@ -83,6 +91,10 @@ module Capybara
|
|
83
91
|
COUNT_KEYS + %i[wait exact normalize_ws]
|
84
92
|
end
|
85
93
|
|
94
|
+
def valid_types
|
95
|
+
%i[all visible]
|
96
|
+
end
|
97
|
+
|
86
98
|
def check_visible_text?
|
87
99
|
@type == :visible
|
88
100
|
end
|
@@ -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?
|
@@ -53,14 +57,17 @@ class Capybara::RackTest::Browser
|
|
53
57
|
end
|
54
58
|
end
|
55
59
|
end
|
56
|
-
|
60
|
+
|
61
|
+
if last_response.redirect? # rubocop:disable Style/GuardClause
|
62
|
+
raise Capybara::InfiniteRedirectError, "redirected more than #{driver.redirect_limit} times, check for infinite redirects."
|
63
|
+
end
|
57
64
|
end
|
58
65
|
|
59
66
|
def process(method, path, attributes = {}, env = {})
|
60
67
|
method = method.downcase
|
61
68
|
new_uri = build_uri(path)
|
62
69
|
@current_scheme, @current_host, @current_port = new_uri.select(:scheme, :host, :port)
|
63
|
-
|
70
|
+
@current_fragment = new_uri.fragment || @current_fragment
|
64
71
|
reset_cache!
|
65
72
|
send(method, new_uri.to_s, attributes, env.merge(options[:headers] || {}))
|
66
73
|
end
|
@@ -78,7 +85,9 @@ class Capybara::RackTest::Browser
|
|
78
85
|
end
|
79
86
|
|
80
87
|
def current_url
|
81
|
-
last_request.url
|
88
|
+
uri = build_uri(last_request.url)
|
89
|
+
uri.fragment = @current_fragment if @current_fragment
|
90
|
+
uri.to_s
|
82
91
|
rescue Rack::Test::Error
|
83
92
|
''
|
84
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
|
@@ -42,7 +43,7 @@ class Capybara::RackTest::Driver < Capybara::Driver::Base
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def visit(path, **attributes)
|
45
|
-
browser.visit(path, attributes)
|
46
|
+
browser.visit(path, **attributes)
|
46
47
|
end
|
47
48
|
|
48
49
|
def refresh
|
@@ -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
|
@@ -56,7 +56,7 @@ private
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def request_method
|
59
|
-
/post/i.match?(self[:method]) ? :post : :get
|
59
|
+
/post/i.match?(self[:method] || '') ? :post : :get
|
60
60
|
end
|
61
61
|
|
62
62
|
def merge_param!(params, key, value)
|
@@ -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
|
@@ -63,8 +64,9 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
63
64
|
native.remove_attribute('selected')
|
64
65
|
end
|
65
66
|
|
66
|
-
def click(keys = [], **
|
67
|
-
|
67
|
+
def click(keys = [], **options)
|
68
|
+
options.delete(:offset)
|
69
|
+
raise ArgumentError, 'The RackTest driver does not support click options' unless keys.empty? && options.empty?
|
68
70
|
|
69
71
|
if link?
|
70
72
|
follow_link
|
@@ -75,6 +77,8 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
75
77
|
set(!checked?)
|
76
78
|
elsif tag_name == 'label'
|
77
79
|
click_label
|
80
|
+
elsif (details = native.xpath('.//ancestor-or-self::details').last)
|
81
|
+
toggle_details(details)
|
78
82
|
end
|
79
83
|
end
|
80
84
|
|
@@ -120,9 +124,18 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
120
124
|
alias_method "unchecked_#{meth_name}", meth_name
|
121
125
|
private "unchecked_#{meth_name}" # rubocop:disable Style/AccessModifierDeclarations
|
122
126
|
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
126
139
|
end
|
127
140
|
end
|
128
141
|
|
@@ -196,6 +209,14 @@ private
|
|
196
209
|
end
|
197
210
|
end
|
198
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
|
+
|
199
220
|
def set_input(value) # rubocop:disable Naming/AccessorMethodName
|
200
221
|
if text_or_password? && attribute_is_not_blank?(:maxlength)
|
201
222
|
# Browser behavior for maxlength="0" is inconsistent, so we stick with
|
@@ -235,6 +256,17 @@ private
|
|
235
256
|
labelled_control.set(!labelled_control.checked?) if checkbox_or_radio?(labelled_control)
|
236
257
|
end
|
237
258
|
|
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')
|
265
|
+
else
|
266
|
+
details.set_attribute('open', 'open')
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
238
270
|
def link?
|
239
271
|
tag_name == 'a' && !self[:href].nil?
|
240
272
|
end
|
@@ -273,6 +305,10 @@ protected
|
|
273
305
|
tag_name == 'textarea'
|
274
306
|
end
|
275
307
|
|
308
|
+
def range?
|
309
|
+
input_field? && type == 'range'
|
310
|
+
end
|
311
|
+
|
276
312
|
OPTION_OWNER_XPATH = XPath.parent(:optgroup, :select, :datalist).to_s.freeze
|
277
313
|
DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
|
278
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
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Puma
|
4
|
+
module MiniSSL
|
5
|
+
class Socket
|
6
|
+
def read_nonblock(size, *_)
|
7
|
+
wait_states = %i[wait_readable wait_writable]
|
8
|
+
|
9
|
+
loop do
|
10
|
+
output = engine_read_all
|
11
|
+
return output if output
|
12
|
+
|
13
|
+
data = @socket.read_nonblock(size, exception: false)
|
14
|
+
raise IO::EAGAINWaitReadable if wait_states.include? data
|
15
|
+
return nil if data.nil?
|
16
|
+
|
17
|
+
@engine.inject(data)
|
18
|
+
output = engine_read_all
|
19
|
+
|
20
|
+
return output if output
|
21
|
+
|
22
|
+
while (neg_data = @engine.extract)
|
23
|
+
@socket.write neg_data
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -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|
|
@@ -20,13 +20,20 @@ Capybara.register_server :puma do |app, port, host, **options|
|
|
20
20
|
raise LoadError, 'Capybara requires `puma` version 3.8.0 or higher, please upgrade `puma` or register and specify your own server block'
|
21
21
|
end
|
22
22
|
end
|
23
|
+
|
23
24
|
# If we just run the Puma Rack handler it installs signal handlers which prevent us from being able to interrupt tests.
|
24
25
|
# Therefore construct and run the Server instance ourselves.
|
25
26
|
# Rack::Handler::Puma.run(app, { Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false }.merge(options))
|
26
|
-
|
27
|
+
default_options = { Host: host, Port: port, Threads: '0:4', workers: 0, daemon: false }
|
28
|
+
options = default_options.merge(options)
|
29
|
+
|
27
30
|
conf = Rack::Handler::Puma.config(app, options)
|
31
|
+
conf.clamp
|
28
32
|
events = conf.options[:Silent] ? ::Puma::Events.strings : ::Puma::Events.stdio
|
29
33
|
|
34
|
+
puma_ver = Gem::Version.new(Puma::Const::PUMA_VERSION)
|
35
|
+
require_relative 'patches/puma_ssl' if Gem::Requirement.new('>=4.0.0', '< 4.1.0').satisfied_by?(puma_ver)
|
36
|
+
|
30
37
|
events.log 'Capybara starting Puma...'
|
31
38
|
events.log "* Version #{Puma::Const::PUMA_VERSION} , codename: #{Puma::Const::CODE_NAME}"
|
32
39
|
events.log "* Min threads: #{conf.options[:min_threads]}, max threads: #{conf.options[:max_threads]}"
|
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,15 +167,18 @@ module Capybara
|
|
150
167
|
@rest ||= @elements - full_results
|
151
168
|
end
|
152
169
|
|
153
|
-
|
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
|
157
|
-
|
158
|
-
|
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
|
177
|
+
def lazy_select_elements(&block)
|
159
178
|
@elements.select(&block).to_enum # non-lazy evaluation
|
160
|
-
|
161
|
-
|
179
|
+
end
|
180
|
+
else
|
181
|
+
def lazy_select_elements(&block)
|
162
182
|
@elements.lazy.select(&block)
|
163
183
|
end
|
164
184
|
end
|