capybara 3.24.0 → 3.25.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 +16 -1
- data/README.md +1 -1
- data/lib/capybara.rb +2 -0
- data/lib/capybara/node/actions.rb +2 -2
- data/lib/capybara/node/element.rb +8 -5
- data/lib/capybara/node/matchers.rb +1 -1
- data/lib/capybara/rack_test/node.rb +3 -2
- data/lib/capybara/rspec/matchers/base.rb +5 -0
- data/lib/capybara/rspec/matchers/have_ancestor.rb +1 -4
- data/lib/capybara/rspec/matchers/have_selector.rb +1 -4
- data/lib/capybara/rspec/matchers/have_sibling.rb +1 -4
- data/lib/capybara/rspec/matchers/have_text.rb +1 -4
- data/lib/capybara/selector/builders/css_builder.rb +10 -6
- data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
- data/lib/capybara/selenium/driver.rb +10 -9
- data/lib/capybara/selenium/extensions/find.rb +18 -17
- data/lib/capybara/selenium/extensions/html5_drag.rb +26 -4
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/node.rb +26 -16
- data/lib/capybara/selenium/nodes/chrome_node.rb +9 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +0 -23
- data/lib/capybara/selenium/nodes/safari_node.rb +1 -23
- data/lib/capybara/server/animation_disabler.rb +1 -1
- data/lib/capybara/session/config.rb +3 -1
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -0
- data/lib/capybara/spec/session/node_spec.rb +119 -0
- data/lib/capybara/spec/session/selectors_spec.rb +1 -1
- data/lib/capybara/spec/spec_helper.rb +1 -0
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/with_animation.erb +29 -1
- data/lib/capybara/spec/views/with_dragula.erb +22 -0
- data/lib/capybara/spec/views/with_html.erb +3 -0
- data/lib/capybara/spec/views/with_js.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/spec/selenium_spec_edge.rb +6 -2
- data/spec/selenium_spec_firefox.rb +1 -1
- data/spec/shared_selenium_session.rb +7 -1
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 439a641ea3d9a06bcc674c159c3ef16612fb29874e71f11ef7bb2d0e73382892
|
4
|
+
data.tar.gz: a5e57dfb62e3682a87f05650a13945545a61183a84a15498390d07aa3ec6e4ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d50ab813eecabef7465c9a42904174f65eefe6dc8e0f92fea59d523753582c1797a1a87880a1d9805edb8f74e33585314841d6fac7abcf2781a627ac9703191e
|
7
|
+
data.tar.gz: 0d4f2b360e528a3fae6357072592ac5295cb500d68251d23bc66a014fc62528473e960b4049d4e24a5339a8a41f02f15c70b7ae59b5f51ebfb1a7369afa47f27
|
data/History.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
|
+
# Version 3.25.0
|
2
|
+
Release date: 2019-06-27
|
3
|
+
|
4
|
+
### Added
|
5
|
+
|
6
|
+
* Animation disabler also disables before and after pseudoelements - Issue #2221 [Daniel Heath]
|
7
|
+
* `w3c_click_offset` configuration option to determine whether click offsets are calculated from element
|
8
|
+
center or top left corner
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
|
12
|
+
* Woraround issue with chromedriver 76/77 in W3C mode losing mouse state during legacy drag. Only fixed if
|
13
|
+
both source and target are simultaenously inside the viewport - Issue #2223
|
14
|
+
* Negative ancestor expectations/predicates were incorrectly checking siblings rather than ancestors
|
15
|
+
|
1
16
|
# Version 3.24.0
|
2
|
-
Release date:
|
17
|
+
Release date: 2019-06-13
|
3
18
|
|
4
19
|
### Added
|
5
20
|
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
[](https://gitter.im/jnicklas/capybara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
8
8
|
[](https://dependabot.com/compatibility-score.html?dependency-name=capybara&package-manager=bundler&version-scheme=semver)
|
9
9
|
|
10
|
-
**Note** You are viewing the README for the 3.
|
10
|
+
**Note** You are viewing the README for the 3.25.x version of Capybara
|
11
11
|
|
12
12
|
Capybara helps you test web applications by simulating how a real user would
|
13
13
|
interact with your app. It is agnostic about the driver running your tests and
|
data/lib/capybara.rb
CHANGED
@@ -97,6 +97,7 @@ module Capybara
|
|
97
97
|
# and {configure raise_server_errors} is `true`.
|
98
98
|
# - **test_id** (Symbol, String, `nil` = `nil`) - Optional attribute to match locator against with built-in selectors along with id.
|
99
99
|
# - **threadsafe** (Boolean = `false`) - Whether sessions can be configured individually.
|
100
|
+
# - **w3c_click_offset** (Boolean = 'false') - Whether click offsets should be from element center (true) or top left (false)
|
100
101
|
#
|
101
102
|
# #### DSL Options
|
102
103
|
#
|
@@ -506,4 +507,5 @@ Capybara.configure do |config|
|
|
506
507
|
config.predicates_wait = true
|
507
508
|
config.default_normalize_ws = false
|
508
509
|
config.allow_gumbo = false
|
510
|
+
config.w3c_click_offset = false
|
509
511
|
end
|
@@ -307,12 +307,12 @@ module Capybara
|
|
307
307
|
synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
|
308
308
|
begin
|
309
309
|
find(:select, from, options)
|
310
|
-
rescue Capybara::ElementNotFound => select_error
|
310
|
+
rescue Capybara::ElementNotFound => select_error # rubocop:disable Naming/RescuedExceptionsVariableName
|
311
311
|
raise if %i[selected with_selected multiple].any? { |option| options.key?(option) }
|
312
312
|
|
313
313
|
begin
|
314
314
|
find(:datalist_input, from, options)
|
315
|
-
rescue Capybara::ElementNotFound => dlinput_error
|
315
|
+
rescue Capybara::ElementNotFound => dlinput_error # rubocop:disable Naming/RescuedExceptionsVariableName
|
316
316
|
raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}"
|
317
317
|
end
|
318
318
|
end
|
@@ -157,13 +157,16 @@ module Capybara
|
|
157
157
|
# Both x: and y: must be specified if an offset is wanted, if not specified the click will occur at the middle of the element.
|
158
158
|
# @overload $0(*modifier_keys, wait: nil, **offset)
|
159
159
|
# @param *modifier_keys [:alt, :control, :meta, :shift] ([]) Keys to be held down when clicking
|
160
|
-
# @option
|
161
|
-
#
|
160
|
+
# @option options [Integer] x X coordinate to offset the click location. If {Capybara.configure w3c_click_offset} is `true` the
|
161
|
+
# offset will be from the element center, otherwise it will be from the top left corner of the element
|
162
|
+
# @option options [Integer] y Y coordinate to offset the click location. If {Capybara.configure w3c_click_offset} is `true` the
|
163
|
+
# offset will be from the element center, otherwise it will be from the top left corner of the element
|
162
164
|
# @return [Capybara::Node::Element] The element
|
163
|
-
def click(*keys, wait: nil, **
|
164
|
-
raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^
|
165
|
+
def click(*keys, wait: nil, **options)
|
166
|
+
raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ options[:x] ^ options[:y]
|
165
167
|
|
166
|
-
|
168
|
+
options[:offset] = :center if session_options.w3c_click_offset
|
169
|
+
synchronize(wait) { base.click(Array(keys), options) }
|
167
170
|
self
|
168
171
|
end
|
169
172
|
|
@@ -743,7 +743,7 @@ module Capybara
|
|
743
743
|
end
|
744
744
|
|
745
745
|
def assert_no_ancestor(*args, &optional_filter_block)
|
746
|
-
_verify_selector_result(args, optional_filter_block, Capybara::Queries::
|
746
|
+
_verify_selector_result(args, optional_filter_block, Capybara::Queries::AncestorQuery) do |result, query|
|
747
747
|
if result.matches_count? && (!result.empty? || query.expects_none?)
|
748
748
|
raise Capybara::ExpectationNotMet, result.negative_failure_message
|
749
749
|
end
|
@@ -63,8 +63,9 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
63
63
|
native.remove_attribute('selected')
|
64
64
|
end
|
65
65
|
|
66
|
-
def click(keys = [], **
|
67
|
-
|
66
|
+
def click(keys = [], **options)
|
67
|
+
options.delete(:offset)
|
68
|
+
raise ArgumentError, 'The RackTest driver does not support click options' unless keys.empty? && options.empty?
|
68
69
|
|
69
70
|
if link?
|
70
71
|
follow_link
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'capybara/rspec/matchers/compound'
|
4
|
+
require 'capybara/rspec/matchers/count_sugar'
|
4
5
|
|
5
6
|
module Capybara
|
6
7
|
module RSpecMatchers
|
@@ -65,6 +66,10 @@ module Capybara
|
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
69
|
+
class CountableWrappedElementMatcher < WrappedElementMatcher
|
70
|
+
include ::Capybara::RSpecMatchers::CountSugar
|
71
|
+
end
|
72
|
+
|
68
73
|
class NegatedMatcher
|
69
74
|
include ::Capybara::RSpecMatchers::Matchers::Compound if defined?(::Capybara::RSpecMatchers::Matchers::Compound)
|
70
75
|
|
@@ -1,14 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'capybara/rspec/matchers/base'
|
4
|
-
require 'capybara/rspec/matchers/count_sugar'
|
5
4
|
|
6
5
|
module Capybara
|
7
6
|
module RSpecMatchers
|
8
7
|
module Matchers
|
9
|
-
class HaveAncestor <
|
10
|
-
include CountSugar
|
11
|
-
|
8
|
+
class HaveAncestor < CountableWrappedElementMatcher
|
12
9
|
def element_matches?(el)
|
13
10
|
el.assert_ancestor(*@args, &@filter_block)
|
14
11
|
end
|
@@ -1,14 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'capybara/rspec/matchers/base'
|
4
|
-
require 'capybara/rspec/matchers/count_sugar'
|
5
4
|
|
6
5
|
module Capybara
|
7
6
|
module RSpecMatchers
|
8
7
|
module Matchers
|
9
|
-
class HaveSelector <
|
10
|
-
include CountSugar
|
11
|
-
|
8
|
+
class HaveSelector < CountableWrappedElementMatcher
|
12
9
|
def element_matches?(el)
|
13
10
|
el.assert_selector(*@args, &@filter_block)
|
14
11
|
end
|
@@ -1,14 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'capybara/rspec/matchers/base'
|
4
|
-
require 'capybara/rspec/matchers/count_sugar'
|
5
4
|
|
6
5
|
module Capybara
|
7
6
|
module RSpecMatchers
|
8
7
|
module Matchers
|
9
|
-
class HaveSibling <
|
10
|
-
include CountSugar
|
11
|
-
|
8
|
+
class HaveSibling < CountableWrappedElementMatcher
|
12
9
|
def element_matches?(el)
|
13
10
|
el.assert_sibling(*@args, &@filter_block)
|
14
11
|
end
|
@@ -1,14 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'capybara/rspec/matchers/base'
|
4
|
-
require 'capybara/rspec/matchers/count_sugar'
|
5
4
|
|
6
5
|
module Capybara
|
7
6
|
module RSpecMatchers
|
8
7
|
module Matchers
|
9
|
-
class HaveText <
|
10
|
-
include CountSugar
|
11
|
-
|
8
|
+
class HaveText < CountableWrappedElementMatcher
|
12
9
|
def element_matches?(el)
|
13
10
|
el.assert_text(*@args)
|
14
11
|
end
|
@@ -17,11 +17,7 @@ module Capybara
|
|
17
17
|
conditions = if name == :class
|
18
18
|
class_conditions(value)
|
19
19
|
elsif value.is_a? Regexp
|
20
|
-
|
21
|
-
strs.map do |str|
|
22
|
-
"[#{name}*='#{str}'#{' i' if value.casefold?}]"
|
23
|
-
end.join
|
24
|
-
end
|
20
|
+
regexp_conditions(name, value)
|
25
21
|
else
|
26
22
|
[attribute_conditions(name => value)]
|
27
23
|
end
|
@@ -36,6 +32,14 @@ module Capybara
|
|
36
32
|
|
37
33
|
private
|
38
34
|
|
35
|
+
def regexp_conditions(name, value)
|
36
|
+
Selector::RegexpDisassembler.new(value).alternated_substrings.map do |strs|
|
37
|
+
strs.map do |str|
|
38
|
+
"[#{name}*='#{str}'#{' i' if value.casefold?}]"
|
39
|
+
end.join
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
39
43
|
def attribute_conditions(attributes)
|
40
44
|
attributes.map do |attribute, value|
|
41
45
|
case value
|
@@ -70,7 +74,7 @@ module Capybara
|
|
70
74
|
end.join
|
71
75
|
end
|
72
76
|
else
|
73
|
-
cls = Array(classes).group_by { |cl| cl.
|
77
|
+
cls = Array(classes).group_by { |cl| cl.match?(/^!(?!!!)/) }
|
74
78
|
[(cls[false].to_a.map { |cl| ".#{Capybara::Selector::CSS.escape(cl.sub(/^!!/, ''))}" } +
|
75
79
|
cls[true].to_a.map { |cl| ":not(.#{Capybara::Selector::CSS.escape(cl.slice(1..-1))})" }).join]
|
76
80
|
end
|
@@ -48,7 +48,7 @@ module Capybara
|
|
48
48
|
attribute_conditions(class: classes)
|
49
49
|
else
|
50
50
|
Array(classes).map do |klass|
|
51
|
-
if klass.
|
51
|
+
if klass.match?(/^!(?!!!)/)
|
52
52
|
!XPath.attr(:class).contains_word(klass.slice(1..-1))
|
53
53
|
else
|
54
54
|
XPath.attr(:class).contains_word(klass.sub(/^!!/, ''))
|
@@ -300,13 +300,10 @@ private
|
|
300
300
|
end
|
301
301
|
|
302
302
|
def unhandled_alert_errors
|
303
|
-
@unhandled_alert_errors ||=
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
303
|
+
@unhandled_alert_errors ||= with_legacy_error(
|
304
|
+
[Selenium::WebDriver::Error::UnexpectedAlertOpenError],
|
305
|
+
'UnhandledAlertError'
|
306
|
+
)
|
310
307
|
end
|
311
308
|
|
312
309
|
def delete_all_cookies
|
@@ -387,10 +384,14 @@ private
|
|
387
384
|
end
|
388
385
|
|
389
386
|
def find_modal_errors
|
390
|
-
@find_modal_errors ||= [Selenium::WebDriver::Error::TimeoutError]
|
387
|
+
@find_modal_errors ||= with_legacy_error([Selenium::WebDriver::Error::TimeoutError], 'TimeOutError')
|
388
|
+
end
|
389
|
+
|
390
|
+
def with_legacy_error(errors, legacy_error)
|
391
|
+
errors.tap do |errs|
|
391
392
|
unless selenium_4?
|
392
393
|
::Selenium::WebDriver.logger.suppress_deprecations do
|
393
|
-
|
394
|
+
errs << Selenium::WebDriver::Error.const_get(legacy_error)
|
394
395
|
end
|
395
396
|
end
|
396
397
|
end
|
@@ -18,27 +18,28 @@ module Capybara
|
|
18
18
|
hints = []
|
19
19
|
|
20
20
|
if (els.size > 2) && !ENV['DISABLE_CAPYBARA_SELENIUM_OPTIMIZATIONS']
|
21
|
-
|
22
|
-
|
23
|
-
hints_js, functions = build_hints_js(uses_visibility, styles)
|
24
|
-
|
25
|
-
unless functions.empty?
|
26
|
-
hints = es_context.execute_script(hints_js, els).map! do |results|
|
27
|
-
hint = {}
|
28
|
-
hint[:style] = results.pop if functions.include?(:style_func)
|
29
|
-
hint[:visible] = results.pop if functions.include?(:vis_func)
|
30
|
-
hint
|
31
|
-
end
|
32
|
-
end
|
33
|
-
rescue ::Selenium::WebDriver::Error::StaleElementReferenceError,
|
34
|
-
::Capybara::NotSupportedByDriverError
|
35
|
-
# warn 'Unexpected Stale Element Error - skipping optimization'
|
36
|
-
hints = []
|
37
|
-
end
|
21
|
+
els = filter_by_text(els, texts) unless texts.empty?
|
22
|
+
hints = gather_hints(els, uses_visibility: uses_visibility, styles: styles)
|
38
23
|
end
|
39
24
|
els.map.with_index { |el, idx| build_node(el, hints[idx] || {}) }
|
40
25
|
end
|
41
26
|
|
27
|
+
def gather_hints(elements, uses_visibility:, styles:)
|
28
|
+
hints_js, functions = build_hints_js(uses_visibility, styles)
|
29
|
+
return [] unless functions.any?
|
30
|
+
|
31
|
+
es_context.execute_script(hints_js, elements).map! do |results|
|
32
|
+
hint = {}
|
33
|
+
hint[:style] = results.pop if functions.include?(:style_func)
|
34
|
+
hint[:visible] = results.pop if functions.include?(:vis_func)
|
35
|
+
hint
|
36
|
+
end
|
37
|
+
rescue ::Selenium::WebDriver::Error::StaleElementReferenceError,
|
38
|
+
::Capybara::NotSupportedByDriverError
|
39
|
+
# warn 'Unexpected Stale Element Error - skipping optimization'
|
40
|
+
[]
|
41
|
+
end
|
42
|
+
|
42
43
|
def filter_by_text(elements, texts)
|
43
44
|
es_context.execute_script <<~JS, elements, texts
|
44
45
|
var texts = arguments[1];
|
@@ -7,16 +7,24 @@ class Capybara::Selenium::Node
|
|
7
7
|
def drag_to(element, delay: 0.05)
|
8
8
|
driver.execute_script MOUSEDOWN_TRACKER
|
9
9
|
scroll_if_needed { browser_action.click_and_hold(native).perform }
|
10
|
-
if driver.evaluate_script(
|
11
|
-
|
10
|
+
if driver.evaluate_script(LEGACY_DRAG_CHECK, self)
|
11
|
+
perform_legacy_drag(element)
|
12
12
|
else
|
13
|
-
|
14
|
-
browser_action.release.perform
|
13
|
+
perform_html5_drag(element, delay)
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
17
|
private
|
19
18
|
|
19
|
+
def perform_legacy_drag(element)
|
20
|
+
element.scroll_if_needed { browser_action.move_to(element.native).release.perform }
|
21
|
+
end
|
22
|
+
|
23
|
+
def perform_html5_drag(element, delay)
|
24
|
+
driver.evaluate_async_script HTML5_DRAG_DROP_SCRIPT, self, element, delay * 1000
|
25
|
+
browser_action.release.perform
|
26
|
+
end
|
27
|
+
|
20
28
|
def html5_drop(*args)
|
21
29
|
if args[0].is_a? String
|
22
30
|
input = driver.evaluate_script ATTACH_FILE
|
@@ -86,6 +94,16 @@ class Capybara::Selenium::Node
|
|
86
94
|
}, { once: true, passive: true })
|
87
95
|
JS
|
88
96
|
|
97
|
+
LEGACY_DRAG_CHECK = <<~JS
|
98
|
+
(function(el){
|
99
|
+
if (window.capybara_mousedown_prevented) return true;
|
100
|
+
do {
|
101
|
+
if (el.draggable) return false;
|
102
|
+
} while (el = el.parentElement );
|
103
|
+
return true;
|
104
|
+
})(arguments[0])
|
105
|
+
JS
|
106
|
+
|
89
107
|
HTML5_DRAG_DROP_SCRIPT = <<~JS
|
90
108
|
function rectCenter(rect){
|
91
109
|
return new DOMPoint(
|
@@ -166,6 +184,10 @@ class Capybara::Selenium::Node
|
|
166
184
|
var dt = new DataTransfer();
|
167
185
|
var opts = { cancelable: true, bubbles: true, dataTransfer: dt };
|
168
186
|
|
187
|
+
while (source && !source.draggable) {
|
188
|
+
source = source.parentElement;
|
189
|
+
}
|
190
|
+
|
169
191
|
if (source.tagName == 'A'){
|
170
192
|
dt.setData('text/uri-list', source.href);
|
171
193
|
dt.setData('text', source.href);
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Capybara::Selenium::Node
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
#
|
7
|
+
class ModifierKeysStack
|
8
|
+
def initialize
|
9
|
+
@stack = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def include?(key)
|
13
|
+
@stack.flatten.include?(key)
|
14
|
+
end
|
15
|
+
|
16
|
+
def press(key)
|
17
|
+
@stack.last.push(key)
|
18
|
+
end
|
19
|
+
|
20
|
+
def push
|
21
|
+
@stack.push []
|
22
|
+
end
|
23
|
+
|
24
|
+
def pop
|
25
|
+
@stack.pop
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -188,6 +188,21 @@ protected
|
|
188
188
|
yield
|
189
189
|
end
|
190
190
|
|
191
|
+
def scroll_to_center
|
192
|
+
script = <<-'JS'
|
193
|
+
try {
|
194
|
+
arguments[0].scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
|
195
|
+
} catch(e) {
|
196
|
+
arguments[0].scrollIntoView(true);
|
197
|
+
}
|
198
|
+
JS
|
199
|
+
begin
|
200
|
+
driver.execute_script(script, self)
|
201
|
+
rescue StandardError # rubocop:disable Lint/HandleExceptions
|
202
|
+
# Swallow error if scrollIntoView with options isn't supported
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
191
206
|
private
|
192
207
|
|
193
208
|
def sibling_index(parent, node, selector)
|
@@ -241,21 +256,6 @@ private
|
|
241
256
|
end
|
242
257
|
end
|
243
258
|
|
244
|
-
def scroll_to_center
|
245
|
-
script = <<-'JS'
|
246
|
-
try {
|
247
|
-
arguments[0].scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
|
248
|
-
} catch(e) {
|
249
|
-
arguments[0].scrollIntoView(true);
|
250
|
-
}
|
251
|
-
JS
|
252
|
-
begin
|
253
|
-
driver.execute_script(script, self)
|
254
|
-
rescue StandardError # rubocop:disable Lint/HandleExceptions
|
255
|
-
# Swallow error if scrollIntoView with options isn't supported
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
259
|
def set_date(value) # rubocop:disable Naming/AccessorMethodName
|
260
260
|
value = SettableValue.new(value)
|
261
261
|
return set_text(value) unless value.dateable?
|
@@ -328,7 +328,13 @@ private
|
|
328
328
|
end
|
329
329
|
|
330
330
|
def action_with_modifiers(click_options)
|
331
|
-
actions = browser_action.
|
331
|
+
actions = browser_action.tap do |acts|
|
332
|
+
if click_options.center_offset? && click_options.coords?
|
333
|
+
acts.move_to(native).move_by(*click_options.coords)
|
334
|
+
else
|
335
|
+
acts.move_to(native, *click_options.coords)
|
336
|
+
end
|
337
|
+
end
|
332
338
|
modifiers_down(actions, click_options.keys)
|
333
339
|
yield actions
|
334
340
|
modifiers_up(actions, click_options.keys)
|
@@ -483,6 +489,10 @@ private
|
|
483
489
|
[options[:x], options[:y]]
|
484
490
|
end
|
485
491
|
|
492
|
+
def center_offset?
|
493
|
+
options[:offset] == :center
|
494
|
+
end
|
495
|
+
|
486
496
|
def empty?
|
487
497
|
keys.empty? && !coords?
|
488
498
|
end
|
@@ -57,6 +57,15 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
|
|
57
57
|
|
58
58
|
private
|
59
59
|
|
60
|
+
def perform_legacy_drag(element)
|
61
|
+
return super unless (browser_version < 77.0) && w3c? && !element.obscured?
|
62
|
+
|
63
|
+
# W3C Chrome/chromedriver < 77 doesn't maintain mouse button state across actions API performs
|
64
|
+
# https://bugs.chromium.org/p/chromedriver/issues/detail?id=2981
|
65
|
+
browser_action.release.perform
|
66
|
+
browser_action.click_and_hold(native).move_to(element.native).release.perform
|
67
|
+
end
|
68
|
+
|
60
69
|
def file_errors
|
61
70
|
@file_errors = ::Selenium::WebDriver.logger.suppress_deprecations do
|
62
71
|
[::Selenium::WebDriver::Error::ExpectedError]
|
@@ -114,27 +114,4 @@ private
|
|
114
114
|
def browser_version
|
115
115
|
driver.browser.capabilities[:browser_version].to_f
|
116
116
|
end
|
117
|
-
|
118
|
-
class ModifierKeysStack
|
119
|
-
def initialize
|
120
|
-
@stack = []
|
121
|
-
end
|
122
|
-
|
123
|
-
def include?(key)
|
124
|
-
@stack.flatten.include?(key)
|
125
|
-
end
|
126
|
-
|
127
|
-
def press(key)
|
128
|
-
@stack.last.push(key)
|
129
|
-
end
|
130
|
-
|
131
|
-
def push
|
132
|
-
@stack.push []
|
133
|
-
end
|
134
|
-
|
135
|
-
def pop
|
136
|
-
@stack.pop
|
137
|
-
end
|
138
|
-
end
|
139
|
-
private_constant :ModifierKeysStack
|
140
117
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# require 'capybara/selenium/extensions/html5_drag'
|
4
|
+
require 'capybara/selenium/extensions/modifier_keys_stack'
|
4
5
|
|
5
6
|
class Capybara::Selenium::SafariNode < Capybara::Selenium::Node
|
6
7
|
# include Html5Drag
|
@@ -118,27 +119,4 @@ private
|
|
118
119
|
shift left_shift right_shift
|
119
120
|
meta left_meta right_meta
|
120
121
|
command].freeze
|
121
|
-
|
122
|
-
class ModifierKeysStack
|
123
|
-
def initialize
|
124
|
-
@stack = []
|
125
|
-
end
|
126
|
-
|
127
|
-
def include?(key)
|
128
|
-
@stack.flatten.include?(key)
|
129
|
-
end
|
130
|
-
|
131
|
-
def press(key)
|
132
|
-
@stack.last.push(key)
|
133
|
-
end
|
134
|
-
|
135
|
-
def push
|
136
|
-
@stack.push []
|
137
|
-
end
|
138
|
-
|
139
|
-
def pop
|
140
|
-
@stack.pop
|
141
|
-
end
|
142
|
-
end
|
143
|
-
private_constant :ModifierKeysStack
|
144
122
|
end
|
@@ -46,7 +46,7 @@ module Capybara
|
|
46
46
|
DISABLE_MARKUP_TEMPLATE = <<~HTML
|
47
47
|
<script defer>(typeof jQuery !== 'undefined') && (jQuery.fx.off = true);</script>
|
48
48
|
<style>
|
49
|
-
%<selector>s {
|
49
|
+
%<selector>s, %<selector>s::before, %<selector>s::after {
|
50
50
|
transition: none !important;
|
51
51
|
animation-duration: 0s !important;
|
52
52
|
animation-delay: 0s !important;
|
@@ -8,7 +8,7 @@ module Capybara
|
|
8
8
|
automatic_reload match exact exact_text raise_server_errors visible_text_only
|
9
9
|
automatic_label_click enable_aria_label save_path asset_host default_host app_host
|
10
10
|
server_host server_port server_errors default_set_options disable_animation test_id
|
11
|
-
predicates_wait default_normalize_ws].freeze
|
11
|
+
predicates_wait default_normalize_ws w3c_click_offset].freeze
|
12
12
|
|
13
13
|
attr_accessor(*OPTIONS)
|
14
14
|
|
@@ -59,6 +59,8 @@ module Capybara
|
|
59
59
|
# See {Capybara.configure}
|
60
60
|
# @!method default_normalize_ws
|
61
61
|
# See {Capybara.configure}
|
62
|
+
# @!method w3c_click_offset
|
63
|
+
# See {Capybara.configure}
|
62
64
|
|
63
65
|
remove_method :server_host
|
64
66
|
|
@@ -39,6 +39,8 @@ Capybara::SpecHelper.spec '#have_no_ancestor' do
|
|
39
39
|
it 'should assert no matching ancestor' do
|
40
40
|
el = @session.find(:css, '#ancestor1')
|
41
41
|
expect(el).to have_no_ancestor(:css, '#child')
|
42
|
+
expect(el).to have_no_ancestor(:css, '#ancestor1_sibiling')
|
42
43
|
expect(el).not_to have_ancestor(:css, '#child')
|
44
|
+
expect(el).not_to have_ancestor(:css, '#ancestor1_sibiling')
|
43
45
|
end
|
44
46
|
end
|
@@ -419,6 +419,16 @@ Capybara::SpecHelper.spec 'node' do
|
|
419
419
|
expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
|
420
420
|
end
|
421
421
|
|
422
|
+
it 'should work with Dragula' do
|
423
|
+
@session.visit('/with_dragula')
|
424
|
+
@session.within(:css, '#sortable') do
|
425
|
+
src = @session.find('div', text: 'Item 1')
|
426
|
+
target = @session.find('div', text: 'Item 3')
|
427
|
+
src.drag_to target
|
428
|
+
expect(@session).to have_content(/Item 2.*Item 1/, normalize_ws: true)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
422
432
|
context 'HTML5', requires: %i[js html5_drag] do
|
423
433
|
it 'should HTML5 drag and drop an object' do
|
424
434
|
@session.visit('/with_js')
|
@@ -428,6 +438,14 @@ Capybara::SpecHelper.spec 'node' do
|
|
428
438
|
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5")]')
|
429
439
|
end
|
430
440
|
|
441
|
+
it 'should HTML5 drag and drop an object child' do
|
442
|
+
@session.visit('/with_js')
|
443
|
+
element = @session.find('//div[@id="drag_html5"]/p')
|
444
|
+
target = @session.find('//div[@id="drop_html5"]')
|
445
|
+
element.drag_to(target)
|
446
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5")]')
|
447
|
+
end
|
448
|
+
|
431
449
|
it 'should set clientX/Y in dragover events' do
|
432
450
|
@session.visit('/with_js')
|
433
451
|
element = @session.find('//div[@id="drag_html5"]')
|
@@ -471,6 +489,14 @@ Capybara::SpecHelper.spec 'node' do
|
|
471
489
|
expect(@session).to have_content(/Item 3.*Item 1/, normalize_ws: true)
|
472
490
|
end
|
473
491
|
end
|
492
|
+
|
493
|
+
it 'should drag HTML5 default draggable element child' do
|
494
|
+
@session.visit('/with_js')
|
495
|
+
source = @session.find_link('drag_link_html5').find(:css, 'p')
|
496
|
+
target = @session.find(:id, 'drop_html5')
|
497
|
+
source.drag_to target
|
498
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
|
499
|
+
end
|
474
500
|
end
|
475
501
|
end
|
476
502
|
|
@@ -635,6 +661,55 @@ Capybara::SpecHelper.spec 'node' do
|
|
635
661
|
JS
|
636
662
|
expect { obscured.click(wait: 0) }.to(raise_error { |e| expect(e).to be_an_invalid_element_error(@session) })
|
637
663
|
end
|
664
|
+
|
665
|
+
context 'offset', requires: [:js] do
|
666
|
+
before do
|
667
|
+
@session.visit('/offset')
|
668
|
+
@clicker = @session.find(:id, 'clicker')
|
669
|
+
end
|
670
|
+
|
671
|
+
context 'when w3c_click_offset is false' do
|
672
|
+
before do
|
673
|
+
Capybara.w3c_click_offset = false
|
674
|
+
end
|
675
|
+
|
676
|
+
it 'should offset from top left of element' do
|
677
|
+
@clicker.click(x: 10, y: 5)
|
678
|
+
expect(@session).to have_text(/clicked at 110,105/)
|
679
|
+
end
|
680
|
+
|
681
|
+
it 'should offset outside the element' do
|
682
|
+
@clicker.click(x: -15, y: -10)
|
683
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
684
|
+
end
|
685
|
+
|
686
|
+
it 'should default to click the middle' do
|
687
|
+
@clicker.click
|
688
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
context 'when w3c_click_offset is true' do
|
693
|
+
before do
|
694
|
+
Capybara.w3c_click_offset = true
|
695
|
+
end
|
696
|
+
|
697
|
+
it 'should offset from center of element' do
|
698
|
+
@clicker.click(x: 10, y: 5)
|
699
|
+
expect(@session).to have_text(/clicked at 160,155/)
|
700
|
+
end
|
701
|
+
|
702
|
+
it 'should offset outside from center of element' do
|
703
|
+
@clicker.click(x: -65, y: -60)
|
704
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
705
|
+
end
|
706
|
+
|
707
|
+
it 'should default to click the middle' do
|
708
|
+
@clicker.click
|
709
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
710
|
+
end
|
711
|
+
end
|
712
|
+
end
|
638
713
|
end
|
639
714
|
|
640
715
|
describe '#double_click', requires: [:js] do
|
@@ -669,6 +744,28 @@ Capybara::SpecHelper.spec 'node' do
|
|
669
744
|
JS
|
670
745
|
expect { obscured.double_click }.not_to raise_error
|
671
746
|
end
|
747
|
+
|
748
|
+
context 'offset', requires: [:js] do
|
749
|
+
before do
|
750
|
+
@session.visit('/offset')
|
751
|
+
@clicker = @session.find(:id, 'clicker')
|
752
|
+
end
|
753
|
+
|
754
|
+
it 'should offset from top left of element' do
|
755
|
+
@clicker.click(x: 10, y: 5)
|
756
|
+
expect(@session).to have_text(/clicked at 110,105/)
|
757
|
+
end
|
758
|
+
|
759
|
+
it 'should offset outside the element' do
|
760
|
+
@clicker.click(x: -15, y: -10)
|
761
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
762
|
+
end
|
763
|
+
|
764
|
+
it 'should default to click the middle' do
|
765
|
+
@clicker.click
|
766
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
767
|
+
end
|
768
|
+
end
|
672
769
|
end
|
673
770
|
|
674
771
|
describe '#right_click', requires: [:js] do
|
@@ -703,6 +800,28 @@ Capybara::SpecHelper.spec 'node' do
|
|
703
800
|
JS
|
704
801
|
expect { obscured.right_click }.not_to raise_error
|
705
802
|
end
|
803
|
+
|
804
|
+
context 'offset', requires: [:js] do
|
805
|
+
before do
|
806
|
+
@session.visit('/offset')
|
807
|
+
@clicker = @session.find(:id, 'clicker')
|
808
|
+
end
|
809
|
+
|
810
|
+
it 'should offset from top left of element' do
|
811
|
+
@clicker.click(x: 10, y: 5)
|
812
|
+
expect(@session).to have_text(/clicked at 110,105/)
|
813
|
+
end
|
814
|
+
|
815
|
+
it 'should offset outside the element' do
|
816
|
+
@clicker.click(x: -15, y: -10)
|
817
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
818
|
+
end
|
819
|
+
|
820
|
+
it 'should default to click the middle' do
|
821
|
+
@clicker.click
|
822
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
823
|
+
end
|
824
|
+
end
|
706
825
|
end
|
707
826
|
|
708
827
|
describe '#send_keys', requires: [:send_keys] do
|
@@ -79,7 +79,7 @@ Capybara::SpecHelper.spec Capybara::Selector do
|
|
79
79
|
it 'can find by class' do
|
80
80
|
expect(@session.find(:field, class: 'confusion-checkbox')['id']).to eq 'confusion_checkbox'
|
81
81
|
expect(@session).to have_selector(:field, class: 'confusion', count: 3)
|
82
|
-
expect(@session.find(:field, class: [
|
82
|
+
expect(@session.find(:field, class: %w[confusion confusion-textarea])['id']).to eq 'confusion_textarea'
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
4
|
+
<title>Offset</title>
|
5
|
+
<style>
|
6
|
+
body {
|
7
|
+
margin: 0px;
|
8
|
+
}
|
9
|
+
#wrapper {
|
10
|
+
width: 300px;
|
11
|
+
height: 300px;
|
12
|
+
margin: 0px;
|
13
|
+
}
|
14
|
+
#clicker {
|
15
|
+
position: relative;
|
16
|
+
width: 100px;
|
17
|
+
height: 100px;
|
18
|
+
top: 100px;
|
19
|
+
left: 100px;
|
20
|
+
background-color: red;
|
21
|
+
margin: 0px;
|
22
|
+
}
|
23
|
+
</style>
|
24
|
+
<script src="/jquery.js" type="text/javascript" charset="utf-8"></script>
|
25
|
+
<script src="/offset.js" type="text/javascript" charset="utf-8"></script>
|
26
|
+
</head>
|
27
|
+
<body>
|
28
|
+
<div id="wrapper">
|
29
|
+
<div id="clicker"></div>
|
30
|
+
</div>
|
31
|
+
</body>
|
32
|
+
</html>
|
@@ -6,6 +6,17 @@
|
|
6
6
|
<script src="/jquery.js" type="text/javascript" charset="utf-8"></script>
|
7
7
|
<script src="/jquery-ui.js" type="text/javascript" charset="utf-8"></script>
|
8
8
|
<script src="/test.js" type="text/javascript" charset="utf-8"></script>
|
9
|
+
<script type="text/javascript">
|
10
|
+
$(document).on('transitionend', function(){
|
11
|
+
$(document.body).append('<div>Transition Ended</div>')
|
12
|
+
});
|
13
|
+
$(document).on('animationend', function(){
|
14
|
+
$(document.body).append('<div>Animation Ended</div>')
|
15
|
+
});
|
16
|
+
$(document).on('contextmenu', function(e){
|
17
|
+
e.preventDefault();
|
18
|
+
});
|
19
|
+
</script>
|
9
20
|
<style>
|
10
21
|
.transition.away {
|
11
22
|
width: 0%;
|
@@ -17,6 +28,13 @@
|
|
17
28
|
overflow: hidden;
|
18
29
|
}
|
19
30
|
|
31
|
+
a::after {
|
32
|
+
content: "";
|
33
|
+
width: 0px;
|
34
|
+
height: 0px;
|
35
|
+
background-color: blue;
|
36
|
+
}
|
37
|
+
|
20
38
|
a:not(.away) {
|
21
39
|
height: 20px;
|
22
40
|
}
|
@@ -35,12 +53,22 @@
|
|
35
53
|
animation-duration: 3s;
|
36
54
|
animation-fill-mode: forwards;
|
37
55
|
}
|
56
|
+
|
57
|
+
@keyframes pseudo_grow {
|
58
|
+
100% { height: 100px, width: 100px };
|
59
|
+
}
|
60
|
+
|
61
|
+
a.animation.pseudo::after {
|
62
|
+
animation: pseudo_grow 3s forwards;
|
63
|
+
}
|
38
64
|
</style>
|
39
65
|
</head>
|
40
66
|
|
41
67
|
<body id="with_animation">
|
42
68
|
<a href='#' class='transition' onclick='this.classList.add("away")'>transition me away</a>
|
43
|
-
<a href='#' class='animation' onclick='this.classList.add("away")'
|
69
|
+
<a href='#' class='animation' onclick='this.classList.add("away")' oncontextmenu='this.classList.add("pseudo")'>
|
70
|
+
animate me away
|
71
|
+
</a>
|
44
72
|
</body>
|
45
73
|
</html>
|
46
74
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
2
|
+
<head>
|
3
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
4
|
+
<title>with_dragula</title>
|
5
|
+
|
6
|
+
</head>
|
7
|
+
|
8
|
+
<body id="with_dragula">
|
9
|
+
<div id="sortable">
|
10
|
+
<div class="item1">Item 1</div>
|
11
|
+
<div class="item2">Item 2</div>
|
12
|
+
<div class="item3">Item 3</div>
|
13
|
+
<div class="item4">Item 4</div>
|
14
|
+
<div class="item5">Item 5</div>
|
15
|
+
</div>
|
16
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.js" type="text/javascript"></script>
|
17
|
+
<script>
|
18
|
+
dragula([document.getElementById("sortable")]);
|
19
|
+
</script>
|
20
|
+
</body>
|
21
|
+
</html>
|
22
|
+
|
@@ -138,6 +138,9 @@ banana</textarea>
|
|
138
138
|
Ancestor
|
139
139
|
<div id="child">Child</div>
|
140
140
|
</div>
|
141
|
+
<div id="ancestor1_sibiling">
|
142
|
+
ASibling
|
143
|
+
</div>
|
141
144
|
</div>
|
142
145
|
<button id="ancestor_button" type="submit" disabled>
|
143
146
|
<img id="button_img" width="20" height="20" alt="button img"/>
|
@@ -28,7 +28,7 @@
|
|
28
28
|
<div id="drag_html5" draggable="true">
|
29
29
|
<p>This is an HTML5 draggable element.</p>
|
30
30
|
</div>
|
31
|
-
<a id="drag_link_html5" href="#">This is an HTML5 draggable link</a>
|
31
|
+
<a id="drag_link_html5" href="#"><p>This is an HTML5 draggable link</p></a>
|
32
32
|
<div id="drop_html5" class="drop">
|
33
33
|
<p>It should be dropped here.</p>
|
34
34
|
</div>
|
data/lib/capybara/version.rb
CHANGED
data/spec/selenium_spec_edge.rb
CHANGED
@@ -6,8 +6,12 @@ require 'shared_selenium_session'
|
|
6
6
|
require 'shared_selenium_node'
|
7
7
|
require 'rspec/shared_spec_matchers'
|
8
8
|
|
9
|
-
|
10
|
-
Selenium::WebDriver::
|
9
|
+
unless ENV['CI']
|
10
|
+
Selenium::WebDriver::Edge::Service.driver_path = '/usr/local/bin/msedgedriver'
|
11
|
+
Selenium::WebDriver::EdgeChrome.path = '/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary'
|
12
|
+
end
|
13
|
+
|
14
|
+
Webdrivers::Edgedriver.required_version = '76.0.168' if ENV['CI']
|
11
15
|
|
12
16
|
Capybara.register_driver :selenium_edge do |app|
|
13
17
|
# ::Selenium::WebDriver.logger.level = "debug"
|
@@ -57,7 +57,7 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumFirefox, 'selenium', capyba
|
|
57
57
|
when 'Capybara::Session selenium #attach_file with multipart form should fire change once when uploading multiple files from empty'
|
58
58
|
pending "FF < 62 doesn't support setting all files at once" if firefox_lt?(62, @session)
|
59
59
|
when 'Capybara::Session selenium #accept_confirm should work with nested modals'
|
60
|
-
skip 'Broken in FF
|
60
|
+
skip 'Broken in 63 <= FF < 69 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session) && firefox_lt?(69, @session)
|
61
61
|
when 'Capybara::Session selenium #click_link can download a file'
|
62
62
|
skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
|
63
63
|
when 'Capybara::Session selenium #reset_session! removes ALL cookies'
|
@@ -355,11 +355,17 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
355
355
|
expect(@animation_session).to have_no_link('transition me away', wait: 0.5)
|
356
356
|
end
|
357
357
|
|
358
|
-
it 'should disable CSS animations' do
|
358
|
+
it 'should disable CSS animations (set to 0s)' do
|
359
359
|
@animation_session.visit('with_animation')
|
360
360
|
@animation_session.click_link('animate me away')
|
361
361
|
expect(@animation_session).to have_no_link('animate me away', wait: 0.5)
|
362
362
|
end
|
363
|
+
|
364
|
+
it 'should disable CSS animations on pseudo elements (set to 0s)' do
|
365
|
+
@animation_session.visit('with_animation')
|
366
|
+
@animation_session.find_link('animate me away').right_click
|
367
|
+
expect(@animation_session).to have_content('Animation Ended', wait: 0.1)
|
368
|
+
end
|
363
369
|
end
|
364
370
|
|
365
371
|
context 'if we pass in css that matches elements' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capybara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.25.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Walpole
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain:
|
12
12
|
- gem-public_cert.pem
|
13
|
-
date: 2019-06-
|
13
|
+
date: 2019-06-28 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: addressable
|
@@ -268,16 +268,16 @@ dependencies:
|
|
268
268
|
name: rubocop
|
269
269
|
requirement: !ruby/object:Gem::Requirement
|
270
270
|
requirements:
|
271
|
-
- - "
|
271
|
+
- - "~>"
|
272
272
|
- !ruby/object:Gem::Version
|
273
|
-
version: '0'
|
273
|
+
version: '0.72'
|
274
274
|
type: :development
|
275
275
|
prerelease: false
|
276
276
|
version_requirements: !ruby/object:Gem::Requirement
|
277
277
|
requirements:
|
278
|
-
- - "
|
278
|
+
- - "~>"
|
279
279
|
- !ruby/object:Gem::Version
|
280
|
-
version: '0'
|
280
|
+
version: '0.72'
|
281
281
|
- !ruby/object:Gem::Dependency
|
282
282
|
name: rubocop-performance
|
283
283
|
requirement: !ruby/object:Gem::Requirement
|
@@ -516,6 +516,7 @@ files:
|
|
516
516
|
- lib/capybara/selenium/driver_specializations/safari_driver.rb
|
517
517
|
- lib/capybara/selenium/extensions/find.rb
|
518
518
|
- lib/capybara/selenium/extensions/html5_drag.rb
|
519
|
+
- lib/capybara/selenium/extensions/modifier_keys_stack.rb
|
519
520
|
- lib/capybara/selenium/extensions/scroll.rb
|
520
521
|
- lib/capybara/selenium/logger_suppressor.rb
|
521
522
|
- lib/capybara/selenium/node.rb
|
@@ -541,6 +542,7 @@ files:
|
|
541
542
|
- lib/capybara/spec/fixtures/test_file.txt
|
542
543
|
- lib/capybara/spec/public/jquery-ui.js
|
543
544
|
- lib/capybara/spec/public/jquery.js
|
545
|
+
- lib/capybara/spec/public/offset.js
|
544
546
|
- lib/capybara/spec/public/test.js
|
545
547
|
- lib/capybara/spec/session/accept_alert_spec.rb
|
546
548
|
- lib/capybara/spec/session/accept_confirm_spec.rb
|
@@ -646,6 +648,7 @@ files:
|
|
646
648
|
- lib/capybara/spec/views/host_links.erb
|
647
649
|
- lib/capybara/spec/views/initial_alert.erb
|
648
650
|
- lib/capybara/spec/views/obscured.erb
|
651
|
+
- lib/capybara/spec/views/offset.erb
|
649
652
|
- lib/capybara/spec/views/path.erb
|
650
653
|
- lib/capybara/spec/views/popup_one.erb
|
651
654
|
- lib/capybara/spec/views/popup_two.erb
|
@@ -656,6 +659,7 @@ files:
|
|
656
659
|
- lib/capybara/spec/views/with_animation.erb
|
657
660
|
- lib/capybara/spec/views/with_base_tag.erb
|
658
661
|
- lib/capybara/spec/views/with_count.erb
|
662
|
+
- lib/capybara/spec/views/with_dragula.erb
|
659
663
|
- lib/capybara/spec/views/with_fixed_header_footer.erb
|
660
664
|
- lib/capybara/spec/views/with_hover.erb
|
661
665
|
- lib/capybara/spec/views/with_hover1.erb
|