capybara 3.32.2 → 3.39.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (205) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +227 -19
  3. data/README.md +36 -15
  4. data/lib/capybara/config.rb +18 -8
  5. data/lib/capybara/cucumber.rb +1 -1
  6. data/lib/capybara/driver/base.rb +8 -0
  7. data/lib/capybara/driver/node.rb +5 -1
  8. data/lib/capybara/dsl.rb +4 -10
  9. data/lib/capybara/helpers.rb +21 -2
  10. data/lib/capybara/minitest/spec.rb +14 -11
  11. data/lib/capybara/minitest.rb +2 -3
  12. data/lib/capybara/node/actions.rb +27 -27
  13. data/lib/capybara/node/base.rb +8 -7
  14. data/lib/capybara/node/document.rb +2 -2
  15. data/lib/capybara/node/element.rb +14 -7
  16. data/lib/capybara/node/finders.rb +18 -8
  17. data/lib/capybara/node/matchers.rb +12 -12
  18. data/lib/capybara/node/simple.rb +10 -2
  19. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  20. data/lib/capybara/queries/active_element_query.rb +18 -0
  21. data/lib/capybara/queries/ancestor_query.rb +3 -2
  22. data/lib/capybara/queries/base_query.rb +2 -2
  23. data/lib/capybara/queries/current_path_query.rb +14 -4
  24. data/lib/capybara/queries/selector_query.rb +78 -28
  25. data/lib/capybara/queries/sibling_query.rb +3 -2
  26. data/lib/capybara/queries/style_query.rb +1 -1
  27. data/lib/capybara/queries/text_query.rb +8 -2
  28. data/lib/capybara/rack_test/browser.rb +70 -11
  29. data/lib/capybara/rack_test/driver.rb +5 -4
  30. data/lib/capybara/rack_test/form.rb +30 -8
  31. data/lib/capybara/rack_test/node.rb +28 -22
  32. data/lib/capybara/registration_container.rb +41 -0
  33. data/lib/capybara/registrations/drivers.rb +20 -14
  34. data/lib/capybara/registrations/patches/puma_ssl.rb +3 -1
  35. data/lib/capybara/registrations/servers.rb +32 -11
  36. data/lib/capybara/result.rb +6 -10
  37. data/lib/capybara/rspec/matcher_proxies.rb +7 -7
  38. data/lib/capybara/rspec/matchers/base.rb +8 -6
  39. data/lib/capybara/rspec/matchers/compound.rb +1 -1
  40. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  41. data/lib/capybara/rspec/matchers/have_selector.rb +5 -5
  42. data/lib/capybara/rspec/matchers/match_style.rb +5 -0
  43. data/lib/capybara/rspec/matchers.rb +21 -20
  44. data/lib/capybara/rspec.rb +2 -0
  45. data/lib/capybara/selector/builders/css_builder.rb +2 -2
  46. data/lib/capybara/selector/builders/xpath_builder.rb +4 -2
  47. data/lib/capybara/selector/css.rb +1 -1
  48. data/lib/capybara/selector/definition/button.rb +29 -12
  49. data/lib/capybara/selector/definition/checkbox.rb +1 -1
  50. data/lib/capybara/selector/definition/css.rb +1 -1
  51. data/lib/capybara/selector/definition/datalist_input.rb +1 -1
  52. data/lib/capybara/selector/definition/element.rb +2 -1
  53. data/lib/capybara/selector/definition/file_field.rb +1 -1
  54. data/lib/capybara/selector/definition/fillable_field.rb +2 -2
  55. data/lib/capybara/selector/definition/label.rb +1 -1
  56. data/lib/capybara/selector/definition/link.rb +10 -1
  57. data/lib/capybara/selector/definition/radio_button.rb +1 -1
  58. data/lib/capybara/selector/definition/select.rb +1 -1
  59. data/lib/capybara/selector/definition/table.rb +1 -1
  60. data/lib/capybara/selector/definition/table_row.rb +2 -2
  61. data/lib/capybara/selector/definition.rb +14 -10
  62. data/lib/capybara/selector/filter_set.rb +6 -9
  63. data/lib/capybara/selector/regexp_disassembler.rb +2 -5
  64. data/lib/capybara/selector/selector.rb +14 -2
  65. data/lib/capybara/selector.rb +13 -3
  66. data/lib/capybara/selenium/atoms/src/isDisplayed.js +1 -1
  67. data/lib/capybara/selenium/driver.rb +71 -10
  68. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +10 -12
  69. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +18 -16
  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 +5 -4
  73. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  74. data/lib/capybara/selenium/logger_suppressor.rb +13 -3
  75. data/lib/capybara/selenium/node.rb +90 -37
  76. data/lib/capybara/selenium/nodes/chrome_node.rb +29 -7
  77. data/lib/capybara/selenium/nodes/edge_node.rb +25 -3
  78. data/lib/capybara/selenium/nodes/firefox_node.rb +10 -5
  79. data/lib/capybara/selenium/nodes/safari_node.rb +5 -5
  80. data/lib/capybara/selenium/patches/action_pauser.rb +3 -3
  81. data/lib/capybara/selenium/patches/atoms.rb +5 -5
  82. data/lib/capybara/selenium/patches/logs.rb +7 -9
  83. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -1
  84. data/lib/capybara/server/animation_disabler.rb +43 -21
  85. data/lib/capybara/server/middleware.rb +5 -3
  86. data/lib/capybara/session/config.rb +6 -2
  87. data/lib/capybara/session/matchers.rb +11 -11
  88. data/lib/capybara/session.rb +52 -44
  89. data/lib/capybara/spec/public/test.js +17 -1
  90. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  91. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  92. data/lib/capybara/spec/session/all_spec.rb +10 -14
  93. data/lib/capybara/spec/session/assert_text_spec.rb +17 -17
  94. data/lib/capybara/spec/session/attach_file_spec.rb +6 -0
  95. data/lib/capybara/spec/session/check_spec.rb +16 -0
  96. data/lib/capybara/spec/session/choose_spec.rb +6 -0
  97. data/lib/capybara/spec/session/click_button_spec.rb +11 -0
  98. data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
  99. data/lib/capybara/spec/session/click_link_spec.rb +11 -0
  100. data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
  101. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  102. data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
  103. data/lib/capybara/spec/session/find_link_spec.rb +10 -0
  104. data/lib/capybara/spec/session/find_spec.rb +7 -1
  105. data/lib/capybara/spec/session/first_spec.rb +1 -1
  106. data/lib/capybara/spec/session/frame/within_frame_spec.rb +2 -0
  107. data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
  108. data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -2
  109. data/lib/capybara/spec/session/has_any_selectors_spec.rb +6 -2
  110. data/lib/capybara/spec/session/has_button_spec.rb +81 -0
  111. data/lib/capybara/spec/session/has_css_spec.rb +2 -1
  112. data/lib/capybara/spec/session/has_current_path_spec.rb +18 -5
  113. data/lib/capybara/spec/session/has_field_spec.rb +41 -1
  114. data/lib/capybara/spec/session/has_link_spec.rb +40 -0
  115. data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
  116. data/lib/capybara/spec/session/has_select_spec.rb +14 -8
  117. data/lib/capybara/spec/session/has_selector_spec.rb +19 -4
  118. data/lib/capybara/spec/session/has_text_spec.rb +6 -25
  119. data/lib/capybara/spec/session/html_spec.rb +1 -1
  120. data/lib/capybara/spec/session/matches_style_spec.rb +4 -2
  121. data/lib/capybara/spec/session/node_spec.rb +111 -10
  122. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  123. data/lib/capybara/spec/session/reset_session_spec.rb +13 -0
  124. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  125. data/lib/capybara/spec/session/scroll_spec.rb +7 -5
  126. data/lib/capybara/spec/session/visit_spec.rb +20 -0
  127. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  128. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  129. data/lib/capybara/spec/session/window/window_spec.rb +2 -2
  130. data/lib/capybara/spec/session/window/windows_spec.rb +2 -2
  131. data/lib/capybara/spec/session/within_spec.rb +13 -0
  132. data/lib/capybara/spec/spec_helper.rb +23 -16
  133. data/lib/capybara/spec/test_app.rb +113 -34
  134. data/lib/capybara/spec/views/animated.erb +1 -1
  135. data/lib/capybara/spec/views/form.erb +53 -5
  136. data/lib/capybara/spec/views/frame_child.erb +1 -1
  137. data/lib/capybara/spec/views/frame_one.erb +1 -1
  138. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  139. data/lib/capybara/spec/views/frame_two.erb +1 -1
  140. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  141. data/lib/capybara/spec/views/layout.erb +10 -0
  142. data/lib/capybara/spec/views/obscured.erb +1 -1
  143. data/lib/capybara/spec/views/offset.erb +2 -1
  144. data/lib/capybara/spec/views/path.erb +2 -2
  145. data/lib/capybara/spec/views/popup_one.erb +1 -1
  146. data/lib/capybara/spec/views/popup_two.erb +1 -1
  147. data/lib/capybara/spec/views/react.erb +2 -2
  148. data/lib/capybara/spec/views/scroll.erb +2 -1
  149. data/lib/capybara/spec/views/spatial.erb +1 -1
  150. data/lib/capybara/spec/views/with_animation.erb +10 -3
  151. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  152. data/lib/capybara/spec/views/with_dragula.erb +5 -3
  153. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  154. data/lib/capybara/spec/views/with_hover.erb +2 -2
  155. data/lib/capybara/spec/views/with_html.erb +3 -3
  156. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  157. data/lib/capybara/spec/views/with_js.erb +5 -3
  158. data/lib/capybara/spec/views/with_jstree.erb +1 -1
  159. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  160. data/lib/capybara/spec/views/with_scope.erb +2 -2
  161. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  162. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  163. data/lib/capybara/spec/views/with_sortable_js.erb +3 -3
  164. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  165. data/lib/capybara/spec/views/with_windows.erb +1 -1
  166. data/lib/capybara/spec/views/within_frames.erb +1 -1
  167. data/lib/capybara/version.rb +1 -1
  168. data/lib/capybara/window.rb +4 -8
  169. data/lib/capybara.rb +40 -31
  170. data/spec/basic_node_spec.rb +25 -11
  171. data/spec/capybara_spec.rb +13 -1
  172. data/spec/counter_spec.rb +35 -0
  173. data/spec/css_builder_spec.rb +1 -1
  174. data/spec/css_splitter_spec.rb +1 -1
  175. data/spec/dsl_spec.rb +18 -3
  176. data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -2
  177. data/spec/fixtures/selenium_driver_rspec_success.rb +3 -3
  178. data/spec/minitest_spec.rb +7 -2
  179. data/spec/minitest_spec_spec.rb +4 -0
  180. data/spec/per_session_config_spec.rb +1 -1
  181. data/spec/rack_test_spec.rb +41 -12
  182. data/spec/result_spec.rb +32 -35
  183. data/spec/rspec/features_spec.rb +6 -4
  184. data/spec/rspec/scenarios_spec.rb +6 -2
  185. data/spec/rspec/shared_spec_matchers.rb +64 -52
  186. data/spec/rspec_matchers_spec.rb +25 -0
  187. data/spec/rspec_spec.rb +6 -2
  188. data/spec/sauce_spec_chrome.rb +4 -4
  189. data/spec/selector_spec.rb +21 -6
  190. data/spec/selenium_spec_chrome.rb +50 -31
  191. data/spec/selenium_spec_chrome_remote.rb +16 -11
  192. data/spec/selenium_spec_edge.rb +12 -6
  193. data/spec/selenium_spec_firefox.rb +39 -20
  194. data/spec/selenium_spec_firefox_remote.rb +19 -4
  195. data/spec/selenium_spec_ie.rb +7 -8
  196. data/spec/selenium_spec_safari.rb +34 -20
  197. data/spec/server_spec.rb +65 -54
  198. data/spec/shared_selenium_node.rb +0 -4
  199. data/spec/shared_selenium_session.rb +104 -12
  200. data/spec/spec_helper.rb +36 -3
  201. data/spec/whitespace_normalizer_spec.rb +54 -0
  202. data/spec/xpath_builder_spec.rb +1 -1
  203. metadata +82 -21
  204. data/lib/capybara/spec/session/source_spec.rb +0 -0
  205. data/lib/capybara/spec/views/with_title.erb +0 -5
@@ -11,12 +11,38 @@ Capybara::SpecHelper.spec '#has_link?' do
11
11
  expect(@session).to have_link('A link', href: '/with_simple_html')
12
12
  expect(@session).to have_link(:'A link', href: :'/with_simple_html')
13
13
  expect(@session).to have_link('A link', href: %r{/with_simple_html})
14
+ expect(@session).to have_link('labore', target: '_self')
14
15
  end
15
16
 
16
17
  it 'should be false if the given link is not on the page' do
17
18
  expect(@session).not_to have_link('monkey')
18
19
  expect(@session).not_to have_link('A link', href: '/nonexistent-href')
19
20
  expect(@session).not_to have_link('A link', href: /nonexistent/)
21
+ expect(@session).not_to have_link('labore', target: '_blank')
22
+ end
23
+
24
+ it 'should notify if an invalid locator is specified' do
25
+ allow(Capybara::Helpers).to receive(:warn).and_return(nil)
26
+ @session.has_link?(@session)
27
+ expect(Capybara::Helpers).to have_received(:warn).with(/Called from: .+/)
28
+ end
29
+
30
+ context 'with focused:', requires: [:active_element] do
31
+ it 'should be true if the given link is on the page and has focus' do
32
+ @session.send_keys(:tab)
33
+
34
+ expect(@session).to have_link('labore', focused: true)
35
+ end
36
+
37
+ it 'should be false if the given link is on the page and does not have focus' do
38
+ expect(@session).to have_link('labore', focused: false)
39
+ end
40
+ end
41
+
42
+ it 'should raise an error if an invalid option is passed' do
43
+ expect do
44
+ expect(@session).to have_link('labore', invalid: true)
45
+ 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, :target, :download')
20
46
  end
21
47
  end
22
48
 
@@ -29,11 +55,25 @@ Capybara::SpecHelper.spec '#has_no_link?' do
29
55
  expect(@session).not_to have_no_link('foo')
30
56
  expect(@session).not_to have_no_link('awesome title')
31
57
  expect(@session).not_to have_no_link('A link', href: '/with_simple_html')
58
+ expect(@session).not_to have_no_link('labore', target: '_self')
32
59
  end
33
60
 
34
61
  it 'should be true if the given link is not on the page' do
35
62
  expect(@session).to have_no_link('monkey')
36
63
  expect(@session).to have_no_link('A link', href: '/nonexistent-href')
37
64
  expect(@session).to have_no_link('A link', href: %r{/nonexistent-href})
65
+ expect(@session).to have_no_link('labore', target: '_blank')
66
+ end
67
+
68
+ context 'with focused:', requires: [:active_element] do
69
+ it 'should be true if the given link is on the page and has focus' do
70
+ expect(@session).to have_no_link('labore', focused: true)
71
+ end
72
+
73
+ it 'should be false if the given link is on the page and does not have focus' do
74
+ @session.send_keys(:tab)
75
+
76
+ expect(@session).to have_no_link('labore', focused: false)
77
+ end
38
78
  end
39
79
  end
@@ -8,10 +8,10 @@ Capybara::SpecHelper.spec '#have_none_of_selectors' do
8
8
  it 'should be false if any of the given locators are on the page' do
9
9
  expect do
10
10
  expect(@session).to have_none_of_selectors(:xpath, '//p', '//a')
11
- end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
11
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
12
12
  expect do
13
13
  expect(@session).to have_none_of_selectors(:css, 'p a#foo')
14
- end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
14
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
15
15
  end
16
16
 
17
17
  it 'should be true if none of the given locators are on the page' do
@@ -24,7 +24,7 @@ Capybara::SpecHelper.spec '#have_none_of_selectors' do
24
24
  expect(@session).to have_none_of_selectors('p a#doesnotexist', 'abbr')
25
25
  expect do
26
26
  expect(@session).to have_none_of_selectors('abbr', 'p a#foo')
27
- end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
27
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
28
28
  end
29
29
 
30
30
  context 'should respect scopes' do
@@ -32,7 +32,7 @@ Capybara::SpecHelper.spec '#have_none_of_selectors' do
32
32
  @session.within "//p[@id='first']" do
33
33
  expect do
34
34
  expect(@session).to have_none_of_selectors(".//a[@id='foo']")
35
- end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
35
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
36
36
  expect(@session).to have_none_of_selectors(".//a[@id='red']")
37
37
  end
38
38
  end
@@ -41,7 +41,7 @@ Capybara::SpecHelper.spec '#have_none_of_selectors' do
41
41
  el = @session.find "//p[@id='first']"
42
42
  expect do
43
43
  expect(el).to have_none_of_selectors(".//a[@id='foo']")
44
- end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
44
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
45
45
  expect(el).to have_none_of_selectors(".//a[@id='red']")
46
46
  end
47
47
  end
@@ -50,14 +50,14 @@ Capybara::SpecHelper.spec '#have_none_of_selectors' do
50
50
  it 'should apply the options to all locators' do
51
51
  expect do
52
52
  expect(@session).to have_none_of_selectors('//p//a', text: 'Redirect')
53
- end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
53
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
54
54
  expect(@session).to have_none_of_selectors('//p', text: 'Doesnotexist')
55
55
  end
56
56
 
57
57
  it 'should discard all matches where the given regexp is matched' do
58
58
  expect do
59
59
  expect(@session).to have_none_of_selectors('//p//a', text: /re[dab]i/i, count: 1)
60
- end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
60
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
61
61
  expect(@session).to have_none_of_selectors('//p//a', text: /Red$/)
62
62
  end
63
63
  end
@@ -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
 
@@ -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
@@ -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
@@ -117,6 +117,21 @@ Capybara::SpecHelper.spec '#has_selector?' do
117
117
  expect(@session).to have_selector(:id, 'h2one', text: 'Header Class Test One', exact_text: false)
118
118
  expect(@session).to have_selector(:id, 'h2one', text: 'Header Class Test', exact_text: false)
119
119
  end
120
+
121
+ it 'should warn if text option is a regexp that it is ignoring exact_text' do
122
+ allow(Capybara::Helpers).to receive(:warn)
123
+ expect(@session).to have_selector(:id, 'h2one', text: /Class Test/, exact_text: true)
124
+ expect(Capybara::Helpers).to have_received(:warn).with(/'exact_text' option is not supported/)
125
+ end
126
+ end
127
+
128
+ context 'regexp' do
129
+ it 'should only match when it fully matches' do
130
+ expect(@session).to have_selector(:id, 'h2one', exact_text: /Header Class Test One/)
131
+ expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Header Class Test/)
132
+ expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Class Test One/)
133
+ expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Class Test/)
134
+ end
120
135
  end
121
136
  end
122
137
 
@@ -127,22 +127,7 @@ Capybara::SpecHelper.spec '#has_text?' do
127
127
  def to_hash; { value: 'Other hash' } end
128
128
  end.new
129
129
  @session.visit('/with_html')
130
- if RUBY_VERSION >= '2.7'
131
- expect(@session).to have_text(:visible, with_to_hash, **{})
132
- else
133
- expect(@session).to have_text(:visible, with_to_hash, {})
134
- end
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)
130
+ expect(@session).to have_text(:visible, with_to_hash, **{})
146
131
  end
147
132
  end
148
133
 
@@ -168,16 +153,12 @@ Capybara::SpecHelper.spec '#has_text?' do
168
153
  expect(@session).to have_text(42)
169
154
  end
170
155
 
171
- it 'should be true when passed nil' do
156
+ it 'should be true when passed nil, and warn about it' do
172
157
  # nil is converted to '' when to_s is invoked
173
158
  @session.visit('/with_html')
174
- expect(@session).to have_text(nil)
175
- end
176
-
177
- it 'should warn when passed nil' do
178
- @session.visit('/with_html')
179
- expect_any_instance_of(Kernel).to receive(:warn).with(/Checking for expected text of nil is confusing/) # rubocop:disable RSpec/AnyInstance
180
- expect(@session).to have_text(nil)
159
+ expect do
160
+ expect(@session).to have_text(nil)
161
+ end.to output(/Checking for expected text of nil is confusing/).to_stderr
181
162
  end
182
163
 
183
164
  it 'should wait for text to appear', requires: [:js] do
@@ -367,7 +348,7 @@ Capybara::SpecHelper.spec '#has_no_text?' do
367
348
  expect(@session).to have_no_text(/xxxxyzzz/)
368
349
  end
369
350
 
370
- it 'should be false if the text in the page matches given regexp' do
351
+ it 'should be false if the text in the page matches given regexp' do
371
352
  @session.visit('/with_html')
372
353
  expect(@session).not_to have_no_text(/Lorem/)
373
354
  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
 
@@ -23,13 +23,15 @@ Capybara::SpecHelper.spec '#matches_style?', requires: [:css] do
23
23
  expect(@session.find(:css, '#first').matches_style?(display: /^in/)).to be false
24
24
  end
25
25
 
26
+ # rubocop:disable Capybara/MatchStyle
26
27
  it 'deprecated has_style?' do
27
28
  expect { have_style(display: /^bl/) }.to \
28
29
  output(/have_style is deprecated/).to_stderr
29
30
 
30
31
  el = @session.find(:css, '#first')
31
- allow(el).to receive(:warn).and_return(nil)
32
+ allow(Capybara::Helpers).to receive(:warn).and_return(nil)
32
33
  el.has_style?('display' => /^bl/)
33
- expect(el).to have_received(:warn)
34
+ expect(Capybara::Helpers).to have_received(:warn)
34
35
  end
36
+ # rubocop:enable Capybara/MatchStyle
35
37
  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
 
@@ -157,6 +157,12 @@ Capybara::SpecHelper.spec 'node' do
157
157
  expect(@session.find(:css, '#existing_content_editable_child_parent').text).to eq("Some content\nWYSIWYG")
158
158
  end
159
159
  end
160
+
161
+ it 'should submit single text input forms if ended with \n' do
162
+ @session.visit('/form')
163
+ @session.find(:css, '#single_input').set("my entry\n")
164
+ expect(extract_results(@session)['single_input']).to eq('my entry')
165
+ end
160
166
  end
161
167
 
162
168
  describe '#tag_name' do
@@ -271,12 +277,12 @@ Capybara::SpecHelper.spec 'node' do
271
277
 
272
278
  it 'works when details is toggled open and closed' do
273
279
  @session.find(:css, '#closed_details > summary').click
274
- expect(@session).to have_css('#closed_details *', visible: true, count: 5)
280
+ expect(@session).to have_css('#closed_details *', visible: :visible, count: 5)
275
281
  .and(have_no_css('#closed_details *', visible: :hidden))
276
282
 
277
283
  @session.find(:css, '#closed_details > summary').click
278
284
  descendants_css = '#closed_details > *:not(summary), #closed_details > *:not(summary) *'
279
- expect(@session).to have_no_css(descendants_css, visible: true)
285
+ expect(@session).to have_no_css(descendants_css, visible: :visible)
280
286
  .and(have_css(descendants_css, visible: :hidden, count: 3))
281
287
  end
282
288
  end
@@ -388,8 +394,8 @@ Capybara::SpecHelper.spec 'node' do
388
394
 
389
395
  describe '#==' do
390
396
  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
397
+ expect(@session.find('//h1') == @session.find('//h1')).to be true # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
398
+ expect(@session.find('//h1') === @session.find('//h1')).to be true # rubocop:disable Style/CaseEquality, Lint/BinaryOperatorWithIdenticalOperands
393
399
  expect(@session.find('//h1').eql?(@session.find('//h1'))).to be false
394
400
  end
395
401
 
@@ -409,6 +415,17 @@ Capybara::SpecHelper.spec 'node' do
409
415
  element = @session.find(:link, 'Second Link')
410
416
  expect(@session.find(:xpath, element.path)).to eq(element)
411
417
  end
418
+
419
+ it 'reports when element in shadow dom', requires: [:shadow_dom] do
420
+ @session.visit('/with_js')
421
+ shadow = @session.find(:css, '#shadow')
422
+ element = @session.evaluate_script(<<~JS, shadow)
423
+ (function(root){
424
+ return root.shadowRoot.querySelector('span');
425
+ })(arguments[0])
426
+ JS
427
+ expect(element.path).to eq '(: Shadow DOM element - no XPath :)'
428
+ end
412
429
  end
413
430
 
414
431
  describe '#trigger', requires: %i[js trigger] do
@@ -446,7 +463,7 @@ Capybara::SpecHelper.spec 'node' do
446
463
 
447
464
  it 'should work with Dragula' do
448
465
  @session.visit('/with_dragula')
449
- @session.within(:css, '#sortable') do
466
+ @session.within(:css, '#sortable.ready') do
450
467
  src = @session.find('div', text: 'Item 1')
451
468
  target = @session.find('div', text: 'Item 3')
452
469
  src.drag_to target
@@ -640,6 +657,16 @@ Capybara::SpecHelper.spec 'node' do
640
657
  expect(target).to have_text(%r{^HTML5 Dropped string: text/plain drag_html5-#{key}$}m, exact: true)
641
658
  end
642
659
  end
660
+
661
+ it 'should trigger a dragenter event, before the first dragover event' do
662
+ @session.visit('/with_js')
663
+ element = @session.find('//div[@id="drag_html5"]')
664
+ target = @session.find('//div[@id="drop_html5"]')
665
+ element.drag_to(target)
666
+
667
+ # Events are listed in reverse chronological order
668
+ expect(@session).to have_text(/DragOver.*DragEnter/m)
669
+ end
643
670
  end
644
671
  end
645
672
 
@@ -671,6 +698,15 @@ Capybara::SpecHelper.spec 'node' do
671
698
  expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
672
699
  end
673
700
 
701
+ it 'can drop a pathname' do
702
+ @session.visit('/with_js')
703
+ target = @session.find('//div[@id="drop_html5"]')
704
+ target.drop(
705
+ Pathname.new(with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))))
706
+ )
707
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
708
+ end
709
+
674
710
  it 'can drop multiple strings' do
675
711
  @session.visit('/with_js')
676
712
  target = @session.find('//div[@id="drop_html5"]')
@@ -755,10 +791,11 @@ Capybara::SpecHelper.spec 'node' do
755
791
  end
756
792
 
757
793
  it 'should allow to adjust the click offset', requires: [:js] do
794
+ Capybara.w3c_click_offset = false
758
795
  @session.visit('with_js')
759
796
  @session.find(:css, '#click-test').click(x: 5, y: 5)
760
797
  link = @session.find(:link, 'has-been-clicked')
761
- locations = link.text.match(/^Has been clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
798
+ locations = link.text.match(/^Has been clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
762
799
  # 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
800
  # integer/float conversions and rounding.
764
801
  expect(locations[:x].to_f).to be_within(1).of(5)
@@ -881,10 +918,11 @@ Capybara::SpecHelper.spec 'node' do
881
918
  end
882
919
 
883
920
  it 'should allow to adjust the offset', requires: [:js] do
921
+ Capybara.w3c_click_offset = false
884
922
  @session.visit('with_js')
885
923
  @session.find(:css, '#click-test').double_click(x: 10, y: 5)
886
924
  link = @session.find(:link, 'has-been-double-clicked')
887
- locations = link.text.match(/^Has been double clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
925
+ locations = link.text.match(/^Has been double clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
888
926
  # 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
927
  # to integer/float conversions and rounding.
890
928
  expect(locations[:x].to_f).to be_within(1).of(10)
@@ -967,10 +1005,11 @@ Capybara::SpecHelper.spec 'node' do
967
1005
  end
968
1006
 
969
1007
  it 'should allow to adjust the offset', requires: [:js] do
1008
+ Capybara.w3c_click_offset = false
970
1009
  @session.visit('with_js')
971
1010
  @session.find(:css, '#click-test').right_click(x: 10, y: 10)
972
1011
  link = @session.find(:link, 'has-been-right-clicked')
973
- locations = link.text.match(/^Has been right clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/)
1012
+ locations = link.text.match(/^Has been right clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
974
1013
  # 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
1014
  # to integer/float conversions and rounding
976
1015
  expect(locations[:x].to_f).to be_within(1).of(10)
@@ -1095,7 +1134,7 @@ Capybara::SpecHelper.spec 'node' do
1095
1134
  end
1096
1135
 
1097
1136
  describe '#evaluate_script', requires: %i[js es_args] do
1098
- it 'should evaluate the given script in the context of the element and return whatever it produces' do
1137
+ it 'should evaluate the given script in the context of the element and return whatever it produces' do
1099
1138
  @session.visit('/with_js')
1100
1139
  el = @session.find(:css, '#with_change_event')
1101
1140
  expect(el.evaluate_script('this.value')).to eq('default value')
@@ -1156,6 +1195,68 @@ Capybara::SpecHelper.spec 'node' do
1156
1195
  end
1157
1196
  end
1158
1197
 
1198
+ describe '#shadow_root', requires: %i[js] do
1199
+ it 'should get the shadow root' do
1200
+ @session.visit('/with_shadow')
1201
+ expect do
1202
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1203
+ expect(shadow_root).to be_a(Capybara::Node::Element)
1204
+ end.not_to raise_error
1205
+ end
1206
+
1207
+ it 'should find elements inside the shadow dom using CSS' do
1208
+ @session.visit('/with_shadow')
1209
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1210
+ expect(shadow_root).to have_css('#shadow_content', text: 'some text')
1211
+ end
1212
+
1213
+ it 'should find nested shadow roots' do
1214
+ @session.visit('/with_shadow')
1215
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1216
+ nested_shadow_root = shadow_root.find(:css, '#nested_shadow_host').shadow_root
1217
+ expect(nested_shadow_root).to have_css('#nested_shadow_content', text: 'nested text')
1218
+ end
1219
+
1220
+ it 'should click on elements' do
1221
+ @session.visit('/with_shadow')
1222
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1223
+ checkbox = shadow_root.find(:css, 'input[type="checkbox"]')
1224
+ expect(checkbox).not_to be_checked
1225
+ checkbox.click
1226
+ expect(checkbox).to be_checked
1227
+ end
1228
+
1229
+ it 'should use convenience methods once moved to a descendant of the shadow root' do
1230
+ @session.visit('/with_shadow')
1231
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1232
+ descendant = shadow_root.find(:css, '#controls_wrapper')
1233
+ expect do
1234
+ descendant.check('shadow_checkbox')
1235
+ end.not_to raise_error
1236
+ expect(descendant).to have_checked_field('shadow_checkbox')
1237
+ end
1238
+
1239
+ it 'should produce error messages when failing' do
1240
+ @session.visit('/with_shadow')
1241
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1242
+ expect do
1243
+ expect(shadow_root).to have_css('#shadow_content', text: 'Not in the document')
1244
+ end.to raise_error(/tag="ShadowRoot"/)
1245
+ end
1246
+
1247
+ it 'should get visible text' do
1248
+ @session.visit('/with_shadow')
1249
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1250
+ expect(shadow_root).to have_text('some text scroll.html')
1251
+ end
1252
+
1253
+ it 'should get all text' do
1254
+ @session.visit('/with_shadow')
1255
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1256
+ expect(shadow_root).to have_text(:all, 'some text scroll.html')
1257
+ end
1258
+ end
1259
+
1159
1260
  describe '#reload', requires: [:js] do
1160
1261
  it 'should reload elements found via ancestor with CSS' do
1161
1262
  @session.visit('/with_js')
@@ -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
 
@@ -25,6 +25,7 @@ Capybara::SpecHelper.spec '#refresh' do
25
25
  @session.visit('/form')
26
26
  @session.select('Sweden', from: 'form_region')
27
27
  @session.click_button('awesome')
28
+ sleep 2
28
29
  expect do
29
30
  @session.refresh
30
31
  sleep 2
@@ -95,6 +95,19 @@ Capybara::SpecHelper.spec '#reset_session!' do
95
95
  expect(@session.windows.size).to eq 1
96
96
  end
97
97
 
98
+ it 'does not block opening a new window after a frame was switched to and not switched back', requires: [:windows] do
99
+ @session.visit('/with_iframe?id=test_iframe&url=/')
100
+ @session.switch_to_frame(@session.find(:frame, 'test_iframe'))
101
+ within_window_test = lambda do
102
+ @session.within_window(@session.open_new_window) do
103
+ @session.visit('/')
104
+ end
105
+ end
106
+ expect(&within_window_test).to raise_error(Capybara::ScopeError)
107
+ @session.reset_session!
108
+ expect(&within_window_test).not_to raise_error
109
+ end
110
+
98
111
  context 'When reuse_server == false' do
99
112
  let!(:orig_reuse_server) { Capybara.reuse_server }
100
113
 
@@ -31,7 +31,7 @@ Capybara::SpecHelper.spec '#save_page' do
31
31
  it 'can store files in a specified directory' do
32
32
  Capybara.save_path = alternative_path
33
33
  @session.save_page
34
- path = Dir.glob(alternative_path + '/capybara-*.html').first
34
+ path = Dir.glob("#{alternative_path}/capybara-*.html").first
35
35
  expect(File.read(path)).to include('Another World')
36
36
  end
37
37
 
@@ -43,14 +43,14 @@ Capybara::SpecHelper.spec '#save_page' do
43
43
  it 'can store files in a specified directory with a given filename' do
44
44
  Capybara.save_path = alternative_path
45
45
  @session.save_page('capybara-001133.html')
46
- path = alternative_path + '/capybara-001133.html'
46
+ path = "#{alternative_path}/capybara-001133.html"
47
47
  expect(File.read(path)).to include('Another World')
48
48
  end
49
49
 
50
50
  it 'can store files in a specified directory with a given relative filename' do
51
51
  Capybara.save_path = alternative_path
52
52
  @session.save_page('tmp/capybara-001144.html')
53
- path = alternative_path + '/tmp/capybara-001144.html'
53
+ path = "#{alternative_path}/tmp/capybara-001144.html"
54
54
  expect(File.read(path)).to include('Another World')
55
55
  end
56
56
 
@@ -63,7 +63,7 @@ Capybara::SpecHelper.spec '#save_page' do
63
63
  it 'returns an absolute path in given directory' do
64
64
  Capybara.save_path = alternative_path
65
65
  result = @session.save_page
66
- path = File.expand_path(Dir.glob(alternative_path + '/capybara-*.html').first, alternative_path)
66
+ path = File.expand_path(Dir.glob("#{alternative_path}/capybara-*.html").first, alternative_path)
67
67
  expect(result).to eq(path)
68
68
  end
69
69
 
@@ -15,7 +15,7 @@ Capybara::SpecHelper.spec '#scroll_to', requires: [:scroll] do
15
15
  el = @session.find(:css, '#scroll')
16
16
  @session.scroll_to(el, align: :bottom)
17
17
  el_bottom = el.evaluate_script('this.getBoundingClientRect().bottom')
18
- viewport_bottom = el.evaluate_script('document.body.clientHeight')
18
+ viewport_bottom = el.evaluate_script('document.documentElement.clientHeight')
19
19
  expect(el_bottom).to be_within(1).of(viewport_bottom)
20
20
  end
21
21
 
@@ -23,7 +23,7 @@ Capybara::SpecHelper.spec '#scroll_to', requires: [:scroll] do
23
23
  el = @session.find(:css, '#scroll')
24
24
  @session.scroll_to(el, align: :center)
25
25
  el_center = el.evaluate_script('(function(rect){return (rect.top + rect.bottom)/2})(this.getBoundingClientRect())')
26
- viewport_bottom = el.evaluate_script('document.body.clientHeight')
26
+ viewport_bottom = el.evaluate_script('document.documentElement.clientHeight')
27
27
  expect(el_center).to be_within(2).of(viewport_bottom / 2)
28
28
  end
29
29
 
@@ -35,13 +35,15 @@ Capybara::SpecHelper.spec '#scroll_to', requires: [:scroll] do
35
35
 
36
36
  it 'can scroll the window to the vertical bottom' do
37
37
  @session.scroll_to :bottom
38
- max_scroll = @session.evaluate_script('document.body.scrollHeight - document.body.clientHeight')
39
- expect(@session.evaluate_script('[window.scrollX || window.pageXOffset, window.scrollY || window.pageYOffset]')).to eq [0, max_scroll]
38
+ max_scroll = @session.evaluate_script('document.documentElement.scrollHeight - document.documentElement.clientHeight')
39
+ scrolled_location_x, scrolled_location_y = @session.evaluate_script('[window.scrollX || window.pageXOffset, window.scrollY || window.pageYOffset]')
40
+ expect(scrolled_location_x).to be_within(0.5).of(0)
41
+ expect(scrolled_location_y).to be_within(0.5).of(max_scroll)
40
42
  end
41
43
 
42
44
  it 'can scroll the window to the vertical center' do
43
45
  @session.scroll_to :center
44
- max_scroll = @session.evaluate_script('document.documentElement.scrollHeight - document.body.clientHeight')
46
+ max_scroll = @session.evaluate_script('document.documentElement.scrollHeight - document.documentElement.clientHeight')
45
47
  expect(@session.evaluate_script('[window.scrollX || window.pageXOffset, window.scrollY || window.pageYOffset]')).to eq [0, max_scroll / 2]
46
48
  end
47
49