capybara 3.30.0 → 3.35.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +153 -13
  3. data/README.md +9 -4
  4. data/lib/capybara.rb +18 -8
  5. data/lib/capybara/config.rb +4 -6
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/driver/base.rb +4 -0
  8. data/lib/capybara/dsl.rb +10 -2
  9. data/lib/capybara/helpers.rb +25 -1
  10. data/lib/capybara/minitest.rb +232 -144
  11. data/lib/capybara/minitest/spec.rb +156 -97
  12. data/lib/capybara/node/actions.rb +16 -21
  13. data/lib/capybara/node/base.rb +6 -6
  14. data/lib/capybara/node/element.rb +14 -13
  15. data/lib/capybara/node/finders.rb +12 -7
  16. data/lib/capybara/node/matchers.rb +36 -27
  17. data/lib/capybara/node/simple.rb +6 -2
  18. data/lib/capybara/queries/ancestor_query.rb +1 -1
  19. data/lib/capybara/queries/base_query.rb +2 -1
  20. data/lib/capybara/queries/current_path_query.rb +14 -4
  21. data/lib/capybara/queries/selector_query.rb +40 -18
  22. data/lib/capybara/queries/sibling_query.rb +1 -1
  23. data/lib/capybara/queries/style_query.rb +1 -1
  24. data/lib/capybara/queries/text_query.rb +7 -1
  25. data/lib/capybara/rack_test/browser.rb +9 -3
  26. data/lib/capybara/rack_test/driver.rb +1 -0
  27. data/lib/capybara/rack_test/form.rb +1 -1
  28. data/lib/capybara/rack_test/node.rb +35 -10
  29. data/lib/capybara/registration_container.rb +44 -0
  30. data/lib/capybara/registrations/drivers.rb +18 -12
  31. data/lib/capybara/registrations/patches/puma_ssl.rb +3 -1
  32. data/lib/capybara/registrations/servers.rb +3 -2
  33. data/lib/capybara/result.rb +35 -15
  34. data/lib/capybara/rspec.rb +2 -0
  35. data/lib/capybara/rspec/matcher_proxies.rb +5 -5
  36. data/lib/capybara/rspec/matchers.rb +33 -32
  37. data/lib/capybara/rspec/matchers/base.rb +12 -6
  38. data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
  39. data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
  40. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  41. data/lib/capybara/rspec/matchers/have_selector.rb +15 -7
  42. data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
  43. data/lib/capybara/rspec/matchers/have_text.rb +3 -3
  44. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  45. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  46. data/lib/capybara/rspec/matchers/match_style.rb +7 -2
  47. data/lib/capybara/rspec/matchers/spatial_sugar.rb +2 -1
  48. data/lib/capybara/selector.rb +14 -3
  49. data/lib/capybara/selector/builders/css_builder.rb +1 -1
  50. data/lib/capybara/selector/builders/xpath_builder.rb +3 -1
  51. data/lib/capybara/selector/definition.rb +11 -9
  52. data/lib/capybara/selector/definition/button.rb +26 -14
  53. data/lib/capybara/selector/definition/css.rb +1 -1
  54. data/lib/capybara/selector/definition/datalist_input.rb +1 -1
  55. data/lib/capybara/selector/definition/element.rb +2 -1
  56. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  57. data/lib/capybara/selector/definition/label.rb +2 -2
  58. data/lib/capybara/selector/definition/link.rb +8 -0
  59. data/lib/capybara/selector/definition/select.rb +32 -13
  60. data/lib/capybara/selector/definition/table.rb +1 -1
  61. data/lib/capybara/selector/definition/table_row.rb +2 -2
  62. data/lib/capybara/selector/filter_set.rb +2 -2
  63. data/lib/capybara/selector/selector.rb +9 -1
  64. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
  65. data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
  66. data/lib/capybara/selenium/atoms/src/isDisplayed.js +1 -1
  67. data/lib/capybara/selenium/driver.rb +52 -7
  68. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +10 -12
  69. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -11
  70. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +3 -3
  71. data/lib/capybara/selenium/extensions/find.rb +4 -4
  72. data/lib/capybara/selenium/extensions/html5_drag.rb +24 -8
  73. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  74. data/lib/capybara/selenium/logger_suppressor.rb +8 -2
  75. data/lib/capybara/selenium/node.rb +96 -16
  76. data/lib/capybara/selenium/nodes/chrome_node.rb +27 -16
  77. data/lib/capybara/selenium/nodes/edge_node.rb +1 -1
  78. data/lib/capybara/selenium/nodes/firefox_node.rb +9 -4
  79. data/lib/capybara/selenium/nodes/safari_node.rb +1 -1
  80. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  81. data/lib/capybara/selenium/patches/atoms.rb +4 -4
  82. data/lib/capybara/selenium/patches/logs.rb +7 -9
  83. data/lib/capybara/server/animation_disabler.rb +8 -3
  84. data/lib/capybara/server/middleware.rb +4 -2
  85. data/lib/capybara/session.rb +53 -29
  86. data/lib/capybara/session/config.rb +3 -1
  87. data/lib/capybara/session/matchers.rb +11 -11
  88. data/lib/capybara/spec/public/test.js +64 -7
  89. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  90. data/lib/capybara/spec/session/all_spec.rb +45 -5
  91. data/lib/capybara/spec/session/assert_text_spec.rb +5 -5
  92. data/lib/capybara/spec/session/check_spec.rb +6 -0
  93. data/lib/capybara/spec/session/click_button_spec.rb +11 -0
  94. data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
  95. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  96. data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
  97. data/lib/capybara/spec/session/find_spec.rb +11 -8
  98. data/lib/capybara/spec/session/has_button_spec.rb +51 -0
  99. data/lib/capybara/spec/session/has_css_spec.rb +14 -10
  100. data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
  101. data/lib/capybara/spec/session/has_field_spec.rb +16 -0
  102. data/lib/capybara/spec/session/has_select_spec.rb +32 -4
  103. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  104. data/lib/capybara/spec/session/has_text_spec.rb +5 -12
  105. data/lib/capybara/spec/session/html_spec.rb +1 -1
  106. data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
  107. data/lib/capybara/spec/session/node_spec.rb +169 -33
  108. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  109. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  110. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  111. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  112. data/lib/capybara/spec/session/window/window_spec.rb +8 -8
  113. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  114. data/lib/capybara/spec/spec_helper.rb +13 -14
  115. data/lib/capybara/spec/test_app.rb +23 -21
  116. data/lib/capybara/spec/views/form.erb +36 -3
  117. data/lib/capybara/spec/views/with_animation.erb +8 -0
  118. data/lib/capybara/spec/views/with_dragula.erb +3 -1
  119. data/lib/capybara/spec/views/with_html.erb +2 -2
  120. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  121. data/lib/capybara/spec/views/with_js.erb +3 -0
  122. data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
  123. data/lib/capybara/version.rb +1 -1
  124. data/lib/capybara/window.rb +3 -7
  125. data/spec/basic_node_spec.rb +9 -8
  126. data/spec/capybara_spec.rb +1 -1
  127. data/spec/dsl_spec.rb +14 -1
  128. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  129. data/spec/minitest_spec.rb +3 -2
  130. data/spec/rack_test_spec.rb +28 -6
  131. data/spec/regexp_dissassembler_spec.rb +0 -4
  132. data/spec/result_spec.rb +40 -29
  133. data/spec/rspec/features_spec.rb +3 -1
  134. data/spec/rspec/scenarios_spec.rb +4 -0
  135. data/spec/rspec/shared_spec_matchers.rb +63 -51
  136. data/spec/rspec_spec.rb +4 -0
  137. data/spec/selector_spec.rb +17 -2
  138. data/spec/selenium_spec_chrome.rb +45 -21
  139. data/spec/selenium_spec_chrome_remote.rb +7 -1
  140. data/spec/selenium_spec_firefox.rb +15 -13
  141. data/spec/server_spec.rb +60 -49
  142. data/spec/shared_selenium_node.rb +18 -0
  143. data/spec/shared_selenium_session.rb +98 -7
  144. data/spec/spec_helper.rb +1 -1
  145. metadata +50 -14
  146. data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -18,7 +18,7 @@ class Capybara::Selenium::EdgeNode < Capybara::Selenium::Node
18
18
  # In Chrome 75+ files are appended (due to WebDriver spec - why?) so we have to clear here if its multiple and already set
19
19
  if chrome_edge?
20
20
  driver.execute_script(<<~JS, self)
21
- if (arguments[0].multiple && (arguments[0].files.length > 0)){
21
+ if (arguments[0].multiple && arguments[0].files.length){
22
22
  arguments[0].value = null;
23
23
  }
24
24
  JS
@@ -26,7 +26,7 @@ class Capybara::Selenium::FirefoxNode < Capybara::Selenium::Node
26
26
  def set_file(value) # rubocop:disable Naming/AccessorMethodName
27
27
  # By default files are appended so we have to clear here if its multiple and already set
28
28
  driver.execute_script(<<~JS, self)
29
- if (arguments[0].multiple && (arguments[0].files.length > 0)){
29
+ if (arguments[0].multiple && arguments[0].files.length){
30
30
  arguments[0].value = null;
31
31
  }
32
32
  JS
@@ -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
- return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none? { |arg| arg.is_a? Array }
49
+ return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none?(Array)
50
+
51
+ native.click unless focused?
46
52
 
47
- native.click
48
53
  _send_keys(args).perform
49
54
  end
50
55
 
@@ -85,7 +90,7 @@ private
85
90
  (driver.options[:native_displayed] != false) && !ENV['DISABLE_CAPYBARA_SELENIUM_OPTIMIZATIONS']
86
91
  end
87
92
 
88
- def click_with_options(click_options)
93
+ def perform_with_options(click_options)
89
94
  # Firefox/marionette has an issue clicking with offset near viewport edge
90
95
  # scroll element to middle just in case
91
96
  scroll_to_center if click_options.coords?
@@ -43,7 +43,7 @@ class Capybara::Selenium::SafariNode < Capybara::Selenium::Node
43
43
  return '' unless visible?
44
44
 
45
45
  vis_text = driver.execute_script('return arguments[0].innerText', self)
46
- vis_text.gsub(/\ +/, ' ')
46
+ vis_text.squeeze(' ')
47
47
  .gsub(/[\ \n]*\n[\ \n]*/, "\n")
48
48
  .gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
49
49
  .gsub(/[[:space:]&&[^\u00a0]]+\z/, '')
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionPauser
4
+ def initialize(mouse, keyboard)
5
+ super
6
+ @devices[:pauser] = Pauser.new
7
+ end
8
+
9
+ def pause(duration)
10
+ @actions << [:pauser, :pause, [duration]]
11
+ self
12
+ end
13
+
14
+ class Pauser
15
+ def pause(duration)
16
+ sleep duration
17
+ end
18
+ end
19
+
20
+ private_constant :Pauser
21
+ end
22
+
23
+ if defined?(::Selenium::WebDriver::VERSION) && (::Selenium::WebDriver::VERSION.to_f < 4) &&
24
+ defined?(::Selenium::WebDriver::ActionBuilder)
25
+ ::Selenium::WebDriver::ActionBuilder.prepend(ActionPauser)
26
+ end
@@ -6,10 +6,10 @@ private
6
6
  def read_atom(function)
7
7
  @atoms ||= Hash.new do |hash, key|
8
8
  hash[key] = begin
9
- File.read(File.expand_path("../../atoms/#{key}.min.js", __FILE__))
10
- rescue Errno::ENOENT
11
- super
12
- end
9
+ File.read(File.expand_path("../../atoms/#{key}.min.js", __FILE__))
10
+ rescue Errno::ENOENT
11
+ super
12
+ end
13
13
  end
14
14
  @atoms[function]
15
15
  end
@@ -27,17 +27,15 @@ module Capybara
27
27
 
28
28
  def log(type)
29
29
  data = begin
30
- execute :get_log, {}, type: type.to_s
31
- rescue ::Selenium::WebDriver::Error::UnknownCommandError
32
- execute :get_log_legacy, {}, type: type.to_s
33
- end
30
+ execute :get_log, {}, type: type.to_s
31
+ rescue ::Selenium::WebDriver::Error::UnknownCommandError
32
+ execute :get_log_legacy, {}, type: type.to_s
33
+ end
34
34
 
35
35
  Array(data).map do |l|
36
- begin
37
- ::Selenium::WebDriver::LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
38
- rescue KeyError
39
- next
40
- end
36
+ ::Selenium::WebDriver::LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
37
+ rescue KeyError
38
+ next
41
39
  end
42
40
  rescue ::Selenium::WebDriver::Error::UnknownCommandError
43
41
  raise NotImplementedError, LOG_MSG
@@ -40,16 +40,21 @@ 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
- %<selector>s, %<selector>s::before, %<selector>s::after {
53
+ %<selector>s, %<selector>s::before, %<selector>s::after {
50
54
  transition: none !important;
51
55
  animation-duration: 0s !important;
52
56
  animation-delay: 0s !important;
57
+ scroll-behavior: auto !important;
53
58
  }
54
59
  </style>
55
60
  HTML
@@ -53,14 +53,16 @@ module Capybara
53
53
  if env['PATH_INFO'] == '/__identify__'
54
54
  [200, {}, [@app.object_id.to_s]]
55
55
  else
56
- @counter.increment(env['REQUEST_URI'])
56
+ request_uri = env['REQUEST_URI']
57
+ @counter.increment(request_uri)
58
+
57
59
  begin
58
60
  @extended_app.call(env)
59
61
  rescue *@server_errors => e
60
62
  @error ||= e
61
63
  raise e
62
64
  ensure
63
- @counter.decrement(env['REQUEST_URI'])
65
+ @counter.decrement(request_uri)
64
66
  end
65
67
  end
66
68
  end
@@ -58,7 +58,7 @@ module Capybara
58
58
  ].freeze
59
59
  SESSION_METHODS = %i[
60
60
  body html source current_url current_host current_path
61
- execute_script evaluate_script visit refresh go_back go_forward
61
+ execute_script evaluate_script visit refresh go_back go_forward send_keys
62
62
  within within_element within_fieldset within_table within_frame switch_to_frame
63
63
  current_window windows open_new_window switch_to_window within_window window_opened_by
64
64
  save_page save_and_open_page save_screenshot
@@ -97,8 +97,8 @@ module Capybara
97
97
 
98
98
  def driver
99
99
  @driver ||= begin
100
- unless Capybara.drivers.key?(mode)
101
- other_drivers = Capybara.drivers.keys.map(&:inspect)
100
+ unless Capybara.drivers[mode]
101
+ other_drivers = Capybara.drivers.names.map(&:inspect)
102
102
  raise Capybara::DriverNotFoundError, "no driver called #{mode.inspect} was found, available drivers: #{other_drivers.join(', ')}"
103
103
  end
104
104
  driver = Capybara.drivers[mode].call(app)
@@ -192,7 +192,7 @@ module Capybara
192
192
  # @return [String] A snapshot of the DOM of the current document, as it looks right now (potentially modified by JavaScript).
193
193
  #
194
194
  def html
195
- driver.html
195
+ driver.html || ''
196
196
  end
197
197
  alias_method :body, :html
198
198
  alias_method :source, :html
@@ -303,6 +303,14 @@ module Capybara
303
303
  driver.go_forward
304
304
  end
305
305
 
306
+ ##
307
+ # @!method send_keys
308
+ # @see Capybara::Node::Element#send_keys
309
+ #
310
+ def send_keys(*args, **kw_args)
311
+ driver.send_keys(*args, **kw_args)
312
+ end
313
+
306
314
  ##
307
315
  #
308
316
  # Executes the given block within the context of a node. {#within} takes the
@@ -338,8 +346,8 @@ module Capybara
338
346
  #
339
347
  # @raise [Capybara::ElementNotFound] If the scope can't be found before time expires
340
348
  #
341
- def within(*args)
342
- new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args)
349
+ def within(*args, **kw_args)
350
+ new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args, **kw_args)
343
351
  begin
344
352
  scopes.push(new_scope)
345
353
  yield if block_given?
@@ -355,8 +363,8 @@ module Capybara
355
363
  #
356
364
  # @param [String] locator Id or legend of the fieldset
357
365
  #
358
- def within_fieldset(locator)
359
- within(:fieldset, locator) { yield }
366
+ def within_fieldset(locator, &block)
367
+ within(:fieldset, locator, &block)
360
368
  end
361
369
 
362
370
  ##
@@ -365,8 +373,8 @@ module Capybara
365
373
  #
366
374
  # @param [String] locator Id or caption of the table
367
375
  #
368
- def within_table(locator)
369
- within(:table, locator) { yield }
376
+ def within_table(locator, &block)
377
+ within(:table, locator, &block)
370
378
  end
371
379
 
372
380
  ##
@@ -398,8 +406,9 @@ module Capybara
398
406
  driver.switch_to_frame(:parent)
399
407
  when :top
400
408
  idx = scopes.index(:frame)
409
+ top_level_scopes = [:frame, nil]
401
410
  if idx
402
- if scopes.slice(idx..-1).any? { |scope| ![:frame, nil].include?(scope) }
411
+ if scopes.slice(idx..-1).any? { |scope| !top_level_scopes.include?(scope) }
403
412
  raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's "\
404
413
  '`within` block.'
405
414
  end
@@ -423,8 +432,8 @@ module Capybara
423
432
  # @param [String] locator The locator for the given selector kind. For :frame this is the name/id of a frame/iframe element
424
433
  # @overload within_frame(index)
425
434
  # @param [Integer] index index of a frame (0 based)
426
- def within_frame(*args)
427
- switch_to_frame(_find_frame(*args))
435
+ def within_frame(*args, **kw_args)
436
+ switch_to_frame(_find_frame(*args, **kw_args))
428
437
  begin
429
438
  yield if block_given?
430
439
  ensure
@@ -488,8 +497,8 @@ module Capybara
488
497
  # @raise [ArgumentError] if both or neither arguments were provided
489
498
  #
490
499
  def switch_to_window(window = nil, **options, &window_locator)
491
- raise ArgumentError, '`switch_to_window` can take either a block or a window, not both' if window && block_given?
492
- raise ArgumentError, '`switch_to_window`: either window or block should be provided' if !window && !block_given?
500
+ raise ArgumentError, '`switch_to_window` can take either a block or a window, not both' if window && window_locator
501
+ raise ArgumentError, '`switch_to_window`: either window or block should be provided' if !window && !window_locator
493
502
 
494
503
  unless scopes.last.nil?
495
504
  raise Capybara::ScopeError, '`switch_to_window` is not supposed to be invoked from '\
@@ -738,7 +747,7 @@ module Capybara
738
747
  # @param [Hash] options a customizable set of options
739
748
  #
740
749
  def save_and_open_screenshot(path = nil, **options)
741
- save_screenshot(path, **options).tap { |s_path| open_file(s_path) } # rubocop:disable Lint/Debugger
750
+ save_screenshot(path, **options).tap { |s_path| open_file(s_path) }
742
751
  end
743
752
 
744
753
  def document
@@ -746,15 +755,32 @@ module Capybara
746
755
  end
747
756
 
748
757
  NODE_METHODS.each do |method|
749
- define_method method do |*args, &block|
750
- @touched = true
751
- current_scope.send(method, *args, &block)
758
+ if RUBY_VERSION >= '2.7'
759
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
760
+ def #{method}(...)
761
+ @touched = true
762
+ current_scope.#{method}(...)
763
+ end
764
+ METHOD
765
+ else
766
+ define_method method do |*args, &block|
767
+ @touched = true
768
+ current_scope.send(method, *args, &block)
769
+ end
752
770
  end
753
771
  end
754
772
 
755
773
  DOCUMENT_METHODS.each do |method|
756
- define_method method do |*args, &block|
757
- document.send(method, *args, &block)
774
+ if RUBY_VERSION >= '2.7'
775
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
776
+ def #{method}(...)
777
+ document.#{method}(...)
778
+ end
779
+ METHOD
780
+ else
781
+ define_method method do |*args, &block|
782
+ document.send(method, *args, &block)
783
+ end
758
784
  end
759
785
  end
760
786
 
@@ -771,7 +797,7 @@ module Capybara
771
797
  #
772
798
  # Yield a block using a specific maximum wait time.
773
799
  #
774
- def using_wait_time(seconds)
800
+ def using_wait_time(seconds, &block)
775
801
  if Capybara.threadsafe
776
802
  begin
777
803
  previous_wait_time = config.default_max_wait_time
@@ -781,7 +807,7 @@ module Capybara
781
807
  config.default_max_wait_time = previous_wait_time
782
808
  end
783
809
  else
784
- Capybara.using_wait_time(seconds) { yield }
810
+ Capybara.using_wait_time(seconds, &block)
785
811
  end
786
812
  end
787
813
 
@@ -873,16 +899,14 @@ module Capybara
873
899
  uri.port ||= @server.port if @server && config.always_include_port
874
900
  end
875
901
 
876
- def _find_frame(*args)
877
- return find(:frame) if args.length.zero?
878
-
902
+ def _find_frame(*args, **kw_args)
879
903
  case args[0]
880
904
  when Capybara::Node::Element
881
905
  args[0]
882
- when String, Hash
883
- find(:frame, *args)
906
+ when String, nil
907
+ find(:frame, *args, **kw_args)
884
908
  when Symbol
885
- find(*args)
909
+ find(*args, **kw_args)
886
910
  when Integer
887
911
  idx = args[0]
888
912
  all(:frame, minimum: idx + 1)[idx]
@@ -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 w3c_click_offset].freeze
11
+ predicates_wait default_normalize_ws w3c_click_offset enable_aria_role].freeze
12
12
 
13
13
  attr_accessor(*OPTIONS)
14
14
 
@@ -37,6 +37,8 @@ module Capybara
37
37
  # See {Capybara.configure}
38
38
  # @!method enable_aria_label
39
39
  # See {Capybara.configure}
40
+ # @!method enable_aria_role
41
+ # See {Capybara.configure}
40
42
  # @!method save_path
41
43
  # See {Capybara.configure}
42
44
  # @!method asset_host
@@ -13,14 +13,14 @@ module Capybara
13
13
  # @param string [String] The string that the current 'path' should equal
14
14
  # @overload $0(regexp, **options)
15
15
  # @param regexp [Regexp] The regexp that the current 'path' should match to
16
- # @option options [Boolean] :url (true if `string` ia a full url, otherwise false) Whether the compare should be done against the full current url or just the path
16
+ # @option options [Boolean] :url (true if `string` is a full url, otherwise false) Whether the comparison should be done against the full current url or just the path
17
17
  # @option options [Boolean] :ignore_query (false) Whether the query portion of the current url/path should be ignored
18
18
  # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for the current url/path to eq/match given string/regexp argument
19
19
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
20
20
  # @return [true]
21
21
  #
22
- def assert_current_path(path, **options)
23
- _verify_current_path(path, **options) do |query|
22
+ def assert_current_path(path, **options, &optional_filter_block)
23
+ _verify_current_path(path, optional_filter_block, **options) do |query|
24
24
  raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
25
25
  end
26
26
  end
@@ -35,8 +35,8 @@ module Capybara
35
35
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
36
36
  # @return [true]
37
37
  #
38
- def assert_no_current_path(path, **options)
39
- _verify_current_path(path, **options) do |query|
38
+ def assert_no_current_path(path, **options, &optional_filter_block)
39
+ _verify_current_path(path, optional_filter_block, **options) do |query|
40
40
  raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self)
41
41
  end
42
42
  end
@@ -50,8 +50,8 @@ module Capybara
50
50
  # @macro current_path_query_params
51
51
  # @return [Boolean]
52
52
  #
53
- def has_current_path?(path, **options)
54
- make_predicate(options) { assert_current_path(path, **options) }
53
+ def has_current_path?(path, **options, &optional_filter_block)
54
+ make_predicate(options) { assert_current_path(path, **options, &optional_filter_block) }
55
55
  end
56
56
 
57
57
  ##
@@ -63,14 +63,14 @@ module Capybara
63
63
  # @macro current_path_query_params
64
64
  # @return [Boolean]
65
65
  #
66
- def has_no_current_path?(path, **options)
67
- make_predicate(options) { assert_no_current_path(path, **options) }
66
+ def has_no_current_path?(path, **options, &optional_filter_block)
67
+ make_predicate(options) { assert_no_current_path(path, **options, &optional_filter_block) }
68
68
  end
69
69
 
70
70
  private
71
71
 
72
- def _verify_current_path(path, **options)
73
- query = Capybara::Queries::CurrentPathQuery.new(path, **options)
72
+ def _verify_current_path(path, filter_block, **options)
73
+ query = Capybara::Queries::CurrentPathQuery.new(path, **options, &filter_block)
74
74
  document.synchronize(query.wait) do
75
75
  yield(query)
76
76
  end
@@ -1,15 +1,40 @@
1
1
  var activeRequests = 0;
2
2
  $(function() {
3
3
  $('#change').text('I changed it');
4
- $('#drag, #drag_scroll, #drag_link').draggable();
4
+ $('#drag, #drag_scroll, #drag_link').draggable({
5
+ start: function(event, ui){
6
+ $(document.body).append(
7
+ "<div class='drag_start'>Dragged!" +
8
+ (event.altKey ? "-alt" : "") +
9
+ (event.ctrlKey ? "-ctrl" : "") +
10
+ (event.metaKey ? "-meta" : "") +
11
+ (event.shiftKey ? "-shift" : "") +
12
+ "</div>"
13
+ );
14
+ }
15
+ });
5
16
  $('#drop, #drop_scroll').droppable({
6
17
  tolerance: 'touch',
7
18
  drop: function(event, ui) {
8
19
  ui.draggable.remove();
9
- $(this).html('Dropped!');
20
+ $(this).html(
21
+ "Dropped!" +
22
+ (event.altKey ? "-alt" : "") +
23
+ (event.ctrlKey ? "-ctrl" : "") +
24
+ (event.metaKey ? "-meta" : "") +
25
+ (event.shiftKey ? "-shift" : "")
26
+ );
10
27
  }
11
28
  });
12
29
  $('#drag_html5, #drag_html5_scroll').on('dragstart', function(ev){
30
+ $(document.body).append(
31
+ "<div class='drag_start'>HTML5 Dragged!" +
32
+ (event.altKey ? "-alt" : "") +
33
+ (event.ctrlKey ? "-ctrl" : "") +
34
+ (event.metaKey ? "-meta" : "") +
35
+ (event.shiftKey ? "-shift" : "") +
36
+ "</div>"
37
+ );
13
38
  ev.originalEvent.dataTransfer.setData("text", ev.target.id);
14
39
  });
15
40
  $('#drag_html5, #drag_html5_scroll').on('dragend', function(ev){
@@ -38,10 +63,19 @@ $(function() {
38
63
  $(this).append('HTML5 Dropped file: ' + file.name);
39
64
  } else {
40
65
  var _this = this;
41
- var callback = (function(type){
42
- return function(s){
43
- $(_this).append('HTML5 Dropped string: ' + type + ' ' + s)
44
- }
66
+ var callback = (function(type) {
67
+ return function(s) {
68
+ $(_this).append(
69
+ "HTML5 Dropped string: " +
70
+ type +
71
+ " " +
72
+ s +
73
+ (ev.altKey ? "-alt" : "") +
74
+ (ev.ctrlKey ? "-ctrl" : "") +
75
+ (ev.metaKey ? "-meta" : "") +
76
+ (ev.shiftKey ? "-shift" : "")
77
+ );
78
+ };
45
79
  })(item.type);
46
80
  item.getAsString(callback);
47
81
  }
@@ -74,6 +108,13 @@ $(function() {
74
108
  }, 4000);
75
109
  return false;
76
110
  });
111
+ $('#aria-button').click(function() {
112
+ var span = $(this);
113
+ setTimeout(function() {
114
+ $(span).after('<span role="button">ARIA button has been clicked</span>')
115
+ }, 1000);
116
+ return false;
117
+ });
77
118
  $('#waiter').change(function() {
78
119
  activeRequests = 1;
79
120
  setTimeout(function() {
@@ -119,6 +160,7 @@ $(function() {
119
160
  });
120
161
  $('#click-test').on({
121
162
  click: function(e) {
163
+ window.click_delay = ((new Date().getTime()) - window.mouse_down_time)/1000.0;
122
164
  var desc = "";
123
165
  if (e.altKey) desc += 'alt ';
124
166
  if (e.ctrlKey) desc += 'control ';
@@ -145,6 +187,16 @@ $(function() {
145
187
  if (e.shiftKey) desc += 'shift ';
146
188
  var pos = this.getBoundingClientRect();
147
189
  $(this).after('<a id="has-been-right-clicked" href="#">Has been ' + desc + 'right clicked at ' + (e.clientX - pos.left) + ',' + (e.clientY - pos.top) + '</a>');
190
+ },
191
+ mousedown: function(e) {
192
+ window.click_delay = undefined;
193
+ window.right_click_delay = undefined;
194
+ window.mouse_down_time = new Date().getTime();
195
+ },
196
+ mouseup: function(e) {
197
+ if (e.button == 2){
198
+ window.right_click_delay = ((new Date().getTime()) - window.mouse_down_time)/1000.0;
199
+ }
148
200
  }
149
201
  });
150
202
  $('#open-alert').click(function() {
@@ -219,5 +271,10 @@ $(function() {
219
271
  });
220
272
  $('#multiple-file, #hidden_file').change(function(e){
221
273
  $('body').append($('<p class="file_change">File input changed</p>'));
222
- })
274
+ });
275
+
276
+ var shadow = document.querySelector('#shadow').attachShadow({mode: 'open'});
277
+ var span = document.createElement('span');
278
+ span.textContent = 'The things we do in the shadows';
279
+ shadow.appendChild(span);
223
280
  });