capybara 3.32.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 (125) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +99 -15
  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/helpers.rb +25 -1
  9. data/lib/capybara/minitest.rb +2 -3
  10. data/lib/capybara/minitest/spec.rb +14 -11
  11. data/lib/capybara/node/actions.rb +16 -21
  12. data/lib/capybara/node/base.rb +6 -6
  13. data/lib/capybara/node/element.rb +1 -5
  14. data/lib/capybara/node/finders.rb +7 -6
  15. data/lib/capybara/node/matchers.rb +12 -12
  16. data/lib/capybara/node/simple.rb +5 -1
  17. data/lib/capybara/queries/ancestor_query.rb +1 -1
  18. data/lib/capybara/queries/current_path_query.rb +14 -4
  19. data/lib/capybara/queries/selector_query.rb +40 -18
  20. data/lib/capybara/queries/sibling_query.rb +1 -1
  21. data/lib/capybara/queries/style_query.rb +1 -1
  22. data/lib/capybara/queries/text_query.rb +7 -1
  23. data/lib/capybara/rack_test/browser.rb +7 -3
  24. data/lib/capybara/rack_test/driver.rb +1 -0
  25. data/lib/capybara/rack_test/form.rb +1 -1
  26. data/lib/capybara/rack_test/node.rb +1 -1
  27. data/lib/capybara/registration_container.rb +44 -0
  28. data/lib/capybara/registrations/drivers.rb +18 -12
  29. data/lib/capybara/registrations/patches/puma_ssl.rb +3 -1
  30. data/lib/capybara/registrations/servers.rb +3 -2
  31. data/lib/capybara/result.rb +10 -11
  32. data/lib/capybara/rspec.rb +2 -0
  33. data/lib/capybara/rspec/matcher_proxies.rb +1 -1
  34. data/lib/capybara/rspec/matchers.rb +7 -6
  35. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  36. data/lib/capybara/rspec/matchers/have_text.rb +1 -1
  37. data/lib/capybara/rspec/matchers/match_style.rb +5 -0
  38. data/lib/capybara/selector.rb +12 -3
  39. data/lib/capybara/selector/builders/css_builder.rb +1 -1
  40. data/lib/capybara/selector/builders/xpath_builder.rb +3 -1
  41. data/lib/capybara/selector/definition.rb +11 -9
  42. data/lib/capybara/selector/definition/button.rb +26 -14
  43. data/lib/capybara/selector/definition/css.rb +1 -1
  44. data/lib/capybara/selector/definition/datalist_input.rb +1 -1
  45. data/lib/capybara/selector/definition/element.rb +2 -1
  46. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  47. data/lib/capybara/selector/definition/label.rb +1 -1
  48. data/lib/capybara/selector/definition/link.rb +8 -0
  49. data/lib/capybara/selector/definition/select.rb +1 -1
  50. data/lib/capybara/selector/definition/table.rb +1 -1
  51. data/lib/capybara/selector/definition/table_row.rb +2 -2
  52. data/lib/capybara/selector/filter_set.rb +2 -2
  53. data/lib/capybara/selector/selector.rb +9 -1
  54. data/lib/capybara/selenium/atoms/src/isDisplayed.js +1 -1
  55. data/lib/capybara/selenium/driver.rb +51 -7
  56. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +9 -11
  57. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -11
  58. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +3 -3
  59. data/lib/capybara/selenium/extensions/find.rb +4 -4
  60. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  61. data/lib/capybara/selenium/logger_suppressor.rb +1 -1
  62. data/lib/capybara/selenium/node.rb +23 -6
  63. data/lib/capybara/selenium/nodes/chrome_node.rb +23 -5
  64. data/lib/capybara/selenium/nodes/firefox_node.rb +7 -2
  65. data/lib/capybara/selenium/nodes/safari_node.rb +1 -1
  66. data/lib/capybara/selenium/patches/action_pauser.rb +4 -1
  67. data/lib/capybara/selenium/patches/atoms.rb +4 -4
  68. data/lib/capybara/selenium/patches/logs.rb +7 -9
  69. data/lib/capybara/server/animation_disabler.rb +8 -3
  70. data/lib/capybara/server/middleware.rb +4 -2
  71. data/lib/capybara/session.rb +23 -14
  72. data/lib/capybara/session/config.rb +3 -1
  73. data/lib/capybara/session/matchers.rb +11 -11
  74. data/lib/capybara/spec/public/test.js +13 -1
  75. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  76. data/lib/capybara/spec/session/check_spec.rb +6 -0
  77. data/lib/capybara/spec/session/click_button_spec.rb +11 -0
  78. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  79. data/lib/capybara/spec/session/has_button_spec.rb +51 -0
  80. data/lib/capybara/spec/session/has_css_spec.rb +2 -1
  81. data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
  82. data/lib/capybara/spec/session/has_field_spec.rb +16 -0
  83. data/lib/capybara/spec/session/has_select_spec.rb +4 -4
  84. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  85. data/lib/capybara/spec/session/has_text_spec.rb +0 -11
  86. data/lib/capybara/spec/session/html_spec.rb +1 -1
  87. data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
  88. data/lib/capybara/spec/session/node_spec.rb +29 -9
  89. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  90. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  91. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  92. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  93. data/lib/capybara/spec/session/window/window_spec.rb +1 -1
  94. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  95. data/lib/capybara/spec/spec_helper.rb +12 -12
  96. data/lib/capybara/spec/test_app.rb +23 -21
  97. data/lib/capybara/spec/views/form.erb +28 -1
  98. data/lib/capybara/spec/views/with_animation.erb +8 -0
  99. data/lib/capybara/spec/views/with_dragula.erb +3 -1
  100. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  101. data/lib/capybara/spec/views/with_js.erb +3 -0
  102. data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
  103. data/lib/capybara/version.rb +1 -1
  104. data/lib/capybara/window.rb +3 -7
  105. data/spec/basic_node_spec.rb +9 -8
  106. data/spec/capybara_spec.rb +1 -1
  107. data/spec/dsl_spec.rb +14 -1
  108. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  109. data/spec/minitest_spec.rb +3 -2
  110. data/spec/rack_test_spec.rb +16 -5
  111. data/spec/result_spec.rb +1 -17
  112. data/spec/rspec/features_spec.rb +3 -1
  113. data/spec/rspec/scenarios_spec.rb +4 -0
  114. data/spec/rspec/shared_spec_matchers.rb +63 -51
  115. data/spec/rspec_spec.rb +4 -0
  116. data/spec/selector_spec.rb +17 -2
  117. data/spec/selenium_spec_chrome.rb +39 -20
  118. data/spec/selenium_spec_chrome_remote.rb +5 -1
  119. data/spec/selenium_spec_firefox.rb +15 -13
  120. data/spec/server_spec.rb +60 -49
  121. data/spec/shared_selenium_node.rb +10 -0
  122. data/spec/shared_selenium_session.rb +98 -7
  123. data/spec/spec_helper.rb +1 -1
  124. metadata +50 -15
  125. data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -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
@@ -108,6 +108,13 @@ $(function() {
108
108
  }, 4000);
109
109
  return false;
110
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
+ });
111
118
  $('#waiter').change(function() {
112
119
  activeRequests = 1;
113
120
  setTimeout(function() {
@@ -264,5 +271,10 @@ $(function() {
264
271
  });
265
272
  $('#multiple-file, #hidden_file').change(function(e){
266
273
  $('body').append($('<p class="file_change">File input changed</p>'));
267
- })
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);
268
280
  });
@@ -53,7 +53,7 @@ Capybara::SpecHelper.spec '#accept_alert', requires: [:modals] do
53
53
  @session.click_link('Alert page change')
54
54
  sleep 1 # ensure page change occurs before the accept_alert block exits
55
55
  end
56
- expect(@session).to have_current_path('/with_html')
56
+ expect(@session).to have_current_path('/with_html', wait: 5)
57
57
  end
58
58
 
59
59
  context 'with an asynchronous alert' do
@@ -229,6 +229,12 @@ Capybara::SpecHelper.spec '#check' do
229
229
  @session.click_button('awesome')
230
230
  expect(extract_results(@session)['cars']).to include('bugatti')
231
231
  end
232
+
233
+ it 'should check via label if multiple labels' do
234
+ expect(@session).to have_field('multi_label_checkbox', checked: false, visible: :hidden)
235
+ @session.check('Label to click', allow_label_click: true)
236
+ expect(@session).to have_field('multi_label_checkbox', checked: true, visible: :hidden)
237
+ end
232
238
  end
233
239
  end
234
240
  end
@@ -193,6 +193,17 @@ Capybara::SpecHelper.spec '#click_button' do
193
193
  end
194
194
  end
195
195
 
196
+ context 'when Capybara.enable_aria_role = true' do
197
+ it 'should click on a button role', requires: [:js] do
198
+ Capybara.enable_aria_role = true
199
+ @session.using_wait_time(1.5) do
200
+ @session.visit('/with_js')
201
+ @session.click_button('ARIA button')
202
+ expect(@session).to have_button('ARIA button has been clicked')
203
+ end
204
+ end
205
+ end
206
+
196
207
  context 'with fields associated with the form using the form attribute', requires: [:form_attribute] do
197
208
  let(:results) { extract_results(@session) }
198
209
 
@@ -22,7 +22,7 @@ Capybara::SpecHelper.spec '#current_url, #current_path, #current_host' do
22
22
 
23
23
  expect(@session.current_url.chomp('?')).to eq("#{scheme}://#{s.host}:#{s.port}#{path}")
24
24
  expect(@session.current_host).to eq("#{scheme}://#{s.host}") # no port
25
- expect(@session.current_path).to eq(path)
25
+ expect(@session.current_path).to eq(path.split('#')[0])
26
26
  # Server should agree with us
27
27
  expect(@session).to have_content("Current host is #{scheme}://#{s.host}:#{s.port}") if path == '/host'
28
28
  end
@@ -84,6 +84,16 @@ Capybara::SpecHelper.spec '#current_url, #current_path, #current_host' do
84
84
  should_be_on 0, '/landed'
85
85
  end
86
86
 
87
+ it 'maintains fragment' do
88
+ @session.visit("#{bases[0]}/redirect#fragment")
89
+ should_be_on 0, '/landed#fragment'
90
+ end
91
+
92
+ it 'redirects to a fragment' do
93
+ @session.visit("#{bases[0]}/redirect_with_fragment")
94
+ should_be_on 0, '/landed#with_fragment'
95
+ end
96
+
87
97
  it 'is affected by pushState', requires: [:js] do
88
98
  @session.visit('/with_js')
89
99
  @session.execute_script("window.history.pushState({}, '', '/pushed')")
@@ -9,6 +9,8 @@ Capybara::SpecHelper.spec '#has_button?' do
9
9
  expect(@session).to have_button('med')
10
10
  expect(@session).to have_button('crap321')
11
11
  expect(@session).to have_button(:crap321)
12
+ expect(@session).to have_button('button with label element')
13
+ expect(@session).to have_button('button within label element')
12
14
  end
13
15
 
14
16
  it 'should be true for disabled buttons if disabled: true' do
@@ -39,6 +41,30 @@ Capybara::SpecHelper.spec '#has_button?' do
39
41
  expect(@session).to have_button('awe123', type: 'submit')
40
42
  expect(@session).not_to have_button('awe123', type: 'reset')
41
43
  end
44
+
45
+ it 'should be true for role=button when enable_aria_role: true' do
46
+ expect(@session).to have_button('ARIA button', enable_aria_role: true)
47
+ end
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
+
53
+ it 'should be false for role=button when enable_aria_role: false' do
54
+ expect(@session).not_to have_button('ARIA button', enable_aria_role: false)
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
42
68
  end
43
69
 
44
70
  Capybara::SpecHelper.spec '#has_no_button?' do
@@ -66,4 +92,29 @@ Capybara::SpecHelper.spec '#has_no_button?' do
66
92
  it 'should be false for disabled buttons if disabled: false' do
67
93
  expect(@session).to have_no_button('Disabled button', disabled: false)
68
94
  end
95
+
96
+ it 'should be true for role=button when enable_aria_role: false' do
97
+ expect(@session).to have_no_button('ARIA button', enable_aria_role: false)
98
+ end
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
+
104
+ it 'should be false for role=button when enable_aria_role: true' do
105
+ expect(@session).not_to have_no_button('ARIA button', enable_aria_role: true)
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
69
120
  end
@@ -14,8 +14,9 @@ Capybara::SpecHelper.spec '#has_css?' do
14
14
  # This was never a specifically accepted format but it has worked for a
15
15
  # lot of versions.
16
16
  # TODO: Remove in 4.0
17
- expect_any_instance_of(Kernel).to receive(:warn) # rubocop:disable RSpec/AnyInstance
17
+ allow(Capybara::Helpers).to receive(:warn).and_return(nil)
18
18
  expect(@session).to have_css(:p)
19
+ expect(Capybara::Helpers).to have_received(:warn)
19
20
  end
20
21
 
21
22
  it 'should be false if the given selector is not on the page' do
@@ -94,6 +94,13 @@ Capybara::SpecHelper.spec '#has_current_path?' do
94
94
  expect(@session).to have_current_path(nil, ignore_query: true)
95
95
  end.not_to raise_exception
96
96
  end
97
+
98
+ it 'should accept a filter block that receives Addressable::URL' do
99
+ @session.visit('/with_js?a=3&b=defgh')
100
+ expect(@session).to have_current_path('/with_js', ignore_query: true) { |url|
101
+ url.query_values.keys == %w[a b]
102
+ }
103
+ end
97
104
  end
98
105
 
99
106
  Capybara::SpecHelper.spec '#has_no_current_path?' do
@@ -128,11 +135,17 @@ Capybara::SpecHelper.spec '#has_no_current_path?' do
128
135
  # Without ignore_query option
129
136
  expect do
130
137
  expect(@session).not_to have_current_path('/with_js')
131
- end. not_to raise_exception
138
+ end.not_to raise_exception
132
139
 
133
140
  # With ignore_query option
134
141
  expect do
135
142
  expect(@session).not_to have_current_path('/with_js', ignore_query: true)
136
- end. not_to raise_exception
143
+ end.not_to raise_exception
144
+ end
145
+
146
+ it 'should accept a filter block that receives Addressable::URL' do
147
+ expect(@session).to have_no_current_path('/with_js', ignore_query: true) { |url|
148
+ !url.query.nil?
149
+ }
137
150
  end
138
151
  end
@@ -60,6 +60,22 @@ Capybara::SpecHelper.spec '#has_field' do
60
60
  end
61
61
  end
62
62
 
63
+ context 'with validation message', requires: [:html_validation] do
64
+ it 'should accept a regexp' do
65
+ @session.fill_in('form_zipcode', with: '1234')
66
+ expect(@session).to have_field('form_zipcode', validation_message: /match the requested format/)
67
+ expect(@session).not_to have_field('form_zipcode', validation_message: /random/)
68
+ end
69
+
70
+ it 'should accept a string' do
71
+ @session.fill_in('form_zipcode', with: '1234')
72
+ expect(@session).to have_field('form_zipcode', validation_message: 'Please match the requested format.')
73
+ expect(@session).not_to have_field('form_zipcode', validation_message: 'match the requested format.')
74
+ @session.fill_in('form_zipcode', with: '12345')
75
+ expect(@session).to have_field('form_zipcode', validation_message: '')
76
+ end
77
+ end
78
+
63
79
  context 'with type' do
64
80
  it 'should be true if a field with the given type is on the page' do
65
81
  expect(@session).to have_field('First Name', type: 'text')
@@ -63,7 +63,7 @@ Capybara::SpecHelper.spec '#has_select?' do
63
63
  end
64
64
 
65
65
  it "should be true even when the selected option invisible, regardless of the select's visibility" do
66
- expect(@session).to have_select('Icecream', visible: false, selected: 'Chocolate')
66
+ expect(@session).to have_select('Icecream', visible: :hidden, selected: 'Chocolate')
67
67
  expect(@session).to have_select('Sorbet', selected: 'Vanilla')
68
68
  end
69
69
  end
@@ -88,7 +88,7 @@ Capybara::SpecHelper.spec '#has_select?' do
88
88
  end
89
89
 
90
90
  it "should be true even when the selected values are invisible, regardless of the select's visibility" do
91
- expect(@session).to have_select('Dessert', visible: false, with_options: %w[Pudding Tiramisu])
91
+ expect(@session).to have_select('Dessert', visible: :hidden, with_options: %w[Pudding Tiramisu])
92
92
  expect(@session).to have_select('Cake', with_selected: ['Chocolate Cake', 'Sponge Cake'])
93
93
  end
94
94
 
@@ -113,7 +113,7 @@ Capybara::SpecHelper.spec '#has_select?' do
113
113
  end
114
114
 
115
115
  it 'should be true even when the options are invisible, if the select itself is invisible' do
116
- expect(@session).to have_select('Icecream', visible: false, options: %w[Chocolate Vanilla Strawberry])
116
+ expect(@session).to have_select('Icecream', visible: :hidden, options: %w[Chocolate Vanilla Strawberry])
117
117
  end
118
118
  end
119
119
 
@@ -158,7 +158,7 @@ Capybara::SpecHelper.spec '#has_select?' do
158
158
  end
159
159
 
160
160
  it 'should be true even when the options are invisible, if the select itself is invisible' do
161
- expect(@session).to have_select('Icecream', visible: false, with_options: %w[Vanilla Strawberry])
161
+ expect(@session).to have_select('Icecream', visible: :hidden, with_options: %w[Vanilla Strawberry])
162
162
  end
163
163
  end
164
164
 
@@ -61,12 +61,12 @@ Capybara::SpecHelper.spec '#has_selector?' do
61
61
  end
62
62
 
63
63
  it 'should respect visibility setting' do
64
- expect(@session).to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: false)
65
- expect(@session).not_to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: true)
64
+ expect(@session).to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :all)
65
+ expect(@session).not_to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :visible)
66
66
  Capybara.ignore_hidden_elements = false
67
- expect(@session).to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: false)
67
+ expect(@session).to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :all)
68
68
  Capybara.visible_text_only = true
69
- expect(@session).not_to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: true)
69
+ expect(@session).not_to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :visible)
70
70
  end
71
71
 
72
72
  it 'should discard all matches where the given regexp is not matched' do
@@ -133,17 +133,6 @@ Capybara::SpecHelper.spec '#has_text?' do
133
133
  expect(@session).to have_text(:visible, with_to_hash, {})
134
134
  end
135
135
  end
136
-
137
- it 'should fail if passed without empty options' do
138
- with_to_hash = Class.new do
139
- def to_s; '42' end
140
- def to_hash; { blah: 'Other hash' } end
141
- end.new
142
- @session.visit('/with_html')
143
- expect do
144
- expect(@session).to have_text(:visible, with_to_hash)
145
- end.to raise_error(ArgumentError)
146
- end
147
136
  end
148
137
 
149
138
  context 'with exact: true option' do
@@ -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
 
@@ -28,8 +28,8 @@ Capybara::SpecHelper.spec '#matches_style?', requires: [:css] do
28
28
  output(/have_style is deprecated/).to_stderr
29
29
 
30
30
  el = @session.find(:css, '#first')
31
- allow(el).to receive(:warn).and_return(nil)
31
+ allow(Capybara::Helpers).to receive(:warn).and_return(nil)
32
32
  el.has_style?('display' => /^bl/)
33
- expect(el).to have_received(:warn)
33
+ expect(Capybara::Helpers).to have_received(:warn)
34
34
  end
35
35
  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
 
@@ -271,12 +271,12 @@ Capybara::SpecHelper.spec 'node' do
271
271
 
272
272
  it 'works when details is toggled open and closed' do
273
273
  @session.find(:css, '#closed_details > summary').click
274
- expect(@session).to have_css('#closed_details *', visible: true, count: 5)
274
+ expect(@session).to have_css('#closed_details *', visible: :visible, count: 5)
275
275
  .and(have_no_css('#closed_details *', visible: :hidden))
276
276
 
277
277
  @session.find(:css, '#closed_details > summary').click
278
278
  descendants_css = '#closed_details > *:not(summary), #closed_details > *:not(summary) *'
279
- expect(@session).to have_no_css(descendants_css, visible: true)
279
+ expect(@session).to have_no_css(descendants_css, visible: :visible)
280
280
  .and(have_css(descendants_css, visible: :hidden, count: 3))
281
281
  end
282
282
  end
@@ -388,8 +388,8 @@ Capybara::SpecHelper.spec 'node' do
388
388
 
389
389
  describe '#==' do
390
390
  it 'preserve object identity' do
391
- expect(@session.find('//h1') == @session.find('//h1')).to be true # rubocop:disable Lint/UselessComparison
392
- expect(@session.find('//h1') === @session.find('//h1')).to be true # rubocop:disable Style/CaseEquality, Lint/UselessComparison
391
+ expect(@session.find('//h1') == @session.find('//h1')).to be true # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
392
+ expect(@session.find('//h1') === @session.find('//h1')).to be true # rubocop:disable Style/CaseEquality, Lint/BinaryOperatorWithIdenticalOperands
393
393
  expect(@session.find('//h1').eql?(@session.find('//h1'))).to be false
394
394
  end
395
395
 
@@ -409,6 +409,17 @@ Capybara::SpecHelper.spec 'node' do
409
409
  element = @session.find(:link, 'Second Link')
410
410
  expect(@session.find(:xpath, element.path)).to eq(element)
411
411
  end
412
+
413
+ it 'reports when element in shadow dom', requires: [:shadow_dom] do
414
+ @session.visit('/with_js')
415
+ shadow = @session.find(:css, '#shadow')
416
+ element = @session.evaluate_script(<<~JS, shadow)
417
+ (function(root){
418
+ return root.shadowRoot.querySelector('span');
419
+ })(arguments[0])
420
+ JS
421
+ expect(element.path).to eq '(: Shadow DOM element - no XPath :)'
422
+ end
412
423
  end
413
424
 
414
425
  describe '#trigger', requires: %i[js trigger] do
@@ -446,7 +457,7 @@ Capybara::SpecHelper.spec 'node' do
446
457
 
447
458
  it 'should work with Dragula' do
448
459
  @session.visit('/with_dragula')
449
- @session.within(:css, '#sortable') do
460
+ @session.within(:css, '#sortable.ready') do
450
461
  src = @session.find('div', text: 'Item 1')
451
462
  target = @session.find('div', text: 'Item 3')
452
463
  src.drag_to target
@@ -671,6 +682,15 @@ Capybara::SpecHelper.spec 'node' do
671
682
  expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
672
683
  end
673
684
 
685
+ it 'can drop a pathname' do
686
+ @session.visit('/with_js')
687
+ target = @session.find('//div[@id="drop_html5"]')
688
+ target.drop(
689
+ Pathname.new(with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))))
690
+ )
691
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
692
+ end
693
+
674
694
  it 'can drop multiple strings' do
675
695
  @session.visit('/with_js')
676
696
  target = @session.find('//div[@id="drop_html5"]')
@@ -758,7 +778,7 @@ Capybara::SpecHelper.spec 'node' do
758
778
  @session.visit('with_js')
759
779
  @session.find(:css, '#click-test').click(x: 5, y: 5)
760
780
  link = @session.find(:link, 'has-been-clicked')
761
- locations = link.text.match(/^Has been clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
781
+ locations = link.text.match(/^Has been clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
762
782
  # Resulting click location should be very close to 0, 0 relative to top left corner of the element, but may not be exact due to
763
783
  # integer/float conversions and rounding.
764
784
  expect(locations[:x].to_f).to be_within(1).of(5)
@@ -884,7 +904,7 @@ Capybara::SpecHelper.spec 'node' do
884
904
  @session.visit('with_js')
885
905
  @session.find(:css, '#click-test').double_click(x: 10, y: 5)
886
906
  link = @session.find(:link, 'has-been-double-clicked')
887
- locations = link.text.match(/^Has been double clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
907
+ locations = link.text.match(/^Has been double clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
888
908
  # Resulting click location should be very close to 10, 5 relative to top left corner of the element, but may not be exact due
889
909
  # to integer/float conversions and rounding.
890
910
  expect(locations[:x].to_f).to be_within(1).of(10)
@@ -970,7 +990,7 @@ Capybara::SpecHelper.spec 'node' do
970
990
  @session.visit('with_js')
971
991
  @session.find(:css, '#click-test').right_click(x: 10, y: 10)
972
992
  link = @session.find(:link, 'has-been-right-clicked')
973
- locations = link.text.match(/^Has been right clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
993
+ locations = link.text.match(/^Has been right clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
974
994
  # Resulting click location should be very close to 10, 10 relative to top left corner of the element, but may not be exact due
975
995
  # to integer/float conversions and rounding
976
996
  expect(locations[:x].to_f).to be_within(1).of(10)