capybara 3.35.3 → 3.38.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +90 -4
  3. data/README.md +28 -12
  4. data/lib/capybara/config.rb +16 -4
  5. data/lib/capybara/driver/base.rb +4 -0
  6. data/lib/capybara/driver/node.rb +5 -1
  7. data/lib/capybara/dsl.rb +4 -10
  8. data/lib/capybara/helpers.rb +8 -13
  9. data/lib/capybara/minitest/spec.rb +2 -2
  10. data/lib/capybara/node/actions.rb +10 -5
  11. data/lib/capybara/node/base.rb +2 -1
  12. data/lib/capybara/node/document.rb +2 -2
  13. data/lib/capybara/node/element.rb +13 -2
  14. data/lib/capybara/node/finders.rb +9 -2
  15. data/lib/capybara/node/simple.rb +5 -1
  16. data/lib/capybara/queries/active_element_query.rb +18 -0
  17. data/lib/capybara/queries/ancestor_query.rb +2 -1
  18. data/lib/capybara/queries/base_query.rb +2 -2
  19. data/lib/capybara/queries/current_path_query.rb +1 -1
  20. data/lib/capybara/queries/selector_query.rb +38 -10
  21. data/lib/capybara/queries/sibling_query.rb +2 -1
  22. data/lib/capybara/queries/text_query.rb +1 -1
  23. data/lib/capybara/rack_test/browser.rb +63 -8
  24. data/lib/capybara/rack_test/driver.rb +4 -4
  25. data/lib/capybara/rack_test/form.rb +29 -7
  26. data/lib/capybara/rack_test/node.rb +10 -7
  27. data/lib/capybara/registration_container.rb +0 -3
  28. data/lib/capybara/registrations/drivers.rb +3 -3
  29. data/lib/capybara/registrations/servers.rb +17 -9
  30. data/lib/capybara/rspec/matcher_proxies.rb +3 -3
  31. data/lib/capybara/rspec/matchers/have_selector.rb +5 -5
  32. data/lib/capybara/rspec/matchers.rb +14 -14
  33. data/lib/capybara/selector/builders/css_builder.rb +1 -1
  34. data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
  35. data/lib/capybara/selector/css.rb +1 -1
  36. data/lib/capybara/selector/definition/button.rb +9 -4
  37. data/lib/capybara/selector/definition/checkbox.rb +1 -1
  38. data/lib/capybara/selector/definition/file_field.rb +1 -1
  39. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  40. data/lib/capybara/selector/definition/radio_button.rb +1 -1
  41. data/lib/capybara/selector/definition.rb +4 -2
  42. data/lib/capybara/selector/filter_set.rb +4 -7
  43. data/lib/capybara/selector/regexp_disassembler.rb +2 -5
  44. data/lib/capybara/selector/selector.rb +5 -1
  45. data/lib/capybara/selector.rb +1 -0
  46. data/lib/capybara/selenium/driver.rb +28 -11
  47. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
  48. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +1 -1
  49. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +1 -1
  50. data/lib/capybara/selenium/extensions/html5_drag.rb +2 -4
  51. data/lib/capybara/selenium/logger_suppressor.rb +4 -0
  52. data/lib/capybara/selenium/node.rb +74 -23
  53. data/lib/capybara/selenium/nodes/chrome_node.rb +1 -1
  54. data/lib/capybara/selenium/nodes/edge_node.rb +1 -1
  55. data/lib/capybara/selenium/nodes/firefox_node.rb +3 -3
  56. data/lib/capybara/selenium/nodes/safari_node.rb +4 -4
  57. data/lib/capybara/server/animation_disabler.rb +41 -23
  58. data/lib/capybara/server/middleware.rb +1 -1
  59. data/lib/capybara/session/config.rb +4 -2
  60. data/lib/capybara/session.rb +31 -32
  61. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  62. data/lib/capybara/spec/session/all_spec.rb +9 -13
  63. data/lib/capybara/spec/session/assert_text_spec.rb +17 -17
  64. data/lib/capybara/spec/session/attach_file_spec.rb +6 -0
  65. data/lib/capybara/spec/session/check_spec.rb +10 -0
  66. data/lib/capybara/spec/session/choose_spec.rb +6 -0
  67. data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
  68. data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
  69. data/lib/capybara/spec/session/find_spec.rb +6 -0
  70. data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -2
  71. data/lib/capybara/spec/session/has_any_selectors_spec.rb +4 -0
  72. data/lib/capybara/spec/session/has_button_spec.rb +30 -0
  73. data/lib/capybara/spec/session/has_current_path_spec.rb +2 -2
  74. data/lib/capybara/spec/session/has_field_spec.rb +25 -1
  75. data/lib/capybara/spec/session/has_link_spec.rb +36 -0
  76. data/lib/capybara/spec/session/has_select_spec.rb +10 -4
  77. data/lib/capybara/spec/session/has_selector_spec.rb +15 -0
  78. data/lib/capybara/spec/session/has_text_spec.rb +6 -14
  79. data/lib/capybara/spec/session/node_spec.rb +66 -1
  80. data/lib/capybara/spec/session/reset_session_spec.rb +13 -0
  81. data/lib/capybara/spec/session/scroll_spec.rb +4 -4
  82. data/lib/capybara/spec/session/visit_spec.rb +20 -0
  83. data/lib/capybara/spec/session/window/window_spec.rb +1 -1
  84. data/lib/capybara/spec/session/within_spec.rb +13 -0
  85. data/lib/capybara/spec/spec_helper.rb +12 -5
  86. data/lib/capybara/spec/test_app.rb +91 -14
  87. data/lib/capybara/spec/views/animated.erb +1 -1
  88. data/lib/capybara/spec/views/form.erb +24 -3
  89. data/lib/capybara/spec/views/frame_child.erb +1 -1
  90. data/lib/capybara/spec/views/frame_one.erb +1 -1
  91. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  92. data/lib/capybara/spec/views/frame_two.erb +1 -1
  93. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  94. data/lib/capybara/spec/views/layout.erb +10 -0
  95. data/lib/capybara/spec/views/obscured.erb +1 -1
  96. data/lib/capybara/spec/views/offset.erb +2 -1
  97. data/lib/capybara/spec/views/path.erb +2 -2
  98. data/lib/capybara/spec/views/popup_one.erb +1 -1
  99. data/lib/capybara/spec/views/popup_two.erb +1 -1
  100. data/lib/capybara/spec/views/react.erb +2 -2
  101. data/lib/capybara/spec/views/scroll.erb +2 -1
  102. data/lib/capybara/spec/views/spatial.erb +1 -1
  103. data/lib/capybara/spec/views/with_animation.erb +2 -3
  104. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  105. data/lib/capybara/spec/views/with_dragula.erb +2 -2
  106. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  107. data/lib/capybara/spec/views/with_hover.erb +2 -2
  108. data/lib/capybara/spec/views/with_html.erb +3 -3
  109. data/lib/capybara/spec/views/with_jquery_animation.erb +1 -1
  110. data/lib/capybara/spec/views/with_js.erb +2 -3
  111. data/lib/capybara/spec/views/with_jstree.erb +1 -1
  112. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  113. data/lib/capybara/spec/views/with_scope.erb +2 -2
  114. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  115. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  116. data/lib/capybara/spec/views/with_sortable_js.erb +2 -2
  117. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  118. data/lib/capybara/spec/views/with_windows.erb +1 -1
  119. data/lib/capybara/spec/views/within_frames.erb +1 -1
  120. data/lib/capybara/version.rb +1 -1
  121. data/lib/capybara/window.rb +1 -1
  122. data/lib/capybara.rb +23 -24
  123. data/spec/basic_node_spec.rb +16 -3
  124. data/spec/capybara_spec.rb +12 -0
  125. data/spec/counter_spec.rb +35 -0
  126. data/spec/dsl_spec.rb +5 -3
  127. data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -2
  128. data/spec/fixtures/selenium_driver_rspec_success.rb +2 -2
  129. data/spec/minitest_spec.rb +4 -0
  130. data/spec/minitest_spec_spec.rb +4 -0
  131. data/spec/per_session_config_spec.rb +1 -1
  132. data/spec/rack_test_spec.rb +28 -10
  133. data/spec/result_spec.rb +32 -35
  134. data/spec/rspec/features_spec.rb +3 -3
  135. data/spec/rspec/scenarios_spec.rb +1 -1
  136. data/spec/rspec/shared_spec_matchers.rb +3 -3
  137. data/spec/rspec_spec.rb +2 -2
  138. data/spec/sauce_spec_chrome.rb +3 -3
  139. data/spec/selector_spec.rb +4 -4
  140. data/spec/selenium_spec_chrome.rb +11 -10
  141. data/spec/selenium_spec_chrome_remote.rb +11 -8
  142. data/spec/selenium_spec_edge.rb +2 -0
  143. data/spec/selenium_spec_firefox.rb +15 -4
  144. data/spec/selenium_spec_firefox_remote.rb +4 -2
  145. data/spec/selenium_spec_ie.rb +6 -7
  146. data/spec/selenium_spec_safari.rb +33 -19
  147. data/spec/server_spec.rb +5 -5
  148. data/spec/shared_selenium_node.rb +0 -4
  149. data/spec/shared_selenium_session.rb +23 -14
  150. data/spec/spec_helper.rb +1 -1
  151. metadata +38 -14
  152. data/lib/capybara/spec/views/with_title.erb +0 -5
@@ -14,7 +14,7 @@ module Capybara
14
14
  end
15
15
 
16
16
  def decrement(uri)
17
- @mutex.synchronize { @value.delete_at(@value.index(uri) || @value.length) }
17
+ @mutex.synchronize { @value.delete_at(@value.index(uri) || - 1) }
18
18
  end
19
19
 
20
20
  def positive?
@@ -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 enable_aria_role].freeze
11
+ predicates_wait default_normalize_ws w3c_click_offset enable_aria_role default_retry_interval].freeze
12
12
 
13
13
  attr_accessor(*OPTIONS)
14
14
 
@@ -21,6 +21,8 @@ module Capybara
21
21
  # See {Capybara.configure}
22
22
  # @!method default_max_wait_time
23
23
  # See {Capybara.configure}
24
+ # @!method default_retry_interval
25
+ # See {Capybara.configure}
24
26
  # @!method ignore_hidden_elements
25
27
  # See {Capybara.configure}
26
28
  # @!method automatic_reload
@@ -100,7 +102,7 @@ module Capybara
100
102
  remove_method :test_id=
101
103
  ##
102
104
  #
103
- # Set an attribue to be optionally matched against the locator for builtin selector types.
105
+ # Set an attribute to be optionally matched against the locator for builtin selector types.
104
106
  # This attribute will be checked by builtin selector types whenever id would normally be checked.
105
107
  # If `nil` then it will be ignored.
106
108
  #
@@ -40,6 +40,7 @@ module Capybara
40
40
 
41
41
  NODE_METHODS = %i[
42
42
  all first attach_file text check choose scroll_to scroll_by
43
+ click double_click right_click
43
44
  click_link_or_button click_button click_link
44
45
  fill_in find find_all find_button find_by_id find_field find_link
45
46
  has_content? has_text? has_css? has_no_content? has_no_text?
@@ -58,7 +59,7 @@ module Capybara
58
59
  ].freeze
59
60
  SESSION_METHODS = %i[
60
61
  body html source current_url current_host current_path
61
- execute_script evaluate_script visit refresh go_back go_forward send_keys
62
+ execute_script evaluate_script evaluate_async_script visit refresh go_back go_forward send_keys
62
63
  within within_element within_fieldset within_table within_frame switch_to_frame
63
64
  current_window windows open_new_window switch_to_window within_window window_opened_by
64
65
  save_page save_and_open_page save_screenshot
@@ -129,6 +130,8 @@ module Capybara
129
130
  if @touched
130
131
  driver.reset!
131
132
  @touched = false
133
+ switch_to_frame(:top) rescue nil # rubocop:disable Style/RescueModifier
134
+ @scopes = [nil]
132
135
  end
133
136
  @server&.wait_for_pending_requests
134
137
  raise_server_error!
@@ -159,9 +162,8 @@ module Capybara
159
162
  if config.raise_server_errors
160
163
  raise CapybaraError, 'Your application server raised an error - It has been raised in your test code because Capybara.raise_server_errors == true'
161
164
  end
162
- rescue CapybaraError
163
- # needed to get the cause set correctly in JRuby -- otherwise we could just do raise @server.error
164
- raise @server.error, @server.error.message, @server.error.backtrace
165
+ rescue CapybaraError => capy_error # rubocop:disable Naming/RescuedExceptionsVariableName
166
+ raise @server.error, cause: capy_error
165
167
  ensure
166
168
  @server.reset_error!
167
169
  end
@@ -311,6 +313,16 @@ module Capybara
311
313
  driver.send_keys(*args, **kw_args)
312
314
  end
313
315
 
316
+ ##
317
+ #
318
+ # Returns the element with focus.
319
+ #
320
+ # Not supported by Rack Test
321
+ #
322
+ def active_element
323
+ Capybara::Queries::ActiveElementQuery.new.resolve_for(self)[0].tap(&:allow_reload!)
324
+ end
325
+
314
326
  ##
315
327
  #
316
328
  # Executes the given block within the context of a node. {#within} takes the
@@ -350,7 +362,7 @@ module Capybara
350
362
  new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args, **kw_args)
351
363
  begin
352
364
  scopes.push(new_scope)
353
- yield if block_given?
365
+ yield new_scope if block_given?
354
366
  ensure
355
367
  scopes.pop
356
368
  end
@@ -399,7 +411,7 @@ module Capybara
399
411
  scopes.push(:frame)
400
412
  when :parent
401
413
  if scopes.last != :frame
402
- raise Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's "\
414
+ raise Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's " \
403
415
  '`within` block.'
404
416
  end
405
417
  scopes.pop
@@ -408,11 +420,11 @@ module Capybara
408
420
  idx = scopes.index(:frame)
409
421
  top_level_scopes = [:frame, nil]
410
422
  if idx
411
- if scopes.slice(idx..-1).any? { |scope| !top_level_scopes.include?(scope) }
412
- raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's "\
423
+ if scopes.slice(idx..).any? { |scope| !top_level_scopes.include?(scope) }
424
+ raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's " \
413
425
  '`within` block.'
414
426
  end
415
- scopes.slice!(idx..-1)
427
+ scopes.slice!(idx..)
416
428
  driver.switch_to_frame(:top)
417
429
  end
418
430
  else
@@ -501,7 +513,7 @@ module Capybara
501
513
  raise ArgumentError, '`switch_to_window`: either window or block should be provided' if !window && !window_locator
502
514
 
503
515
  unless scopes.last.nil?
504
- raise Capybara::ScopeError, '`switch_to_window` is not supposed to be invoked from '\
516
+ raise Capybara::ScopeError, '`switch_to_window` is not supposed to be invoked from ' \
505
517
  '`within` or `within_frame` blocks.'
506
518
  end
507
519
 
@@ -572,7 +584,7 @@ module Capybara
572
584
  synchronize_windows(options) do
573
585
  opened_handles = (driver.window_handles - old_handles)
574
586
  if opened_handles.size != 1
575
- raise Capybara::WindowError, 'block passed to #window_opened_by '\
587
+ raise Capybara::WindowError, 'block passed to #window_opened_by ' \
576
588
  "opened #{opened_handles.size} windows instead of 1"
577
589
  end
578
590
  Window.new(self, opened_handles.first)
@@ -755,33 +767,20 @@ module Capybara
755
767
  end
756
768
 
757
769
  NODE_METHODS.each do |method|
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|
770
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
771
+ def #{method}(...)
767
772
  @touched = true
768
- current_scope.send(method, *args, &block)
773
+ current_scope.#{method}(...)
769
774
  end
770
- end
775
+ METHOD
771
776
  end
772
777
 
773
778
  DOCUMENT_METHODS.each do |method|
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)
779
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
780
+ def #{method}(...)
781
+ document.#{method}(...)
783
782
  end
784
- end
783
+ METHOD
785
784
  end
786
785
 
787
786
  def inspect
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ Capybara::SpecHelper.spec '#active_element', requires: [:active_element] do
4
+ it 'should return the active element' do
5
+ @session.visit('/form')
6
+ @session.send_keys(:tab)
7
+
8
+ expect(@session.active_element).to match_selector(:css, '[tabindex="1"]')
9
+
10
+ @session.send_keys(:tab)
11
+
12
+ expect(@session.active_element).to match_selector(:css, '[tabindex="2"]')
13
+ end
14
+
15
+ it 'should support reloading' do
16
+ @session.visit('/form')
17
+ expect(@session.active_element).to match_selector(:css, 'body')
18
+ @session.execute_script <<-JS
19
+ window.setTimeout(() => {
20
+ document.querySelector('#form_title').focus();
21
+ }, 1000)
22
+ JS
23
+ expect(@session.active_element).to match_selector(:css, 'body', wait: false)
24
+ expect(@session.active_element).to match_selector(:css, '#form_title', wait: 2)
25
+ end
26
+
27
+ it 'should return a Capybara::Element' do
28
+ @session.visit('/form')
29
+ expect(@session.active_element).to be_a Capybara::Node::Element
30
+ end
31
+ end
@@ -132,7 +132,7 @@ Capybara::SpecHelper.spec '#all' do
132
132
  it 'should use the sessions ignore_hidden_elements', psc: true do
133
133
  Capybara.ignore_hidden_elements = true
134
134
  @session.config.ignore_hidden_elements = false
135
- expect(Capybara.ignore_hidden_elements).to eq(true)
135
+ expect(Capybara.ignore_hidden_elements).to be(true)
136
136
  expect(@session.all(:css, 'a.simple').size).to eq(2)
137
137
  @session.config.ignore_hidden_elements = true
138
138
  expect(@session.all(:css, 'a.simple').size).to eq(1)
@@ -203,19 +203,15 @@ Capybara::SpecHelper.spec '#all' do
203
203
  expect { @session.all(:css, 'h1, p', between: 0..3) }.to raise_error(Capybara::ExpectationNotMet)
204
204
  end
205
205
 
206
- eval <<~TEST, binding, __FILE__, __LINE__ + 1 if RUBY_VERSION.to_f > 2.5
207
- it'treats an endless range as minimum' do
208
- expect { @session.all(:css, 'h1, p', between: 2..) }.not_to raise_error
209
- expect { @session.all(:css, 'h1, p', between: 5..) }.to raise_error(Capybara::ExpectationNotMet)
210
- end
211
- TEST
206
+ it 'treats an endless range as minimum' do
207
+ expect { @session.all(:css, 'h1, p', between: 2..) }.not_to raise_error
208
+ expect { @session.all(:css, 'h1, p', between: 5..) }.to raise_error(Capybara::ExpectationNotMet)
209
+ end
212
210
 
213
- eval <<~TEST, binding, __FILE__, __LINE__ + 1 if RUBY_VERSION.to_f > 2.6
214
- it'treats a beginless range as maximum' do
215
- expect { @session.all(:css, 'h1, p', between: ..7) }.not_to raise_error
216
- expect { @session.all(:css, 'h1, p', between: ..3) }.to raise_error(Capybara::ExpectationNotMet)
217
- end
218
- TEST
211
+ it 'treats a beginless range as maximum' do
212
+ expect { @session.all(:css, 'h1, p', between: ..7) }.not_to raise_error
213
+ expect { @session.all(:css, 'h1, p', between: ..3) }.to raise_error(Capybara::ExpectationNotMet)
214
+ end
219
215
  end
220
216
 
221
217
  context 'with multiple count filters' do
@@ -3,16 +3,16 @@
3
3
  Capybara::SpecHelper.spec '#assert_text' do
4
4
  it 'should be true if the given text is on the page' do
5
5
  @session.visit('/with_html')
6
- expect(@session.assert_text('est')).to eq(true)
7
- expect(@session.assert_text('Lorem')).to eq(true)
8
- expect(@session.assert_text('Redirect')).to eq(true)
9
- expect(@session.assert_text(:Redirect)).to eq(true)
10
- expect(@session.assert_text('text with whitespace')).to eq(true)
6
+ expect(@session.assert_text('est')).to be(true)
7
+ expect(@session.assert_text('Lorem')).to be(true)
8
+ expect(@session.assert_text('Redirect')).to be(true)
9
+ expect(@session.assert_text(:Redirect)).to be(true)
10
+ expect(@session.assert_text('text with whitespace')).to be(true)
11
11
  end
12
12
 
13
13
  it 'should support collapsing whitespace' do
14
14
  @session.visit('/with_html')
15
- expect(@session.assert_text('text with whitespace', normalize_ws: true)).to eq(true)
15
+ expect(@session.assert_text('text with whitespace', normalize_ws: true)).to be(true)
16
16
  end
17
17
 
18
18
  context 'with enabled default collapsing whitespace' do
@@ -20,19 +20,19 @@ Capybara::SpecHelper.spec '#assert_text' do
20
20
 
21
21
  it 'should be true if the given unnormalized text is on the page' do
22
22
  @session.visit('/with_html')
23
- expect(@session.assert_text('text with whitespace', normalize_ws: false)).to eq(true)
23
+ expect(@session.assert_text('text with whitespace', normalize_ws: false)).to be(true)
24
24
  end
25
25
 
26
26
  it 'should support collapsing whitespace' do
27
27
  @session.visit('/with_html')
28
- expect(@session.assert_text('text with whitespace')).to eq(true)
28
+ expect(@session.assert_text('text with whitespace')).to be(true)
29
29
  end
30
30
  end
31
31
 
32
32
  it 'should take scopes into account' do
33
33
  @session.visit('/with_html')
34
34
  @session.within("//a[@title='awesome title']") do
35
- expect(@session.assert_text('labore')).to eq(true)
35
+ expect(@session.assert_text('labore')).to be(true)
36
36
  end
37
37
  end
38
38
 
@@ -47,13 +47,13 @@ Capybara::SpecHelper.spec '#assert_text' do
47
47
 
48
48
  it 'should be true if :all given and text is invisible.' do
49
49
  @session.visit('/with_html')
50
- expect(@session.assert_text(:all, 'Some of this text is hidden!')).to eq(true)
50
+ expect(@session.assert_text(:all, 'Some of this text is hidden!')).to be(true)
51
51
  end
52
52
 
53
53
  it 'should be true if `Capybara.ignore_hidden_elements = true` and text is invisible.' do
54
54
  Capybara.ignore_hidden_elements = false
55
55
  @session.visit('/with_html')
56
- expect(@session.assert_text('Some of this text is hidden!')).to eq(true)
56
+ expect(@session.assert_text('Some of this text is hidden!')).to be(true)
57
57
  end
58
58
 
59
59
  it 'should raise error with a helpful message if the requested text is present but invisible' do
@@ -88,7 +88,7 @@ Capybara::SpecHelper.spec '#assert_text' do
88
88
 
89
89
  it 'should be true if the text in the page matches given regexp' do
90
90
  @session.visit('/with_html')
91
- expect(@session.assert_text(/Lorem/)).to eq(true)
91
+ expect(@session.assert_text(/Lorem/)).to be(true)
92
92
  end
93
93
 
94
94
  it "should raise error if the text in the page doesn't match given regexp" do
@@ -109,13 +109,13 @@ Capybara::SpecHelper.spec '#assert_text' do
109
109
  Capybara.default_max_wait_time = 2
110
110
  @session.visit('/with_js')
111
111
  @session.click_link('Click me')
112
- expect(@session.assert_text('Has been clicked')).to eq(true)
112
+ expect(@session.assert_text('Has been clicked')).to be(true)
113
113
  end
114
114
 
115
115
  context 'with between' do
116
116
  it 'should be true if the text occurs within the range given' do
117
117
  @session.visit('/with_count')
118
- expect(@session.assert_text('count', between: 1..3)).to eq(true)
118
+ expect(@session.assert_text('count', between: 1..3)).to be(true)
119
119
  end
120
120
 
121
121
  it 'should be false if the text occurs more or fewer times than range' do
@@ -203,13 +203,13 @@ Capybara::SpecHelper.spec '#assert_no_text' do
203
203
  it 'should be true if scoped to an element which does not have the text' do
204
204
  @session.visit('/with_html')
205
205
  @session.within("//a[@title='awesome title']") do
206
- expect(@session.assert_no_text('monkey')).to eq(true)
206
+ expect(@session.assert_no_text('monkey')).to be(true)
207
207
  end
208
208
  end
209
209
 
210
210
  it 'should be true if the given text is on the page but not visible' do
211
211
  @session.visit('/with_html')
212
- expect(@session.assert_no_text('Inside element with hidden ancestor')).to eq(true)
212
+ expect(@session.assert_no_text('Inside element with hidden ancestor')).to be(true)
213
213
  end
214
214
 
215
215
  it 'should raise error if :all given and text is invisible.' do
@@ -236,7 +236,7 @@ Capybara::SpecHelper.spec '#assert_no_text' do
236
236
  context 'with count' do
237
237
  it 'should be true if the text occurs within the range given' do
238
238
  @session.visit('/with_count')
239
- expect(@session.assert_text('count', count: 2)).to eq(true)
239
+ expect(@session.assert_text('count', count: 2)).to be(true)
240
240
  end
241
241
 
242
242
  it 'should be false if the text occurs more or fewer times than range' do
@@ -55,6 +55,12 @@ Capybara::SpecHelper.spec '#attach_file' do
55
55
  expect(@session).to have_content('No file uploaded')
56
56
  end
57
57
 
58
+ it 'should send prior hidden field if no file submitted' do
59
+ @session.click_button('Upload Empty With Hidden')
60
+ expect(extract_results(@session)['document2']).to eq('hidden_field')
61
+ expect(extract_content_type(@session)).to start_with('multipart/form-data;')
62
+ end
63
+
58
64
  it 'should send content type text/plain when uploading a text file' do
59
65
  @session.attach_file 'Single Document', with_os_path_separators(test_file_path)
60
66
  @session.click_button 'Upload Single'
@@ -236,6 +236,16 @@ Capybara::SpecHelper.spec '#check' do
236
236
  expect(@session).to have_field('multi_label_checkbox', checked: true, visible: :hidden)
237
237
  end
238
238
  end
239
+
240
+ context 'with allow_label_click options', requires: [:js] do
241
+ it 'should allow offsets to click location on label' do
242
+ Capybara.w3c_click_offset = false
243
+ expect(@session.find(:checkbox, 'form_cars_lotus', unchecked: true, visible: :hidden)).to be_truthy
244
+ @session.check('form_cars_lotus', allow_label_click: { x: 90, y: 10 })
245
+ @session.click_button('awesome')
246
+ expect(extract_results(@session)['cars']).to include('lotus')
247
+ end
248
+ end
239
249
  end
240
250
  end
241
251
  end
@@ -11,6 +11,12 @@ Capybara::SpecHelper.spec '#choose' do
11
11
  expect(extract_results(@session)['gender']).to eq('male')
12
12
  end
13
13
 
14
+ it 'ignores readonly attribute on radio buttons' do
15
+ @session.choose('gender_both')
16
+ @session.click_button('awesome')
17
+ expect(extract_results(@session)['gender']).to eq('both')
18
+ end
19
+
14
20
  it 'should choose a radio button by label' do
15
21
  @session.choose('Both')
16
22
  @session.click_button('awesome')
@@ -7,7 +7,7 @@ Capybara::SpecHelper.spec '#current_scope' do
7
7
 
8
8
  context 'when not in a #within block' do
9
9
  it 'should return the document' do
10
- expect(@session.current_scope).to be_kind_of Capybara::Node::Document
10
+ expect(@session.current_scope).to be_a Capybara::Node::Document
11
11
  end
12
12
  end
13
13
 
@@ -98,6 +98,12 @@ Capybara::SpecHelper.spec '#fill_in' do
98
98
  expect(extract_results(@session)['description']).to eq("\r\nSome text\r\n")
99
99
  end
100
100
 
101
+ it 'should handle carriage returns with line feeds in a textarea correctly' do
102
+ @session.fill_in('form_description', with: "\r\nSome text\r\n")
103
+ @session.click_button('awesome')
104
+ expect(extract_results(@session)['description']).to eq("\r\nSome text\r\n")
105
+ end
106
+
101
107
  it 'should fill in a color field' do
102
108
  @session.fill_in('Html5 Color', with: '#112233')
103
109
  @session.click_button('html5_submit')
@@ -528,4 +528,10 @@ Capybara::SpecHelper.spec '#find' do
528
528
  expect(@session.find(:link, 'test-foo')[:id]).to eq 'foo'
529
529
  end
530
530
  end
531
+
532
+ it 'should warn if passed count options' do
533
+ allow(Capybara::Helpers).to receive(:warn)
534
+ @session.find('//h1', count: 44)
535
+ expect(Capybara::Helpers).to have_received(:warn).with(/'find' does not support count options/)
536
+ end
531
537
  end
@@ -39,8 +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
+ expect(el).to have_no_ancestor(:css, '#ancestor1_sibling')
43
43
  expect(el).not_to have_ancestor(:css, '#child')
44
- expect(el).not_to have_ancestor(:css, '#ancestor1_sibiling')
44
+ expect(el).not_to have_ancestor(:css, '#ancestor1_sibling')
45
45
  end
46
46
  end
@@ -22,4 +22,8 @@ Capybara::SpecHelper.spec '#have_any_of_selectors' do
22
22
  expect(@session).to have_any_of_selectors('p a#blah', 'h2#h2three')
23
23
  end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
24
24
  end
25
+
26
+ it 'should be negateable' do
27
+ expect(@session).not_to have_any_of_selectors(:css, 'span a#foo', 'h2#h2nope', 'h2#h2one_no')
28
+ end
25
29
  end
@@ -65,6 +65,24 @@ Capybara::SpecHelper.spec '#has_button?' do
65
65
  it 'should not affect other selectors when enable_aria_role: false' do
66
66
  expect(@session).to have_button('Click me!', enable_aria_role: false)
67
67
  end
68
+
69
+ context 'with focused:', requires: [:active_element] do
70
+ it 'should be true if a field has focus when focused: true' do
71
+ @session.send_keys(:tab)
72
+
73
+ expect(@session).to have_button('A Button', focused: true)
74
+ end
75
+
76
+ it 'should be true if a field does not have focus when focused: false' do
77
+ expect(@session).to have_button('A Button', focused: false)
78
+ end
79
+ end
80
+
81
+ it 'should raise an error if an invalid option is passed' do
82
+ expect do
83
+ expect(@session).to have_button('A Button', invalid: true)
84
+ end.to raise_error(ArgumentError, 'Invalid option(s) :invalid, should be one of :above, :below, :left_of, :right_of, :near, :count, :minimum, :maximum, :between, :text, :id, :class, :style, :visible, :obscured, :exact, :exact_text, :normalize_ws, :match, :wait, :filter_set, :focused, :disabled, :name, :value, :title, :type')
85
+ end
68
86
  end
69
87
 
70
88
  Capybara::SpecHelper.spec '#has_no_button?' do
@@ -117,4 +135,16 @@ Capybara::SpecHelper.spec '#has_no_button?' do
117
135
  it 'should not affect other selectors when enable_aria_role: false' do
118
136
  expect(@session).to have_no_button('Junk button that does not exist', enable_aria_role: false)
119
137
  end
138
+
139
+ context 'with focused:', requires: [:active_element] do
140
+ it 'should be true if a button does not have focus when focused: true' do
141
+ expect(@session).to have_no_button('A Button', focused: true)
142
+ end
143
+
144
+ it 'should be false if a button has focus when focused: false' do
145
+ @session.send_keys(:tab)
146
+
147
+ expect(@session).to have_no_button('A Button', focused: false)
148
+ end
149
+ end
120
150
  end
@@ -16,8 +16,8 @@ Capybara::SpecHelper.spec '#has_current_path?' do
16
16
 
17
17
  it 'should not raise an error when non-http' do
18
18
  @session.reset_session!
19
- expect(@session.has_current_path?(/monkey/)).to eq false
20
- expect(@session.has_current_path?('/with_js')).to eq false
19
+ expect(@session.has_current_path?(/monkey/)).to be false
20
+ expect(@session.has_current_path?('/with_js')).to be false
21
21
  end
22
22
 
23
23
  it 'should handle non-escaped query options' do
@@ -110,6 +110,18 @@ Capybara::SpecHelper.spec '#has_field' do
110
110
  end
111
111
  end
112
112
 
113
+ context 'with focused:', requires: [:active_element] do
114
+ it 'should be true if a field has focus' do
115
+ 2.times { @session.send_keys(:tab) }
116
+
117
+ expect(@session).to have_field('An Input', focused: true)
118
+ end
119
+
120
+ it 'should be false if a field does not have focus' do
121
+ expect(@session).to have_field('An Input', focused: false)
122
+ end
123
+ end
124
+
113
125
  context 'with valid', requires: [:js] do
114
126
  it 'should be true if field is valid' do
115
127
  @session.fill_in 'required', with: 'something'
@@ -184,6 +196,18 @@ Capybara::SpecHelper.spec '#has_no_field' do
184
196
  expect(@session).to have_no_field('Languages', type: 'textarea')
185
197
  end
186
198
  end
199
+
200
+ context 'with focused:', requires: [:active_element] do
201
+ it 'should be true if a field does not have focus when focused: true' do
202
+ expect(@session).to have_no_field('An Input', focused: true)
203
+ end
204
+
205
+ it 'should be false if a field has focus when focused: true' do
206
+ 2.times { @session.send_keys(:tab) }
207
+
208
+ expect(@session).not_to have_no_field('An Input', focused: true)
209
+ end
210
+ end
187
211
  end
188
212
 
189
213
  Capybara::SpecHelper.spec '#has_checked_field?' do
@@ -359,7 +383,7 @@ Capybara::SpecHelper.spec '#has_no_unchecked_field?' do
359
383
  end
360
384
 
361
385
  it 'should support locator-less usage' do
362
- expect(@session.has_no_unchecked_field?(disabled: false, id: 'form_disabled_unchecked_checkbox')).to eq true
386
+ expect(@session.has_no_unchecked_field?(disabled: false, id: 'form_disabled_unchecked_checkbox')).to be true
363
387
  expect(@session).to have_no_unchecked_field(disabled: false, id: 'form_disabled_unchecked_checkbox')
364
388
  end
365
389
  end
@@ -18,6 +18,30 @@ Capybara::SpecHelper.spec '#has_link?' do
18
18
  expect(@session).not_to have_link('A link', href: '/nonexistent-href')
19
19
  expect(@session).not_to have_link('A link', href: /nonexistent/)
20
20
  end
21
+
22
+ it 'should notify if an invalid locator is specified' do
23
+ allow(Capybara::Helpers).to receive(:warn).and_return(nil)
24
+ @session.has_link?(@session)
25
+ expect(Capybara::Helpers).to have_received(:warn).with(/Called from: .+/)
26
+ end
27
+
28
+ context 'with focused:', requires: [:active_element] do
29
+ it 'should be true if the given link is on the page and has focus' do
30
+ @session.send_keys(:tab)
31
+
32
+ expect(@session).to have_link('labore', focused: true)
33
+ end
34
+
35
+ it 'should be false if the given link is on the page and does not have focus' do
36
+ expect(@session).to have_link('labore', focused: false)
37
+ end
38
+ end
39
+
40
+ it 'should raise an error if an invalid option is passed' do
41
+ expect do
42
+ expect(@session).to have_link('labore', invalid: true)
43
+ end.to raise_error(ArgumentError, 'Invalid option(s) :invalid, should be one of :above, :below, :left_of, :right_of, :near, :count, :minimum, :maximum, :between, :text, :id, :class, :style, :visible, :obscured, :exact, :exact_text, :normalize_ws, :match, :wait, :filter_set, :focused, :href, :alt, :title, :download')
44
+ end
21
45
  end
22
46
 
23
47
  Capybara::SpecHelper.spec '#has_no_link?' do
@@ -36,4 +60,16 @@ Capybara::SpecHelper.spec '#has_no_link?' do
36
60
  expect(@session).to have_no_link('A link', href: '/nonexistent-href')
37
61
  expect(@session).to have_no_link('A link', href: %r{/nonexistent-href})
38
62
  end
63
+
64
+ context 'with focused:', requires: [:active_element] do
65
+ it 'should be true if the given link is on the page and has focus' do
66
+ expect(@session).to have_no_link('labore', focused: true)
67
+ end
68
+
69
+ it 'should be false if the given link is on the page and does not have focus' do
70
+ @session.send_keys(:tab)
71
+
72
+ expect(@session).to have_no_link('labore', focused: false)
73
+ end
74
+ end
39
75
  end
@@ -179,10 +179,16 @@ Capybara::SpecHelper.spec '#has_select?' do
179
179
  end
180
180
  end
181
181
 
182
+ it 'should raise an error if an invalid option is passed' do
183
+ expect do
184
+ expect(@session).to have_select('form_languages', invalid: true)
185
+ end.to raise_error(ArgumentError, 'Invalid option(s) :invalid, should be one of :above, :below, :left_of, :right_of, :near, :count, :minimum, :maximum, :between, :text, :id, :class, :style, :visible, :obscured, :exact, :exact_text, :normalize_ws, :match, :wait, :filter_set, :focused, :disabled, :name, :placeholder, :options, :enabled_options, :disabled_options, :selected, :with_selected, :multiple, :with_options')
186
+ end
187
+
182
188
  it 'should support locator-less usage' do
183
- expect(@session.has_select?(with_options: %w[Norway Sweden])).to eq true
189
+ expect(@session.has_select?(with_options: %w[Norway Sweden])).to be true
184
190
  expect(@session).to have_select(with_options: ['London'])
185
- expect(@session.has_select?(with_selected: %w[Commando Boxerbriefs])).to eq true
191
+ expect(@session.has_select?(with_selected: %w[Commando Boxerbriefs])).to be true
186
192
  expect(@session).to have_select(with_selected: ['Briefs'])
187
193
  end
188
194
  end
@@ -302,9 +308,9 @@ Capybara::SpecHelper.spec '#has_no_select?' do
302
308
  end
303
309
 
304
310
  it 'should support locator-less usage' do
305
- expect(@session.has_no_select?(with_options: %w[Norway Sweden Finland Latvia])).to eq true
311
+ expect(@session.has_no_select?(with_options: %w[Norway Sweden Finland Latvia])).to be true
306
312
  expect(@session).to have_no_select(with_options: ['New London'])
307
- expect(@session.has_no_select?(id: 'form_underwear', with_selected: ['Boxers'])).to eq true
313
+ expect(@session.has_no_select?(id: 'form_underwear', with_selected: ['Boxers'])).to be true
308
314
  expect(@session).to have_no_select(id: 'form_underwear', with_selected: %w[Commando Boxers])
309
315
  end
310
316
  end