capybara 3.34.0 → 3.35.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +21 -3
  3. data/lib/capybara/node/base.rb +6 -6
  4. data/lib/capybara/node/matchers.rb +1 -1
  5. data/lib/capybara/queries/selector_query.rb +24 -8
  6. data/lib/capybara/registrations/drivers.rb +18 -12
  7. data/lib/capybara/registrations/servers.rb +1 -1
  8. data/lib/capybara/result.rb +3 -3
  9. data/lib/capybara/selector.rb +2 -2
  10. data/lib/capybara/selector/builders/css_builder.rb +1 -1
  11. data/lib/capybara/selector/builders/xpath_builder.rb +3 -1
  12. data/lib/capybara/selector/definition/button.rb +23 -14
  13. data/lib/capybara/selector/definition/table_row.rb +1 -1
  14. data/lib/capybara/selenium/atoms/src/isDisplayed.js +1 -1
  15. data/lib/capybara/selenium/driver.rb +20 -4
  16. data/lib/capybara/selenium/extensions/find.rb +1 -1
  17. data/lib/capybara/selenium/logger_suppressor.rb +1 -1
  18. data/lib/capybara/selenium/nodes/chrome_node.rb +3 -3
  19. data/lib/capybara/selenium/nodes/firefox_node.rb +6 -1
  20. data/lib/capybara/server/animation_disabler.rb +6 -2
  21. data/lib/capybara/spec/session/has_button_spec.rb +33 -0
  22. data/lib/capybara/spec/session/html_spec.rb +1 -1
  23. data/lib/capybara/spec/session/node_spec.rb +1 -1
  24. data/lib/capybara/spec/session/refresh_spec.rb +1 -1
  25. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  26. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  27. data/lib/capybara/spec/session/window/window_spec.rb +1 -1
  28. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  29. data/lib/capybara/spec/test_app.rb +1 -0
  30. data/lib/capybara/spec/views/form.erb +4 -0
  31. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  32. data/lib/capybara/spec/views/with_js.erb +1 -0
  33. data/lib/capybara/version.rb +1 -1
  34. data/spec/selector_spec.rb +15 -1
  35. data/spec/selenium_spec_chrome.rb +39 -18
  36. data/spec/selenium_spec_chrome_remote.rb +5 -1
  37. data/spec/selenium_spec_firefox.rb +15 -13
  38. data/spec/server_spec.rb +6 -2
  39. data/spec/shared_selenium_session.rb +14 -0
  40. metadata +46 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73f13e5f3cec460ee010f53337dcbf2d7e692a3b5c557110331d81c75f5f2897
4
- data.tar.gz: e137144d97fdb0c47a0464c07c4d12a39c36d62cc3c30aaa9201ed5676b2c66f
3
+ metadata.gz: 00bf1cfd1e72093422fb61df1dae86d72948e8026d57fb00084d5bedceb0967e
4
+ data.tar.gz: 65a8c6b66d1ef91586ca39f7eabcf800019f853e33e087d1bb65f02a85140c8b
5
5
  SHA512:
6
- metadata.gz: 8130baab61559c5221035964a776d72ab84a119be31a6b6534de14ca3ebb5ca1cdcd128ad2cd7d004c45d3ff5c7de0103a756cc3fdcf19fb154d874c876883a5
7
- data.tar.gz: 2379315a8629b50b0681fea69eb603d62d44c058df355f52151e319701d7577e5691fa43283848d0068c769bbd8be0a7890ddac904e7d7aa67e6be0a46261b7d
6
+ metadata.gz: f961de052aa75cb3e3a941ea031d40d6d0f1fc2a9a80190c7dbe2f7d8e96b462fa71d4ed96d4dc45687e2baaf151579ca4508a2753a6e2073814857e2dee9bb4
7
+ data.tar.gz: 4b02c84f7bd1d9da419e3f43848da87290ba303541df516e6217fd3fc2e4cf5263e212e9a4a5329c8505b2f6111c0ce6ea17537ea3099b04f12c9b662d364088
data/History.md CHANGED
@@ -1,13 +1,31 @@
1
+ # Version 3.35.0
2
+ Release date: 2020-01-25
3
+
4
+ ### Added
5
+
6
+ * Support Regexp matching for individual class names in :class filter passed an Array
7
+ * Animation disabler now supports JQuery animation disabling when JQuery loaded from body [Chien-Wei Huang]
8
+
9
+ ### Fixed
10
+
11
+ * :button selector type use with `enable_aria_role` [Sean Doyle]
12
+ * <label> elements don't associate with aria-role buttons
13
+ * Ignore Selenium::WebDriver::Error::InvalidSessionIdError when quitting driver [Robin Daugherty]
14
+ * Firefox: Don't click input when sending keys if already focused
15
+ * Miscellaneous issues with selenium-webdriver 4.0.0.alphas
16
+ * Nil return error in node details optimizations
17
+ * Animation disabler now inserts XHTML compliant content [Dale Morgan]
18
+
1
19
  # Version 3.34.0
2
20
  Release date: 2020-11-26
3
21
 
4
22
  ### Added
5
23
 
6
24
  * Ability to fill in with emoji when using Chrome with selenium driver (Firefox already worked)
7
- * Current path assetsions/expectations accept optional filter block
25
+ * Current path assertions/expectations accept optional filter block
8
26
  * Animation disabler now specifies `scroll-behavior: auto;` [Nathan Broadbent]
9
27
  * :button selector can now find elements by label text [Sean Doyle]
10
- * `Session#send_keys` to send keys to the current element with focus in drivers that support the
28
+ * `Session#send_keys` to send keys to the current element with focus in drivers that support the
11
29
  concept of a current element [Sean Doyle]
12
30
 
13
31
  ### Changed
@@ -21,7 +39,7 @@ Release date: 2020-11-26
21
39
  * Missing `readonly?` added to Node::Simple
22
40
  * Selenium version detection when loaded via alternate method [Joel Hawksley]
23
41
  * Connection count issue if REQUEST_URI value changed by app [Blake Williams]
24
- * Maintain URI fragment when redirecting in rack-test driver
42
+ * Maintain URI fragment when redirecting in rack-test driver
25
43
  * Text query error message [Wojciech Wnętrzak]
26
44
  * Checking a checkbox/radio button with `allow_label_click` now works if there are multiple labels (Issue #2421)
27
45
  * `drop` with `Pathname` (Issue #2424)[Máximo Mussini]
@@ -103,19 +103,19 @@ module Capybara
103
103
 
104
104
  # @api private
105
105
  def find_css(css, **options)
106
- if base.method(:find_css).arity != 1
107
- base.find_css(css, **options)
108
- else
106
+ if base.method(:find_css).arity == 1
109
107
  base.find_css(css)
108
+ else
109
+ base.find_css(css, **options)
110
110
  end
111
111
  end
112
112
 
113
113
  # @api private
114
114
  def find_xpath(xpath, **options)
115
- if base.method(:find_xpath).arity != 1
116
- base.find_xpath(xpath, **options)
117
- else
115
+ if base.method(:find_xpath).arity == 1
118
116
  base.find_xpath(xpath)
117
+ else
118
+ base.find_xpath(xpath, **options)
119
119
  end
120
120
  end
121
121
 
@@ -386,7 +386,7 @@ module Capybara
386
386
  #
387
387
  # page.has_field?('Email', type: 'email')
388
388
  #
389
- # Note: 'textarea' and 'select' are valid type values, matching the associated tag names.
389
+ # NOTE: 'textarea' and 'select' are valid type values, matching the associated tag names.
390
390
  #
391
391
  # @param [String] locator The label, name or id of a field to check for
392
392
  # @option options [String, Regexp] :with The text content of the field or a Regexp to match
@@ -239,16 +239,16 @@ module Capybara
239
239
 
240
240
  case selector_format
241
241
  when :css
242
- if node.method(:find_css).arity != 1
243
- node.find_css(css, **hints)
244
- else
242
+ if node.method(:find_css).arity == 1
245
243
  node.find_css(css)
244
+ else
245
+ node.find_css(css, **hints)
246
246
  end
247
247
  when :xpath
248
- if node.method(:find_xpath).arity != 1
249
- node.find_xpath(xpath(exact), **hints)
250
- else
248
+ if node.method(:find_xpath).arity == 1
251
249
  node.find_xpath(xpath(exact))
250
+ else
251
+ node.find_xpath(xpath(exact), **hints)
252
252
  end
253
253
  else
254
254
  raise ArgumentError, "Unknown format: #{selector_format}"
@@ -482,9 +482,25 @@ module Capybara
482
482
  end
483
483
 
484
484
  def matches_class_filter?(node)
485
- return true unless use_default_class_filter? && options[:class].is_a?(Regexp)
485
+ return true unless use_default_class_filter? && need_to_process_classes?
486
486
 
487
- options[:class].match? node[:class]
487
+ if options[:class].is_a? Regexp
488
+ options[:class].match? node[:class]
489
+ else
490
+ classes = (node[:class] || '').split
491
+ options[:class].select { |c| c.is_a? Regexp }.all? do |r|
492
+ classes.any? { |cls| r.match? cls }
493
+ end
494
+ end
495
+ end
496
+
497
+ def need_to_process_classes?
498
+ case options[:class]
499
+ when Regexp then true
500
+ when Array then options[:class].any?(Regexp)
501
+ else
502
+ false
503
+ end
488
504
  end
489
505
 
490
506
  def matches_style_filter?(node)
@@ -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
- browser_options = ::Selenium::WebDriver::Firefox::Options.new
14
- browser_options.args << '-headless'
15
- Capybara::Selenium::Driver.new(app, browser: :firefox, options: browser_options)
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.args << '--disable-site-isolation-trials'
25
+ opts.add_argument('--disable-site-isolation-trials')
23
26
  end
24
- Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
27
+
28
+ Capybara::Selenium::Driver.new(app, **Hash[:browser => :firefox, 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.args << '--headless'
31
- opts.args << '--disable-gpu' if Gem.win_platform?
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.args << '--disable-site-isolation-trials'
38
+ opts.add_argument('--disable-site-isolation-trials')
34
39
  end
35
- Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
40
+
41
+ Capybara::Selenium::Driver.new(app, **Hash[:browser => :firefox, options_key => browser_options])
36
42
  end
@@ -32,7 +32,7 @@ Capybara.register_server :puma do |app, port, host, **options|
32
32
  events = conf.options[:Silent] ? ::Puma::Events.strings : ::Puma::Events.stdio
33
33
 
34
34
  puma_ver = Gem::Version.new(Puma::Const::PUMA_VERSION)
35
- require_relative 'patches/puma_ssl' if (Gem::Version.new('4.0.0')...Gem::Version.new('4.1.0')).cover? puma_ver
35
+ require_relative 'patches/puma_ssl' if Gem::Requirement.new('>=4.0.0', '< 4.1.0').satisfied_by?(puma_ver)
36
36
 
37
37
  events.log 'Capybara starting Puma...'
38
38
  events.log "* Version #{Puma::Const::PUMA_VERSION} , codename: #{Puma::Const::CODE_NAME}"
@@ -54,10 +54,10 @@ module Capybara
54
54
  idx, length = args
55
55
  max_idx = case idx
56
56
  when Integer
57
- if !idx.negative?
58
- length.nil? ? idx : idx + length - 1
59
- else
57
+ if idx.negative?
60
58
  nil
59
+ else
60
+ length.nil? ? idx : idx + length - 1
61
61
  end
62
62
  when Range
63
63
  # idx.max is broken with beginless ranges
@@ -7,7 +7,7 @@ require 'capybara/selector/definition'
7
7
  #
8
8
  # All Selectors below support the listed selector specific filters in addition to the following system-wide filters
9
9
  # * :id (String, Regexp, XPath::Expression) - Matches the id attribute
10
- # * :class (String, Array<String>, Regexp, XPath::Expression) - Matches the class(es) provided
10
+ # * :class (String, Array<String | Regexp>, Regexp, XPath::Expression) - Matches the class(es) provided
11
11
  # * :style (String, Regexp, Hash<String, String>) - Match on elements style
12
12
  # * :above (Element) - Match elements above the passed element on the page
13
13
  # * :below (Element) - Match elements below the passed element on the page
@@ -171,7 +171,7 @@ require 'capybara/selector/definition'
171
171
  # * Filters:
172
172
  # * :\<any> (String, Regexp) - Match on any specified element attribute
173
173
  #
174
- class Capybara::Selector; end
174
+ class Capybara::Selector; end # rubocop:disable Lint/EmptyClass
175
175
 
176
176
  Capybara::Selector::FilterSet.add(:_field) do
177
177
  node_filter(:checked, :boolean) { |node, value| !(value ^ node.checked?) }
@@ -74,7 +74,7 @@ module Capybara
74
74
  end.join
75
75
  end
76
76
  else
77
- cls = Array(classes).group_by { |cl| cl.match?(/^!(?!!!)/) }
77
+ cls = Array(classes).reject { |c| c.is_a? Regexp }.group_by { |cl| cl.match?(/^!(?!!!)/) }
78
78
  [(cls[false].to_a.map { |cl| ".#{Capybara::Selector::CSS.escape(cl.sub(/^!!/, ''))}" } +
79
79
  cls[true].to_a.map { |cl| ":not(.#{Capybara::Selector::CSS.escape(cl.slice(1..-1))})" }).join]
80
80
  end
@@ -15,6 +15,8 @@ module Capybara
15
15
  def add_attribute_conditions(**conditions)
16
16
  @expression = conditions.inject(expression) do |xp, (name, value)|
17
17
  conditions = name == :class ? class_conditions(value) : attribute_conditions(name => value)
18
+ return xp if conditions.nil?
19
+
18
20
  if xp.is_a? XPath::Expression
19
21
  xp[conditions]
20
22
  else
@@ -47,7 +49,7 @@ module Capybara
47
49
  when XPath::Expression, Regexp
48
50
  attribute_conditions(class: classes)
49
51
  else
50
- Array(classes).map do |klass|
52
+ Array(classes).reject { |c| c.is_a? Regexp }.map do |klass|
51
53
  if klass.match?(/^!(?!!!)/)
52
54
  !XPath.attr(:class).contains_word(klass.slice(1..-1))
53
55
  else
@@ -4,32 +4,29 @@ Capybara.add_selector(:button, locator_type: [String, Symbol]) do
4
4
  xpath(:value, :title, :type, :name) do |locator, **options|
5
5
  input_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).one_of('submit', 'reset', 'image', 'button')]
6
6
  btn_xpath = XPath.descendant(:button)
7
- btn_xpath += XPath.descendant[XPath.attr(:role).equals('button')] if enable_aria_role
7
+ aria_btn_xpath = XPath.descendant[XPath.attr(:role).equals('button')]
8
8
  image_btn_xpath = XPath.descendant(:input)[XPath.attr(:type) == 'image']
9
9
 
10
10
  unless locator.nil?
11
11
  locator = locator.to_s
12
- locator_matchers = XPath.attr(:id).equals(locator) |
13
- XPath.attr(:name).equals(locator) |
14
- XPath.attr(:value).is(locator) |
15
- XPath.attr(:title).is(locator) |
16
- (XPath.attr(:id) == XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for))
17
- locator_matchers |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
18
- locator_matchers |= XPath.attr(test_id) == locator if test_id
12
+ locator_matchers = combine_locators(locator, config: self)
13
+ btn_matchers = locator_matchers |
14
+ XPath.string.n.is(locator) |
15
+ XPath.descendant(:img)[XPath.attr(:alt).is(locator)]
19
16
 
20
17
  input_btn_xpath = input_btn_xpath[locator_matchers] + locate_label(locator).descendant(input_btn_xpath)
21
-
22
- btn_xpath = btn_xpath[locator_matchers |
23
- XPath.string.n.is(locator) |
24
- XPath.descendant(:img)[XPath.attr(:alt).is(locator)]
25
- ] + locate_label(locator).descendant(btn_xpath)
18
+ btn_xpath = btn_xpath[btn_matchers] + locate_label(locator).descendant(btn_xpath)
19
+ aria_btn_xpath = aria_btn_xpath[btn_matchers]
26
20
 
27
21
  alt_matches = XPath.attr(:alt).is(locator)
28
22
  alt_matches |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
29
23
  image_btn_xpath = image_btn_xpath[alt_matches] + locate_label(locator).descendant(image_btn_xpath)
30
24
  end
31
25
 
32
- %i[value title type].inject(input_btn_xpath.union(btn_xpath).union(image_btn_xpath)) do |memo, ef|
26
+ btn_xpaths = [input_btn_xpath, btn_xpath, image_btn_xpath]
27
+ btn_xpaths << aria_btn_xpath if enable_aria_role
28
+
29
+ %i[value title type].inject(btn_xpaths.inject(&:union)) do |memo, ef|
33
30
  memo.where(find_by_attr(ef, options[ef]))
34
31
  end
35
32
  end
@@ -51,4 +48,16 @@ Capybara.add_selector(:button, locator_type: [String, Symbol]) do
51
48
  describe_node_filters do |disabled: nil, **|
52
49
  ' that is disabled' if disabled == true
53
50
  end
51
+
52
+ def combine_locators(locator, config:)
53
+ [
54
+ XPath.attr(:id).equals(locator),
55
+ XPath.attr(:name).equals(locator),
56
+ XPath.attr(:value).is(locator),
57
+ XPath.attr(:title).is(locator),
58
+ (XPath.attr(:id) == XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for)),
59
+ (XPath.attr(:'aria-label').is(locator) if config.enable_aria_label),
60
+ (XPath.attr(test_id) == locator if config.test_id)
61
+ ].compact.inject(&:|)
62
+ end
54
63
  end
@@ -9,7 +9,7 @@ Capybara.add_selector(:table_row, locator_type: [Array, Hash]) do
9
9
  cell_xp = XPath.descendant(:td)[
10
10
  XPath.string.n.is(cell) & XPath.position.equals(header_xp.preceding_sibling.count.plus(1))
11
11
  ]
12
- xp[cell_xp]
12
+ xp.where(cell_xp)
13
13
  end
14
14
  else
15
15
  initial_td = XPath.descendant(:td)[XPath.string.n.is(locator.shift)]
@@ -158,7 +158,7 @@
158
158
  // the overflow style of the body, and the body is really overflow:visible.
159
159
  var overflowElem = e;
160
160
  if (htmlOverflowStyle == "visible") {
161
- // Note: bodyElem will be null/undefined in SVG documents.
161
+ // NOTE: bodyElem will be null/undefined in SVG documents.
162
162
  if (e == htmlElem && bodyElem) {
163
163
  overflowElem = bodyElem;
164
164
  } else if (e == bodyElem) {
@@ -12,9 +12,13 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
12
12
  clear_session_storage: nil
13
13
  }.freeze
14
14
  SPECIAL_OPTIONS = %i[browser clear_local_storage clear_session_storage timeout native_displayed].freeze
15
+ CAPS_VERSION = Gem::Requirement.new('~> 4.0.0.alpha6')
16
+
15
17
  attr_reader :app, :options
16
18
 
17
19
  class << self
20
+ attr_reader :selenium_webdriver_version
21
+
18
22
  def load_selenium
19
23
  require 'selenium-webdriver'
20
24
  require 'capybara/selenium/logger_suppressor'
@@ -32,15 +36,18 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
32
36
  # Selenium::WebDriver::VERSION. Ideally we'd
33
37
  # use the constant in all cases, but earlier versions
34
38
  # of `selenium-webdriver` didn't provide the constant.
35
- selenium_webdriver_version =
39
+ @selenium_webdriver_version =
36
40
  if Gem.loaded_specs['selenium-webdriver']
37
41
  Gem.loaded_specs['selenium-webdriver'].version
38
42
  else
39
43
  Gem::Version.new(Selenium::WebDriver::VERSION)
40
44
  end
41
- if selenium_webdriver_version < Gem::Version.new('3.5.0')
45
+
46
+ unless Gem::Requirement.new('>= 3.5.0').satisfied_by? @selenium_webdriver_version
42
47
  warn "Warning: You're using an unsupported version of selenium-webdriver, please upgrade."
43
48
  end
49
+
50
+ @selenium_webdriver_version
44
51
  rescue LoadError => e
45
52
  raise e unless e.message.include?('selenium-webdriver')
46
53
 
@@ -66,7 +73,15 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
66
73
  end
67
74
  end
68
75
  processed_options = options.reject { |key, _val| SPECIAL_OPTIONS.include?(key) }
69
- @browser = Selenium::WebDriver.for(options[:browser], processed_options)
76
+
77
+ @browser = if options[:browser] == :firefox &&
78
+ RUBY_VERSION >= '3.0' &&
79
+ Capybara::Selenium::Driver.selenium_webdriver_version <= Gem::Version.new('4.0.0.alpha1')
80
+ # selenium-webdriver 3.x doesn't correctly pass options through for Firefox with Ruby 3 so workaround that
81
+ Selenium::WebDriver::Firefox::Driver.new(**processed_options)
82
+ else
83
+ Selenium::WebDriver.for(options[:browser], processed_options)
84
+ end
70
85
 
71
86
  specialize_driver
72
87
  setup_exit_handler
@@ -265,7 +280,8 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
265
280
 
266
281
  def quit
267
282
  @browser&.quit
268
- rescue Selenium::WebDriver::Error::SessionNotCreatedError, Errno::ECONNREFUSED
283
+ rescue Selenium::WebDriver::Error::SessionNotCreatedError, Errno::ECONNREFUSED,
284
+ Selenium::WebDriver::Error::InvalidSessionIdError
269
285
  # Browser must have already gone
270
286
  rescue Selenium::WebDriver::Error::UnknownError => e
271
287
  unless silenced_unknown_error_message?(e.message) # Most likely already gone
@@ -28,7 +28,7 @@ module Capybara
28
28
  hints_js, functions = build_hints_js(uses_visibility, styles, position)
29
29
  return [] unless functions.any?
30
30
 
31
- es_context.execute_script(hints_js, elements).map! do |results|
31
+ (es_context.execute_script(hints_js, elements) || []).map! do |results|
32
32
  hint = {}
33
33
  hint[:style] = results.pop if functions.include?(:style_func)
34
34
  hint[:position] = results.pop if functions.include?(:position_func)
@@ -8,7 +8,7 @@ module Capybara
8
8
  super
9
9
  end
10
10
 
11
- def deprecate(*)
11
+ def deprecate(*, **, &block)
12
12
  super unless @suppress_for_capybara
13
13
  end
14
14
 
@@ -118,15 +118,15 @@ private
118
118
  end
119
119
 
120
120
  def chromedriver_fixed_actions_key_state?
121
- Gem::Version.new(chromedriver_version) >= Gem::Version.new('76.0.3809.68')
121
+ Gem::Requirement.new('>= 76.0.3809.68').satisfied_by?(chromedriver_version)
122
122
  end
123
123
 
124
124
  def chromedriver_supports_displayed_endpoint?
125
- Gem::Version.new(chromedriver_version) >= Gem::Version.new('76.0.3809.25')
125
+ Gem::Requirement.new('>= 76.0.3809.25').satisfied_by?(chromedriver_version)
126
126
  end
127
127
 
128
128
  def chromedriver_version
129
- capabilities['chrome']['chromedriverVersion'].split(' ')[0]
129
+ Gem::Version.new(capabilities['chrome']['chromedriverVersion'].split(' ')[0]) # rubocop:disable Style/RedundantArgument
130
130
  end
131
131
 
132
132
  def native_displayed?
@@ -40,11 +40,16 @@ class Capybara::Selenium::FirefoxNode < Capybara::Selenium::Node
40
40
  path_names.each { |path| native.send_keys(path) }
41
41
  end
42
42
 
43
+ def focused?
44
+ driver.evaluate_script('arguments[0] == document.activeElement', self)
45
+ end
46
+
43
47
  def send_keys(*args)
44
48
  # https://github.com/mozilla/geckodriver/issues/846
45
49
  return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none?(Array)
46
50
 
47
- native.click
51
+ native.click unless focused?
52
+
48
53
  _send_keys(args).perform
49
54
  end
50
55
 
@@ -40,11 +40,15 @@ module Capybara
40
40
  end
41
41
 
42
42
  def insert_disable(html)
43
- html.sub(%r{(</head>)}, "#{disable_markup}\\1")
43
+ html.sub(%r{(</body>)}, "#{disable_markup}\\1")
44
44
  end
45
45
 
46
46
  DISABLE_MARKUP_TEMPLATE = <<~HTML
47
- <script defer>(typeof jQuery !== 'undefined') && (jQuery.fx.off = true);</script>
47
+ <script>
48
+ //<![CDATA[
49
+ (typeof jQuery !== 'undefined') && (jQuery.fx.off = true);
50
+ //]]>
51
+ </script>
48
52
  <style>
49
53
  %<selector>s, %<selector>s::before, %<selector>s::after {
50
54
  transition: none !important;
@@ -46,9 +46,25 @@ Capybara::SpecHelper.spec '#has_button?' do
46
46
  expect(@session).to have_button('ARIA button', enable_aria_role: true)
47
47
  end
48
48
 
49
+ it 'should be false for a role=button within a label when enable_aria_role: true' do
50
+ expect(@session).not_to have_button('role=button within label', enable_aria_role: true)
51
+ end
52
+
49
53
  it 'should be false for role=button when enable_aria_role: false' do
50
54
  expect(@session).not_to have_button('ARIA button', enable_aria_role: false)
51
55
  end
56
+
57
+ it 'should be false for a role=button within a label when enable_aria_role: false' do
58
+ expect(@session).not_to have_button('role=button within label', enable_aria_role: false)
59
+ end
60
+
61
+ it 'should not affect other selectors when enable_aria_role: true' do
62
+ expect(@session).to have_button('Click me!', enable_aria_role: true)
63
+ end
64
+
65
+ it 'should not affect other selectors when enable_aria_role: false' do
66
+ expect(@session).to have_button('Click me!', enable_aria_role: false)
67
+ end
52
68
  end
53
69
 
54
70
  Capybara::SpecHelper.spec '#has_no_button?' do
@@ -81,7 +97,24 @@ Capybara::SpecHelper.spec '#has_no_button?' do
81
97
  expect(@session).to have_no_button('ARIA button', enable_aria_role: false)
82
98
  end
83
99
 
100
+ it 'should be true for role=button within a label when enable_aria_role: false' do
101
+ expect(@session).to have_no_button('role=button within label', enable_aria_role: false)
102
+ end
103
+
84
104
  it 'should be false for role=button when enable_aria_role: true' do
85
105
  expect(@session).not_to have_no_button('ARIA button', enable_aria_role: true)
86
106
  end
107
+
108
+ it 'should be true for a role=button within a label when enable_aria_role: true' do
109
+ # label element does not associate with aria button
110
+ expect(@session).to have_no_button('role=button within label', enable_aria_role: true)
111
+ end
112
+
113
+ it 'should not affect other selectors when enable_aria_role: true' do
114
+ expect(@session).to have_no_button('Junk button that does not exist', enable_aria_role: true)
115
+ end
116
+
117
+ it 'should not affect other selectors when enable_aria_role: false' do
118
+ expect(@session).to have_no_button('Junk button that does not exist', enable_aria_role: false)
119
+ end
87
120
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Note: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
3
+ # NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
4
4
  # because of the methods being tested. In tests using Capybara this type of behavior should be implemented
5
5
  # using Capybara provided assertions with builtin waiting behavior.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Note: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
3
+ # NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
4
4
  # because of the methods being tested. In tests using Capybara this type of behavior should be implemented
5
5
  # using Capybara provided assertions with builtin waiting behavior.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Note: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
3
+ # NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
4
4
  # because of the methods being tested. In tests using Capybara this type of behavior should be implemented
5
5
  # using Capybara provided assertions with builtin waiting behavior.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Note: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
3
+ # NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
4
4
  # because of the methods being tested. In tests using Capybara this type of behavior should be implemented
5
5
  # using Capybara provided assertions with builtin waiting behavior.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Note: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
3
+ # NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
4
4
  # because of the methods being tested. In tests using Capybara this type of behavior should be implemented
5
5
  # using Capybara provided assertions with builtin waiting behavior.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Note: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
3
+ # NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
4
4
  # because of the methods being tested. In tests using Capybara this type of behavior should be implemented
5
5
  # using Capybara provided assertions with builtin waiting behavior.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Note: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
3
+ # NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
4
4
  # because of the methods being tested. In tests using Capybara this type of behavior should be implemented
5
5
  # using Capybara provided assertions with builtin waiting behavior.
6
6
 
@@ -7,6 +7,7 @@ require 'yaml'
7
7
 
8
8
  class TestApp < Sinatra::Base
9
9
  class TestAppError < Exception; end # rubocop:disable Lint/InheritException
10
+
10
11
  class TestAppOtherError < Exception # rubocop:disable Lint/InheritException
11
12
  def initialize(string1, msg)
12
13
  super()
@@ -462,6 +462,10 @@ New line after and before textarea tag
462
462
  button within label element
463
463
  <button></button>
464
464
  </label>
465
+ <label>
466
+ role=button within label element
467
+ <span role="button">with other text</span>
468
+ </label>
465
469
  <input type="button" disabled="disabled" value="Disabled button"/>
466
470
  <span role="button">ARIA button</span>
467
471
  </p>
@@ -0,0 +1,24 @@
1
+
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
5
+ <title>with_jquery_animation</title>
6
+ <style>
7
+ body {
8
+ height: 2000px;
9
+ }
10
+ </style>
11
+ </head>
12
+
13
+ <body id="with_animation">
14
+ <a href="#" id='scroll'>scroll top 500</a>
15
+
16
+ <script src="/jquery.js" type="text/javascript" charset="utf-8"></script>
17
+ <script type='text/javascript'>
18
+ $('#scroll').click(function(e){
19
+ e.preventDefault();
20
+ $('html, body').animate({ scrollTop: 500 }, 'slow');
21
+ });
22
+ </script>
23
+ </body>
24
+ </html>
@@ -36,6 +36,7 @@
36
36
  <p><a href="#" id="clickable">Click me</a></p>
37
37
  <p><a href="#" id="slow-click">Slowly</a></p>
38
38
  <p><span id="aria-button" role="button">ARIA button</span></p>
39
+ <p><span role="button">ARIA button2</span></p>
39
40
 
40
41
  <p>
41
42
  <select id="waiter">
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Capybara
4
- VERSION = '3.34.0'
4
+ VERSION = '3.35.0'
5
5
  end
@@ -327,9 +327,23 @@ RSpec.describe Capybara do
327
327
  expect(string.find(:custom_xpath_selector, './/div', class: /dOm WoR/i)[:id]).to eq 'random_words'
328
328
  end
329
329
 
330
- it 'accepts Regexp for CSS base selectors' do
330
+ it 'accepts Regexp for CSS based selectors' do
331
331
  expect(string.find(:custom_css_selector, 'div', class: /random/)[:id]).to eq 'random_words'
332
332
  end
333
+
334
+ it 'accepts Regexp for individual class names for XPath based selectors' do
335
+ expect(string.find(:custom_xpath_selector, './/div', class: [/random/, 'some'])[:id]).to eq 'random_words'
336
+ expect(string.find(:custom_xpath_selector, './/div', class: [/om/, /wor/])[:id]).to eq 'random_words'
337
+ expect { string.find(:custom_xpath_selector, './/div', class: [/not/, /wor/]) }.to raise_error(Capybara::ElementNotFound)
338
+ expect { string.find(:custom_xpath_selector, './/div', class: [/dom wor/]) }.to raise_error(Capybara::ElementNotFound)
339
+ end
340
+
341
+ it 'accepts Regexp for individual class names for CSS based selectors' do
342
+ expect(string.find(:custom_css_selector, 'div', class: [/random/])[:id]).to eq 'random_words'
343
+ expect(string.find(:custom_css_selector, 'div', class: [/om/, /wor/, 'some'])[:id]).to eq 'random_words'
344
+ expect { string.find(:custom_css_selector, 'div', class: [/not/, /wor/]) }.to raise_error(Capybara::ElementNotFound)
345
+ expect { string.find(:custom_css_selector, 'div', class: [/dom wor/]) }.to raise_error(Capybara::ElementNotFound)
346
+ end
333
347
  end
334
348
 
335
349
  context 'with :style option' do
@@ -19,39 +19,56 @@ browser_options.add_preference('download.default_directory', Capybara.save_path)
19
19
  browser_options.add_preference(:download, default_directory: Capybara.save_path)
20
20
 
21
21
  Capybara.register_driver :selenium_chrome do |app|
22
- Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options, timeout: 30).tap do |driver|
22
+ version = Capybara::Selenium::Driver.load_selenium
23
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
24
+ driver_options = { browser: :chrome, timeout: 30 }.tap do |opts|
25
+ opts[options_key] = browser_options
26
+ end
27
+
28
+ Capybara::Selenium::Driver.new(app, **driver_options).tap do |driver|
23
29
  # Set download dir for Chrome < 77
24
30
  driver.browser.download_path = Capybara.save_path
25
31
  end
26
32
  end
27
33
 
28
34
  Capybara.register_driver :selenium_chrome_not_clear_storage do |app|
29
- chrome_options = {
30
- browser: :chrome,
31
- options: browser_options
32
- }
33
- Capybara::Selenium::Driver.new(app, **chrome_options.merge(clear_local_storage: false, clear_session_storage: false))
35
+ version = Capybara::Selenium::Driver.load_selenium
36
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
37
+ chrome_options = { browser: :chrome, clear_local_storage: false, clear_session_storage: false }.tap do |opts|
38
+ opts[options_key] = browser_options
39
+ end
40
+
41
+ Capybara::Selenium::Driver.new(app, **chrome_options)
34
42
  end
35
43
 
36
44
  Capybara.register_driver :selenium_chrome_not_clear_session_storage do |app|
37
- chrome_options = {
38
- browser: :chrome,
39
- options: browser_options
40
- }
41
- Capybara::Selenium::Driver.new(app, **chrome_options.merge(clear_session_storage: false))
45
+ version = Capybara::Selenium::Driver.load_selenium
46
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
47
+ chrome_options = { browser: :chrome, clear_session_storage: false }.tap do |opts|
48
+ opts[options_key] = browser_options
49
+ end
50
+
51
+ Capybara::Selenium::Driver.new(app, **chrome_options)
42
52
  end
43
53
 
44
54
  Capybara.register_driver :selenium_chrome_not_clear_local_storage do |app|
45
- chrome_options = {
46
- browser: :chrome,
47
- options: browser_options
48
- }
49
- Capybara::Selenium::Driver.new(app, **chrome_options.merge(clear_local_storage: false))
55
+ version = Capybara::Selenium::Driver.load_selenium
56
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
57
+ chrome_options = { browser: :chrome, clear_local_storage: false }.tap do |opts|
58
+ opts[options_key] = browser_options
59
+ end
60
+ Capybara::Selenium::Driver.new(app, **chrome_options)
50
61
  end
51
62
 
52
63
  Capybara.register_driver :selenium_driver_subclass_with_chrome do |app|
64
+ version = Capybara::Selenium::Driver.load_selenium
65
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
53
66
  subclass = Class.new(Capybara::Selenium::Driver)
54
- subclass.new(app, browser: :chrome, options: browser_options, timeout: 30)
67
+ chrome_options = { browser: :chrome, timeout: 30 }.tap do |opts|
68
+ opts[options_key] = browser_options
69
+ end
70
+
71
+ subclass.new(app, **chrome_options)
55
72
  end
56
73
 
57
74
  module TestSessions
@@ -171,7 +188,7 @@ RSpec.describe 'Capybara::Session with chrome' do
171
188
  before { skip 'Only makes sense in W3C mode' if ENV['W3C'] == 'false' }
172
189
 
173
190
  it 'does not error getting log types' do
174
- skip if Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0]) < Gem::Version.new('75.0.3770.90')
191
+ skip if Gem::Requirement.new('< 75.0.3770.90').satisfied_by? chromedriver_version
175
192
  expect do
176
193
  session.driver.browser.manage.logs.available_types
177
194
  end.not_to raise_error
@@ -183,4 +200,8 @@ RSpec.describe 'Capybara::Session with chrome' do
183
200
  end.not_to raise_error
184
201
  end
185
202
  end
203
+
204
+ def chromedriver_version
205
+ Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0])
206
+ end
186
207
  end
@@ -81,7 +81,7 @@ RSpec.describe 'Capybara::Session with remote Chrome' do
81
81
  before { skip 'Only makes sense in W3C mode' if ENV['W3C'] == 'false' }
82
82
 
83
83
  it 'does not error when getting log types' do
84
- skip if Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0]) < Gem::Version.new('75.0.3770.90')
84
+ skip unless Gem::Requirement.new('>= 75.0.3770.90').satisfied_by? chromedriver_version
85
85
  expect do
86
86
  session.driver.browser.manage.logs.available_types
87
87
  end.not_to raise_error
@@ -93,4 +93,8 @@ RSpec.describe 'Capybara::Session with remote Chrome' do
93
93
  end.not_to raise_error
94
94
  end
95
95
  end
96
+
97
+ def chromedriver_version
98
+ Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0])
99
+ end
96
100
  end
@@ -14,28 +14,30 @@ browser_options.profile = Selenium::WebDriver::Firefox::Profile.new.tap do |prof
14
14
  profile['browser.download.dir'] = Capybara.save_path
15
15
  profile['browser.download.folderList'] = 2
16
16
  profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv'
17
+ profile['browser.startup.homepage'] = 'about:blank' # workaround bug in Selenium 4 alpha4-7
17
18
  end
18
19
 
19
20
  Capybara.register_driver :selenium_firefox do |app|
20
21
  # ::Selenium::WebDriver.logger.level = "debug"
21
- Capybara::Selenium::Driver.new(
22
- app,
23
- browser: :firefox,
24
- options: browser_options,
25
- timeout: 31
22
+ version = Capybara::Selenium::Driver.load_selenium
23
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
24
+ driver_options = { browser: :firefox, timeout: 31 }.tap do |opts|
25
+ opts[options_key] = browser_options
26
26
  # Get a trace level log from geckodriver
27
27
  # :driver_opts => { args: ['-vv'] }
28
- )
28
+ end
29
+
30
+ Capybara::Selenium::Driver.new(app, **driver_options)
29
31
  end
30
32
 
31
33
  Capybara.register_driver :selenium_firefox_not_clear_storage do |app|
32
- Capybara::Selenium::Driver.new(
33
- app,
34
- browser: :firefox,
35
- clear_local_storage: false,
36
- clear_session_storage: false,
37
- options: browser_options
38
- )
34
+ version = Capybara::Selenium::Driver.load_selenium
35
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
36
+ driver_options = { browser: :firefox, clear_local_storage: false, clear_session_storage: false }.tap do |opts|
37
+ opts[options_key] = browser_options
38
+ end
39
+
40
+ Capybara::Selenium::Driver.new(app, **driver_options)
39
41
  end
40
42
 
41
43
  module TestSessions
@@ -108,8 +108,12 @@ RSpec.describe Capybara::Server do
108
108
  expect(options.fetch(:environment)).to be_a(String)
109
109
  method.call(app, events, options)
110
110
  end
111
- described_class.new(app_proc).boot
112
- expect(Puma::Server).to have_received(:new)
111
+ server = described_class.new(app_proc).boot
112
+ expect(Puma::Server).to have_received(:new).with(
113
+ anything,
114
+ anything,
115
+ satisfy { |opts| opts.final_options[:Port] == server.port }
116
+ )
113
117
  ensure
114
118
  Capybara.server = :default
115
119
  end
@@ -411,6 +411,13 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
411
411
  JS
412
412
  expect(scroll_y).to eq 500
413
413
  end
414
+
415
+ it 'should scroll the page instantly without jquery animation', requires: [:js] do
416
+ @animation_session.visit('with_jquery_animation')
417
+ @animation_session.click_link('scroll top 500')
418
+ scroll_y = @animation_session.evaluate_script('window.scrollY')
419
+ expect(scroll_y).to eq 500
420
+ end
414
421
  end
415
422
 
416
423
  context 'when set to `false`' do
@@ -433,6 +440,13 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
433
440
  # measured over 0.5 seconds: 0, 75, 282, 478, 500
434
441
  expect(scroll_y).to be < 500
435
442
  end
443
+
444
+ it 'should scroll the page with jquery animation', requires: [:js] do
445
+ @animation_session.visit('with_jquery_animation')
446
+ @animation_session.click_link('scroll top 500')
447
+ scroll_y = @animation_session.evaluate_script('window.scrollY')
448
+ expect(scroll_y).to be < 500
449
+ end
436
450
  end
437
451
 
438
452
  context 'if we pass in css that matches elements' do
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.34.0
4
+ version: 3.35.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Walpole
8
8
  - Jonas Nicklas
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain:
12
12
  - gem-public_cert.pem
13
- date: 2020-11-26 00:00:00.000000000 Z
13
+ date: 2021-01-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: addressable
@@ -86,16 +86,22 @@ dependencies:
86
86
  name: regexp_parser
87
87
  requirement: !ruby/object:Gem::Requirement
88
88
  requirements:
89
- - - "~>"
89
+ - - ">="
90
90
  - !ruby/object:Gem::Version
91
91
  version: '1.5'
92
+ - - "<"
93
+ - !ruby/object:Gem::Version
94
+ version: '3.0'
92
95
  type: :runtime
93
96
  prerelease: false
94
97
  version_requirements: !ruby/object:Gem::Requirement
95
98
  requirements:
96
- - - "~>"
99
+ - - ">="
97
100
  - !ruby/object:Gem::Version
98
101
  version: '1.5'
102
+ - - "<"
103
+ - !ruby/object:Gem::Version
104
+ version: '3.0'
99
105
  - !ruby/object:Gem::Dependency
100
106
  name: xpath
101
107
  requirement: !ruby/object:Gem::Requirement
@@ -270,14 +276,28 @@ dependencies:
270
276
  requirements:
271
277
  - - "~>"
272
278
  - !ruby/object:Gem::Version
273
- version: 1.1.0
279
+ version: '1.1'
274
280
  type: :development
275
281
  prerelease: false
276
282
  version_requirements: !ruby/object:Gem::Requirement
277
283
  requirements:
278
284
  - - "~>"
279
285
  - !ruby/object:Gem::Version
280
- version: 1.1.0
286
+ version: '1.1'
287
+ - !ruby/object:Gem::Dependency
288
+ name: rubocop-minitest
289
+ requirement: !ruby/object:Gem::Requirement
290
+ requirements:
291
+ - - ">="
292
+ - !ruby/object:Gem::Version
293
+ version: '0'
294
+ type: :development
295
+ prerelease: false
296
+ version_requirements: !ruby/object:Gem::Requirement
297
+ requirements:
298
+ - - ">="
299
+ - !ruby/object:Gem::Version
300
+ version: '0'
281
301
  - !ruby/object:Gem::Dependency
282
302
  name: rubocop-performance
283
303
  requirement: !ruby/object:Gem::Requirement
@@ -292,20 +312,34 @@ dependencies:
292
312
  - - ">="
293
313
  - !ruby/object:Gem::Version
294
314
  version: '0'
315
+ - !ruby/object:Gem::Dependency
316
+ name: rubocop-rake
317
+ requirement: !ruby/object:Gem::Requirement
318
+ requirements:
319
+ - - ">="
320
+ - !ruby/object:Gem::Version
321
+ version: '0'
322
+ type: :development
323
+ prerelease: false
324
+ version_requirements: !ruby/object:Gem::Requirement
325
+ requirements:
326
+ - - ">="
327
+ - !ruby/object:Gem::Version
328
+ version: '0'
295
329
  - !ruby/object:Gem::Dependency
296
330
  name: rubocop-rspec
297
331
  requirement: !ruby/object:Gem::Requirement
298
332
  requirements:
299
333
  - - "~>"
300
334
  - !ruby/object:Gem::Version
301
- version: 2.0.0.pre
335
+ version: '2.0'
302
336
  type: :development
303
337
  prerelease: false
304
338
  version_requirements: !ruby/object:Gem::Requirement
305
339
  requirements:
306
340
  - - "~>"
307
341
  - !ruby/object:Gem::Version
308
- version: 2.0.0.pre
342
+ version: '2.0'
309
343
  - !ruby/object:Gem::Dependency
310
344
  name: sauce_whisk
311
345
  requirement: !ruby/object:Gem::Requirement
@@ -672,6 +706,7 @@ files:
672
706
  - lib/capybara/spec/views/with_html.erb
673
707
  - lib/capybara/spec/views/with_html5_svg.erb
674
708
  - lib/capybara/spec/views/with_html_entities.erb
709
+ - lib/capybara/spec/views/with_jquery_animation.erb
675
710
  - lib/capybara/spec/views/with_js.erb
676
711
  - lib/capybara/spec/views/with_jstree.erb
677
712
  - lib/capybara/spec/views/with_namespace.erb
@@ -730,7 +765,7 @@ licenses:
730
765
  metadata:
731
766
  changelog_uri: https://github.com/teamcapybara/capybara/blob/master/History.md
732
767
  source_code_uri: https://github.com/teamcapybara/capybara
733
- post_install_message:
768
+ post_install_message:
734
769
  rdoc_options: []
735
770
  require_paths:
736
771
  - lib
@@ -746,7 +781,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
746
781
  version: '0'
747
782
  requirements: []
748
783
  rubygems_version: 3.1.4
749
- signing_key:
784
+ signing_key:
750
785
  specification_version: 4
751
786
  summary: Capybara aims to simplify the process of integration testing Rack applications,
752
787
  such as Rails, Sinatra or Merb