capybara 3.13.2 → 3.40.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 (260) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +587 -16
  4. data/README.md +240 -90
  5. data/lib/capybara/config.rb +24 -11
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/driver/base.rb +8 -0
  8. data/lib/capybara/driver/node.rb +20 -4
  9. data/lib/capybara/dsl.rb +5 -3
  10. data/lib/capybara/helpers.rb +25 -4
  11. data/lib/capybara/minitest/spec.rb +174 -90
  12. data/lib/capybara/minitest.rb +256 -142
  13. data/lib/capybara/node/actions.rb +123 -77
  14. data/lib/capybara/node/base.rb +20 -12
  15. data/lib/capybara/node/document.rb +2 -2
  16. data/lib/capybara/node/document_matchers.rb +3 -3
  17. data/lib/capybara/node/element.rb +223 -117
  18. data/lib/capybara/node/finders.rb +81 -71
  19. data/lib/capybara/node/matchers.rb +271 -134
  20. data/lib/capybara/node/simple.rb +18 -5
  21. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  22. data/lib/capybara/queries/active_element_query.rb +18 -0
  23. data/lib/capybara/queries/ancestor_query.rb +8 -9
  24. data/lib/capybara/queries/base_query.rb +3 -2
  25. data/lib/capybara/queries/current_path_query.rb +15 -5
  26. data/lib/capybara/queries/selector_query.rb +364 -54
  27. data/lib/capybara/queries/sibling_query.rb +8 -6
  28. data/lib/capybara/queries/style_query.rb +2 -2
  29. data/lib/capybara/queries/text_query.rb +13 -1
  30. data/lib/capybara/queries/title_query.rb +1 -1
  31. data/lib/capybara/rack_test/browser.rb +76 -11
  32. data/lib/capybara/rack_test/driver.rb +10 -5
  33. data/lib/capybara/rack_test/errors.rb +6 -0
  34. data/lib/capybara/rack_test/form.rb +31 -9
  35. data/lib/capybara/rack_test/node.rb +74 -23
  36. data/lib/capybara/registration_container.rb +41 -0
  37. data/lib/capybara/registrations/drivers.rb +42 -0
  38. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  39. data/lib/capybara/registrations/servers.rb +66 -0
  40. data/lib/capybara/result.rb +44 -20
  41. data/lib/capybara/rspec/matcher_proxies.rb +13 -11
  42. data/lib/capybara/rspec/matchers/base.rb +31 -16
  43. data/lib/capybara/rspec/matchers/compound.rb +1 -1
  44. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  45. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  46. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  47. data/lib/capybara/rspec/matchers/have_selector.rb +21 -21
  48. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  49. data/lib/capybara/rspec/matchers/have_text.rb +4 -4
  50. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  51. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  52. data/lib/capybara/rspec/matchers/match_style.rb +7 -2
  53. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  54. data/lib/capybara/rspec/matchers.rb +111 -68
  55. data/lib/capybara/rspec.rb +2 -0
  56. data/lib/capybara/selector/builders/css_builder.rb +11 -7
  57. data/lib/capybara/selector/builders/xpath_builder.rb +5 -3
  58. data/lib/capybara/selector/css.rb +11 -9
  59. data/lib/capybara/selector/definition/button.rb +68 -0
  60. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  61. data/lib/capybara/selector/definition/css.rb +10 -0
  62. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  63. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  64. data/lib/capybara/selector/definition/element.rb +28 -0
  65. data/lib/capybara/selector/definition/field.rb +40 -0
  66. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  67. data/lib/capybara/selector/definition/file_field.rb +13 -0
  68. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  69. data/lib/capybara/selector/definition/frame.rb +17 -0
  70. data/lib/capybara/selector/definition/id.rb +6 -0
  71. data/lib/capybara/selector/definition/label.rb +62 -0
  72. data/lib/capybara/selector/definition/link.rb +55 -0
  73. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  74. data/lib/capybara/selector/definition/option.rb +27 -0
  75. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  76. data/lib/capybara/selector/definition/select.rb +81 -0
  77. data/lib/capybara/selector/definition/table.rb +109 -0
  78. data/lib/capybara/selector/definition/table_row.rb +21 -0
  79. data/lib/capybara/selector/definition/xpath.rb +5 -0
  80. data/lib/capybara/selector/definition.rb +280 -0
  81. data/lib/capybara/selector/filter_set.rb +19 -18
  82. data/lib/capybara/selector/filters/base.rb +11 -2
  83. data/lib/capybara/selector/filters/locator_filter.rb +13 -3
  84. data/lib/capybara/selector/regexp_disassembler.rb +11 -7
  85. data/lib/capybara/selector/selector.rb +50 -440
  86. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  87. data/lib/capybara/selector.rb +473 -482
  88. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  89. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  90. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  91. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  92. data/lib/capybara/selenium/driver.rb +174 -62
  93. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +74 -18
  94. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  95. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +37 -3
  96. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +14 -1
  97. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  98. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  99. data/lib/capybara/selenium/extensions/find.rb +68 -45
  100. data/lib/capybara/selenium/extensions/html5_drag.rb +192 -22
  101. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  102. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  103. data/lib/capybara/selenium/node.rb +268 -72
  104. data/lib/capybara/selenium/nodes/chrome_node.rb +105 -9
  105. data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
  106. data/lib/capybara/selenium/nodes/firefox_node.rb +51 -61
  107. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  108. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  109. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  110. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  111. data/lib/capybara/selenium/patches/logs.rb +45 -0
  112. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -1
  113. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  114. data/lib/capybara/server/animation_disabler.rb +43 -21
  115. data/lib/capybara/server/checker.rb +6 -2
  116. data/lib/capybara/server/middleware.rb +25 -13
  117. data/lib/capybara/server.rb +20 -4
  118. data/lib/capybara/session/config.rb +15 -11
  119. data/lib/capybara/session/matchers.rb +11 -11
  120. data/lib/capybara/session.rb +162 -131
  121. data/lib/capybara/spec/public/offset.js +6 -0
  122. data/lib/capybara/spec/public/test.js +105 -6
  123. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  124. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  125. data/lib/capybara/spec/session/all_spec.rb +89 -15
  126. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  127. data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
  128. data/lib/capybara/spec/session/assert_text_spec.rb +26 -22
  129. data/lib/capybara/spec/session/attach_file_spec.rb +64 -31
  130. data/lib/capybara/spec/session/check_spec.rb +26 -4
  131. data/lib/capybara/spec/session/choose_spec.rb +14 -2
  132. data/lib/capybara/spec/session/click_button_spec.rb +109 -61
  133. data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
  134. data/lib/capybara/spec/session/click_link_spec.rb +23 -1
  135. data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
  136. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  137. data/lib/capybara/spec/session/element/matches_selector_spec.rb +40 -39
  138. data/lib/capybara/spec/session/evaluate_script_spec.rb +12 -0
  139. data/lib/capybara/spec/session/fill_in_spec.rb +46 -5
  140. data/lib/capybara/spec/session/find_link_spec.rb +10 -0
  141. data/lib/capybara/spec/session/find_spec.rb +80 -7
  142. data/lib/capybara/spec/session/first_spec.rb +2 -2
  143. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +14 -1
  144. data/lib/capybara/spec/session/frame/within_frame_spec.rb +14 -1
  145. data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
  146. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  147. data/lib/capybara/spec/session/has_any_selectors_spec.rb +6 -2
  148. data/lib/capybara/spec/session/has_button_spec.rb +81 -0
  149. data/lib/capybara/spec/session/has_css_spec.rb +45 -8
  150. data/lib/capybara/spec/session/has_current_path_spec.rb +22 -7
  151. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  152. data/lib/capybara/spec/session/has_field_spec.rb +59 -1
  153. data/lib/capybara/spec/session/has_link_spec.rb +40 -0
  154. data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
  155. data/lib/capybara/spec/session/has_select_spec.rb +42 -8
  156. data/lib/capybara/spec/session/has_selector_spec.rb +19 -4
  157. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  158. data/lib/capybara/spec/session/has_table_spec.rb +177 -0
  159. data/lib/capybara/spec/session/has_text_spec.rb +31 -3
  160. data/lib/capybara/spec/session/html_spec.rb +1 -1
  161. data/lib/capybara/spec/session/matches_style_spec.rb +6 -4
  162. data/lib/capybara/spec/session/node_spec.rb +697 -23
  163. data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
  164. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  165. data/lib/capybara/spec/session/reset_session_spec.rb +21 -7
  166. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  167. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  168. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  169. data/lib/capybara/spec/session/scroll_spec.rb +9 -7
  170. data/lib/capybara/spec/session/select_spec.rb +5 -10
  171. data/lib/capybara/spec/session/selectors_spec.rb +24 -3
  172. data/lib/capybara/spec/session/uncheck_spec.rb +3 -3
  173. data/lib/capybara/spec/session/unselect_spec.rb +1 -1
  174. data/lib/capybara/spec/session/visit_spec.rb +20 -0
  175. data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
  176. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  177. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  178. data/lib/capybara/spec/session/window/window_spec.rb +54 -57
  179. data/lib/capybara/spec/session/window/windows_spec.rb +2 -2
  180. data/lib/capybara/spec/session/within_spec.rb +36 -0
  181. data/lib/capybara/spec/spec_helper.rb +30 -19
  182. data/lib/capybara/spec/test_app.rb +122 -34
  183. data/lib/capybara/spec/views/animated.erb +49 -0
  184. data/lib/capybara/spec/views/form.erb +86 -8
  185. data/lib/capybara/spec/views/frame_child.erb +3 -2
  186. data/lib/capybara/spec/views/frame_one.erb +2 -1
  187. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  188. data/lib/capybara/spec/views/frame_two.erb +1 -1
  189. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  190. data/lib/capybara/spec/views/layout.erb +10 -0
  191. data/lib/capybara/spec/views/obscured.erb +10 -10
  192. data/lib/capybara/spec/views/offset.erb +33 -0
  193. data/lib/capybara/spec/views/path.erb +2 -2
  194. data/lib/capybara/spec/views/popup_one.erb +1 -1
  195. data/lib/capybara/spec/views/popup_two.erb +1 -1
  196. data/lib/capybara/spec/views/react.erb +45 -0
  197. data/lib/capybara/spec/views/scroll.erb +2 -1
  198. data/lib/capybara/spec/views/spatial.erb +31 -0
  199. data/lib/capybara/spec/views/tables.erb +67 -0
  200. data/lib/capybara/spec/views/with_animation.erb +39 -4
  201. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  202. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  203. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  204. data/lib/capybara/spec/views/with_hover.erb +3 -2
  205. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  206. data/lib/capybara/spec/views/with_html.erb +34 -6
  207. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  208. data/lib/capybara/spec/views/with_js.erb +7 -4
  209. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  210. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  211. data/lib/capybara/spec/views/with_scope.erb +2 -2
  212. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  213. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  214. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  215. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  216. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  217. data/lib/capybara/spec/views/with_windows.erb +1 -1
  218. data/lib/capybara/spec/views/within_frames.erb +1 -1
  219. data/lib/capybara/version.rb +1 -1
  220. data/lib/capybara/window.rb +14 -18
  221. data/lib/capybara.rb +91 -126
  222. data/spec/basic_node_spec.rb +30 -16
  223. data/spec/capybara_spec.rb +40 -28
  224. data/spec/counter_spec.rb +35 -0
  225. data/spec/css_builder_spec.rb +3 -1
  226. data/spec/css_splitter_spec.rb +1 -1
  227. data/spec/dsl_spec.rb +33 -22
  228. data/spec/filter_set_spec.rb +5 -5
  229. data/spec/fixtures/selenium_driver_rspec_failure.rb +3 -3
  230. data/spec/fixtures/selenium_driver_rspec_success.rb +3 -3
  231. data/spec/minitest_spec.rb +24 -2
  232. data/spec/minitest_spec_spec.rb +60 -45
  233. data/spec/per_session_config_spec.rb +1 -1
  234. data/spec/rack_test_spec.rb +131 -98
  235. data/spec/regexp_dissassembler_spec.rb +53 -39
  236. data/spec/result_spec.rb +68 -66
  237. data/spec/rspec/features_spec.rb +9 -4
  238. data/spec/rspec/scenarios_spec.rb +6 -2
  239. data/spec/rspec/shared_spec_matchers.rb +137 -98
  240. data/spec/rspec_matchers_spec.rb +25 -0
  241. data/spec/rspec_spec.rb +23 -21
  242. data/spec/sauce_spec_chrome.rb +43 -0
  243. data/spec/selector_spec.rb +77 -21
  244. data/spec/selenium_spec_chrome.rb +141 -39
  245. data/spec/selenium_spec_chrome_remote.rb +32 -17
  246. data/spec/selenium_spec_edge.rb +36 -8
  247. data/spec/selenium_spec_firefox.rb +110 -68
  248. data/spec/selenium_spec_firefox_remote.rb +22 -15
  249. data/spec/selenium_spec_ie.rb +29 -22
  250. data/spec/selenium_spec_safari.rb +162 -0
  251. data/spec/server_spec.rb +153 -81
  252. data/spec/session_spec.rb +11 -4
  253. data/spec/shared_selenium_node.rb +79 -0
  254. data/spec/shared_selenium_session.rb +179 -74
  255. data/spec/spec_helper.rb +80 -5
  256. data/spec/whitespace_normalizer_spec.rb +54 -0
  257. data/spec/xpath_builder_spec.rb +3 -1
  258. metadata +218 -30
  259. data/lib/capybara/spec/session/source_spec.rb +0 -0
  260. data/lib/capybara/spec/views/with_title.erb +0 -5
@@ -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,35 @@ 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
+ end
118
+ end
119
+
120
+ context 'with enabled options' do
121
+ it 'should be true if the listed options exist and are enabled' do
122
+ expect(@session).to have_select('form_title', enabled_options: %w[Mr Mrs Miss])
123
+ end
124
+
125
+ it 'should be false if the listed options do not exist' do
126
+ expect(@session).not_to have_select('form_title', enabled_options: ['Not there'])
127
+ end
128
+
129
+ it 'should be false if the listed option exists but is not enabled' do
130
+ expect(@session).not_to have_select('form_title', enabled_options: %w[Mr Mrs Miss Other])
131
+ end
132
+ end
133
+
134
+ context 'with disabled options' do
135
+ it 'should be true if the listed options exist and are disabled' do
136
+ expect(@session).to have_select('form_title', disabled_options: ['Other'])
137
+ end
138
+
139
+ it 'should be false if the listed options do not exist' do
140
+ expect(@session).not_to have_select('form_title', disabled_options: ['Not there'])
141
+ end
142
+
143
+ it 'should be false if the listed option exists but is not disabled' do
144
+ expect(@session).not_to have_select('form_title', disabled_options: %w[Other Mrs])
117
145
  end
118
146
  end
119
147
 
@@ -130,7 +158,7 @@ Capybara::SpecHelper.spec '#has_select?' do
130
158
  end
131
159
 
132
160
  it 'should be true even when the options are invisible, if the select itself is invisible' do
133
- 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])
134
162
  end
135
163
  end
136
164
 
@@ -151,10 +179,16 @@ Capybara::SpecHelper.spec '#has_select?' do
151
179
  end
152
180
  end
153
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
+
154
188
  it 'should support locator-less usage' do
155
- 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
156
190
  expect(@session).to have_select(with_options: ['London'])
157
- 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
158
192
  expect(@session).to have_select(with_selected: ['Briefs'])
159
193
  end
160
194
  end
@@ -274,9 +308,9 @@ Capybara::SpecHelper.spec '#has_no_select?' do
274
308
  end
275
309
 
276
310
  it 'should support locator-less usage' do
277
- 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
278
312
  expect(@session).to have_no_select(with_options: ['New London'])
279
- 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
280
314
  expect(@session).to have_no_select(id: 'form_underwear', with_selected: %w[Commando Boxers])
281
315
  end
282
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
 
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ Capybara::SpecHelper.spec '#have_sibling' do
4
+ before do
5
+ @session.visit('/with_html')
6
+ end
7
+
8
+ it 'should assert a prior sibling element using the given locator' do
9
+ el = @session.find(:css, '#mid_sibling')
10
+ expect(el).to have_sibling(:css, '#pre_sibling')
11
+ end
12
+
13
+ it 'should assert a following sibling element using the given locator' do
14
+ el = @session.find(:css, '#mid_sibling')
15
+ expect(el).to have_sibling(:css, '#post_sibling')
16
+ end
17
+
18
+ it 'should not raise an error if there are multiple matches' do
19
+ el = @session.find(:css, '#mid_sibling')
20
+ expect(el).to have_sibling(:css, 'div')
21
+ end
22
+
23
+ it 'should allow counts to be specified' do
24
+ el = @session.find(:css, '#mid_sibling')
25
+
26
+ expect(el).to have_sibling(:css, 'div').exactly(2).times
27
+ expect do
28
+ expect(el).to have_sibling(:css, 'div').once
29
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError)
30
+ end
31
+ end
32
+
33
+ Capybara::SpecHelper.spec '#have_no_sibling' do
34
+ before do
35
+ @session.visit('/with_html')
36
+ end
37
+
38
+ it 'should assert no matching sibling' do
39
+ el = @session.find(:css, '#mid_sibling')
40
+ expect(el).to have_no_sibling(:css, '#not_a_sibling')
41
+ expect(el).not_to have_sibling(:css, '#not_a_sibling')
42
+ end
43
+
44
+ it 'should raise if there are matching siblings' do
45
+ el = @session.find(:css, '#mid_sibling')
46
+ expect do
47
+ expect(el).to have_no_sibling(:css, '#pre_sibling')
48
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError)
49
+ end
50
+ end
@@ -11,9 +11,126 @@ Capybara::SpecHelper.spec '#has_table?' do
11
11
  expect(@session).to have_table(:villain_table)
12
12
  end
13
13
 
14
+ it 'should accept rows with column header hashes' do
15
+ expect(@session).to have_table('Horizontal Headers', with_rows:
16
+ [
17
+ { 'First Name' => 'Vern', 'Last Name' => 'Konopelski', 'City' => 'Everette' },
18
+ { 'First Name' => 'Palmer', 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
19
+ ])
20
+ end
21
+
22
+ it 'should accept rows with partial column header hashes' do
23
+ expect(@session).to have_table('Horizontal Headers', with_rows:
24
+ [
25
+ { 'First Name' => 'Thomas' },
26
+ { 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
27
+ ])
28
+
29
+ expect(@session).not_to have_table('Horizontal Headers', with_rows:
30
+ [
31
+ { 'Unmatched Header' => 'Thomas' }
32
+ ])
33
+ end
34
+
35
+ it 'should accept rows with array of cell values' do
36
+ expect(@session).to have_table('Horizontal Headers', with_rows:
37
+ [
38
+ %w[Thomas Walpole Oceanside],
39
+ ['Ratke', 'Lawrence', 'East Sorayashire']
40
+ ])
41
+ end
42
+
43
+ it 'should consider order of cells in each row' do
44
+ expect(@session).not_to have_table('Horizontal Headers', with_rows:
45
+ [
46
+ %w[Thomas Walpole Oceanside],
47
+ ['Lawrence', 'Ratke', 'East Sorayashire']
48
+ ])
49
+ end
50
+
51
+ it 'should accept all rows with array of cell values' do
52
+ expect(@session).to have_table('Horizontal Headers', rows:
53
+ [
54
+ %w[Thomas Walpole Oceanside],
55
+ %w[Danilo Wilkinson Johnsonville],
56
+ %w[Vern Konopelski Everette],
57
+ ['Ratke', 'Lawrence', 'East Sorayashire'],
58
+ ['Palmer', 'Sawayn', 'West Trinidad']
59
+ ])
60
+ end
61
+
62
+ it 'should match with vertical headers' do
63
+ expect(@session).to have_table('Vertical Headers', with_cols:
64
+ [
65
+ { 'First Name' => 'Thomas' },
66
+ { 'First Name' => 'Danilo', 'Last Name' => 'Wilkinson', 'City' => 'Johnsonville' },
67
+ { 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
68
+ ])
69
+ end
70
+
71
+ it 'should match col with array of cell values' do
72
+ expect(@session).to have_table('Vertical Headers', with_cols:
73
+ [
74
+ %w[Vern Konopelski Everette]
75
+ ])
76
+ end
77
+
78
+ it 'should match cols with array of cell values' do
79
+ expect(@session).to have_table('Vertical Headers', with_cols:
80
+ [
81
+ %w[Danilo Wilkinson Johnsonville],
82
+ %w[Vern Konopelski Everette]
83
+ ])
84
+ end
85
+
86
+ it 'should match all cols with array of cell values' do
87
+ expect(@session).to have_table('Vertical Headers', cols:
88
+ [
89
+ %w[Thomas Walpole Oceanside],
90
+ %w[Danilo Wilkinson Johnsonville],
91
+ %w[Vern Konopelski Everette],
92
+ ['Ratke', 'Lawrence', 'East Sorayashire'],
93
+ ['Palmer', 'Sawayn', 'West Trinidad']
94
+ ])
95
+ end
96
+
97
+ it "should not match if the order of cell values doesn't match" do
98
+ expect(@session).not_to have_table('Vertical Headers', with_cols:
99
+ [
100
+ %w[Vern Everette Konopelski]
101
+ ])
102
+ end
103
+
104
+ it "should not match with vertical headers if the columns don't match" do
105
+ expect(@session).not_to have_table('Vertical Headers', with_cols:
106
+ [
107
+ { 'First Name' => 'Thomas' },
108
+ { 'First Name' => 'Danilo', 'Last Name' => 'Walpole', 'City' => 'Johnsonville' },
109
+ { 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
110
+ ])
111
+
112
+ expect(@session).not_to have_table('Vertical Headers', with_cols:
113
+ [
114
+ { 'Unmatched Header' => 'Thomas' }
115
+ ])
116
+ end
117
+
14
118
  it 'should be false if the table is not on the page' do
15
119
  expect(@session).not_to have_table('Monkey')
16
120
  end
121
+
122
+ it 'should find row by header and cell values' do
123
+ expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, 'First Name' => 'Thomas', 'Last Name' => 'Walpole')
124
+ expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, 'Last Name' => 'Walpole')
125
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, 'First Name' => 'Walpole')
126
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, 'Unmatched Header' => 'Thomas')
127
+ end
128
+
129
+ it 'should find row by cell values' do
130
+ expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, %w[Thomas Walpole Oceanside])
131
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, %w[Walpole Thomas])
132
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, %w[Other])
133
+ end
17
134
  end
18
135
 
19
136
  Capybara::SpecHelper.spec '#has_no_table?' do
@@ -29,4 +146,64 @@ Capybara::SpecHelper.spec '#has_no_table?' do
29
146
  it 'should be true if the table is not on the page' do
30
147
  expect(@session).to have_no_table('Monkey')
31
148
  end
149
+
150
+ it 'should consider rows' do
151
+ expect(@session).to have_no_table('Horizontal Headers', with_rows:
152
+ [
153
+ { 'First Name' => 'Thomas', 'City' => 'Los Angeles' }
154
+ ])
155
+ end
156
+
157
+ context 'using :with_cols' do
158
+ it 'should consider a single column' do
159
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
160
+ [
161
+ { 'First Name' => 'Joe' }
162
+ ])
163
+ end
164
+
165
+ it 'should be true even if the last column does exist' do
166
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
167
+ [
168
+ {
169
+ 'First Name' => 'What?',
170
+ 'What?' => 'Walpole',
171
+ 'City' => 'Oceanside' # This line makes the example fail
172
+ }
173
+ ])
174
+ end
175
+
176
+ it 'should be true if none of the columns exist' do
177
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
178
+ [
179
+ {
180
+ 'First Name' => 'What?',
181
+ 'What?' => 'Walpole',
182
+ 'City' => 'What?'
183
+ }
184
+ ])
185
+ end
186
+
187
+ it 'should be true if the first column does match' do
188
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
189
+ [
190
+ {
191
+ 'First Name' => 'Thomas',
192
+ 'Last Name' => 'What',
193
+ 'City' => 'What'
194
+ }
195
+ ])
196
+ end
197
+
198
+ it 'should be true if none of the columns match' do
199
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
200
+ [
201
+ {
202
+ 'First Name' => 'What',
203
+ 'Last Name' => 'What',
204
+ 'City' => 'What'
205
+ }
206
+ ])
207
+ end
208
+ end
32
209
  end
@@ -111,6 +111,26 @@ Capybara::SpecHelper.spec '#has_text?' do
111
111
  expect(@session).not_to have_text(/xxxxyzzz/)
112
112
  end
113
113
 
114
+ context 'with object implementing to_s and to_hash' do
115
+ it 'should work if the object is passed alone' do
116
+ with_to_hash = Class.new do
117
+ def to_s; '42' end
118
+ def to_hash; { value: 'Other hash' } end
119
+ end.new
120
+ @session.visit('/with_html')
121
+ expect(@session).to have_text(with_to_hash)
122
+ end
123
+
124
+ it 'should work if passed with empty options' do
125
+ with_to_hash = Class.new do
126
+ def to_s; '42' end
127
+ def to_hash; { value: 'Other hash' } end
128
+ end.new
129
+ @session.visit('/with_html')
130
+ expect(@session).to have_text(:visible, with_to_hash, **{})
131
+ end
132
+ end
133
+
114
134
  context 'with exact: true option' do
115
135
  it 'should be true if text matches exactly' do
116
136
  @session.visit('/with_html')
@@ -133,10 +153,12 @@ Capybara::SpecHelper.spec '#has_text?' do
133
153
  expect(@session).to have_text(42)
134
154
  end
135
155
 
136
- it 'should be true when passed nil' do
156
+ it 'should be true when passed nil, and warn about it' do
137
157
  # nil is converted to '' when to_s is invoked
138
158
  @session.visit('/with_html')
139
- 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
140
162
  end
141
163
 
142
164
  it 'should wait for text to appear', requires: [:js] do
@@ -166,12 +188,14 @@ Capybara::SpecHelper.spec '#has_text?' do
166
188
  it 'should be true if the text occurs the given number of times' do
167
189
  @session.visit('/with_count')
168
190
  expect(@session).to have_text('count', count: 2)
191
+ expect(@session).to have_text('count').exactly(2).times
169
192
  end
170
193
 
171
194
  it 'should be false if the text occurs a different number of times than the given' do
172
195
  @session.visit('/with_count')
173
196
  expect(@session).not_to have_text('count', count: 0)
174
197
  expect(@session).not_to have_text('count', count: 1)
198
+ expect(@session).not_to have_text('count').once
175
199
  expect(@session).not_to have_text(/count/, count: 3)
176
200
  end
177
201
 
@@ -186,12 +210,14 @@ Capybara::SpecHelper.spec '#has_text?' do
186
210
  it 'should be true when text occurs same or fewer times than given' do
187
211
  @session.visit('/with_count')
188
212
  expect(@session).to have_text('count', maximum: 2)
213
+ expect(@session).to have_text('count').at_most(2).times
189
214
  expect(@session).to have_text(/count/, maximum: 3)
190
215
  end
191
216
 
192
217
  it 'should be false when text occurs more times than given' do
193
218
  @session.visit('/with_count')
194
219
  expect(@session).not_to have_text('count', maximum: 1)
220
+ expect(@session).not_to have_text('count').at_most(1).times
195
221
  expect(@session).not_to have_text('count', maximum: 0)
196
222
  end
197
223
 
@@ -206,12 +232,14 @@ Capybara::SpecHelper.spec '#has_text?' do
206
232
  it 'should be true when text occurs same or more times than given' do
207
233
  @session.visit('/with_count')
208
234
  expect(@session).to have_text('count', minimum: 2)
235
+ expect(@session).to have_text('count').at_least(2).times
209
236
  expect(@session).to have_text(/count/, minimum: 0)
210
237
  end
211
238
 
212
239
  it 'should be false when text occurs fewer times than given' do
213
240
  @session.visit('/with_count')
214
241
  expect(@session).not_to have_text('count', minimum: 3)
242
+ expect(@session).not_to have_text('count').at_least(3).times
215
243
  end
216
244
 
217
245
  it 'should coerce minimum to an integer' do
@@ -320,7 +348,7 @@ Capybara::SpecHelper.spec '#has_no_text?' do
320
348
  expect(@session).to have_no_text(/xxxxyzzz/)
321
349
  end
322
350
 
323
- 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
324
352
  @session.visit('/with_html')
325
353
  expect(@session).not_to have_no_text(/Lorem/)
326
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
- expect_any_instance_of(Kernel).to receive(:warn).once
28
- have_style(display: /^bl/)
28
+ expect { have_style(display: /^bl/) }.to \
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