capybara 3.0.0 → 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 (312) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +891 -12
  4. data/License.txt +1 -1
  5. data/README.md +257 -84
  6. data/lib/capybara/config.rb +29 -10
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/base.rb +22 -4
  9. data/lib/capybara/driver/node.rb +38 -9
  10. data/lib/capybara/dsl.rb +9 -7
  11. data/lib/capybara/helpers.rb +57 -8
  12. data/lib/capybara/minitest/spec.rb +185 -84
  13. data/lib/capybara/minitest.rb +264 -145
  14. data/lib/capybara/node/actions.rb +248 -124
  15. data/lib/capybara/node/base.rb +35 -20
  16. data/lib/capybara/node/document.rb +14 -2
  17. data/lib/capybara/node/document_matchers.rb +13 -15
  18. data/lib/capybara/node/element.rb +350 -113
  19. data/lib/capybara/node/finders.rb +104 -82
  20. data/lib/capybara/node/matchers.rb +363 -157
  21. data/lib/capybara/node/simple.rb +54 -15
  22. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  23. data/lib/capybara/queries/active_element_query.rb +18 -0
  24. data/lib/capybara/queries/ancestor_query.rb +9 -10
  25. data/lib/capybara/queries/base_query.rb +25 -18
  26. data/lib/capybara/queries/current_path_query.rb +16 -6
  27. data/lib/capybara/queries/match_query.rb +11 -0
  28. data/lib/capybara/queries/selector_query.rb +617 -104
  29. data/lib/capybara/queries/sibling_query.rb +9 -7
  30. data/lib/capybara/queries/style_query.rb +45 -0
  31. data/lib/capybara/queries/text_query.rb +40 -22
  32. data/lib/capybara/queries/title_query.rb +2 -2
  33. data/lib/capybara/rack_test/browser.rb +106 -31
  34. data/lib/capybara/rack_test/driver.rb +16 -7
  35. data/lib/capybara/rack_test/errors.rb +6 -0
  36. data/lib/capybara/rack_test/form.rb +74 -49
  37. data/lib/capybara/rack_test/node.rb +120 -47
  38. data/lib/capybara/rails.rb +1 -1
  39. data/lib/capybara/registration_container.rb +41 -0
  40. data/lib/capybara/registrations/drivers.rb +42 -0
  41. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  42. data/lib/capybara/registrations/servers.rb +66 -0
  43. data/lib/capybara/result.rb +87 -53
  44. data/lib/capybara/rspec/features.rb +8 -10
  45. data/lib/capybara/rspec/matcher_proxies.rb +39 -18
  46. data/lib/capybara/rspec/matchers/base.rb +113 -0
  47. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  48. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  49. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  50. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  51. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  52. data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
  53. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  54. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  55. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  56. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  57. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  58. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  59. data/lib/capybara/rspec/matchers.rb +142 -315
  60. data/lib/capybara/rspec.rb +3 -2
  61. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  62. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  63. data/lib/capybara/selector/css.rb +85 -8
  64. data/lib/capybara/selector/definition/button.rb +68 -0
  65. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  66. data/lib/capybara/selector/definition/css.rb +10 -0
  67. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  68. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  69. data/lib/capybara/selector/definition/element.rb +28 -0
  70. data/lib/capybara/selector/definition/field.rb +40 -0
  71. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  72. data/lib/capybara/selector/definition/file_field.rb +13 -0
  73. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  74. data/lib/capybara/selector/definition/frame.rb +17 -0
  75. data/lib/capybara/selector/definition/id.rb +6 -0
  76. data/lib/capybara/selector/definition/label.rb +62 -0
  77. data/lib/capybara/selector/definition/link.rb +55 -0
  78. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  79. data/lib/capybara/selector/definition/option.rb +27 -0
  80. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  81. data/lib/capybara/selector/definition/select.rb +81 -0
  82. data/lib/capybara/selector/definition/table.rb +109 -0
  83. data/lib/capybara/selector/definition/table_row.rb +21 -0
  84. data/lib/capybara/selector/definition/xpath.rb +5 -0
  85. data/lib/capybara/selector/definition.rb +280 -0
  86. data/lib/capybara/selector/filter.rb +1 -0
  87. data/lib/capybara/selector/filter_set.rb +72 -28
  88. data/lib/capybara/selector/filters/base.rb +45 -2
  89. data/lib/capybara/selector/filters/expression_filter.rb +5 -6
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +18 -4
  92. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  93. data/lib/capybara/selector/selector.rb +89 -200
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/lib/capybara/selector.rb +474 -534
  96. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  97. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  98. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  99. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  100. data/lib/capybara/selenium/driver.rb +270 -245
  101. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  102. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  103. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
  104. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  105. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  106. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  107. data/lib/capybara/selenium/extensions/find.rb +110 -0
  108. data/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
  109. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  110. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  111. data/lib/capybara/selenium/node.rb +460 -170
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
  114. data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  115. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  116. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  117. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  118. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  119. data/lib/capybara/selenium/patches/logs.rb +45 -0
  120. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  121. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  122. data/lib/capybara/server/animation_disabler.rb +80 -0
  123. data/lib/capybara/server/checker.rb +44 -0
  124. data/lib/capybara/server/middleware.rb +71 -0
  125. data/lib/capybara/server.rb +58 -67
  126. data/lib/capybara/session/config.rb +40 -6
  127. data/lib/capybara/session/matchers.rb +26 -19
  128. data/lib/capybara/session.rb +252 -194
  129. data/lib/capybara/spec/public/jquery.js +5 -5
  130. data/lib/capybara/spec/public/offset.js +6 -0
  131. data/lib/capybara/spec/public/test.js +126 -8
  132. data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
  133. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
  134. data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
  135. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  136. data/lib/capybara/spec/session/all_spec.rb +135 -44
  137. data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
  138. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
  139. data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +20 -18
  140. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  141. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  142. data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +76 -52
  143. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +12 -12
  144. data/lib/capybara/spec/session/attach_file_spec.rb +126 -72
  145. data/lib/capybara/spec/session/body_spec.rb +11 -13
  146. data/lib/capybara/spec/session/check_spec.rb +112 -51
  147. data/lib/capybara/spec/session/choose_spec.rb +62 -30
  148. data/lib/capybara/spec/session/click_button_spec.rb +227 -161
  149. data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -30
  150. data/lib/capybara/spec/session/click_link_spec.rb +89 -55
  151. data/lib/capybara/spec/session/current_scope_spec.rb +8 -8
  152. data/lib/capybara/spec/session/current_url_spec.rb +44 -37
  153. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
  154. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
  155. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
  156. data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
  157. data/lib/capybara/spec/session/element/match_xpath_spec.rb +8 -6
  158. data/lib/capybara/spec/session/element/matches_selector_spec.rb +70 -56
  159. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
  160. data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
  161. data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
  162. data/lib/capybara/spec/session/fill_in_spec.rb +110 -44
  163. data/lib/capybara/spec/session/find_button_spec.rb +23 -23
  164. data/lib/capybara/spec/session/find_by_id_spec.rb +8 -8
  165. data/lib/capybara/spec/session/find_field_spec.rb +33 -31
  166. data/lib/capybara/spec/session/find_link_spec.rb +42 -14
  167. data/lib/capybara/spec/session/find_spec.rb +251 -142
  168. data/lib/capybara/spec/session/first_spec.rb +45 -44
  169. data/lib/capybara/spec/session/frame/frame_title_spec.rb +6 -6
  170. data/lib/capybara/spec/session/frame/frame_url_spec.rb +6 -6
  171. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +32 -20
  172. data/lib/capybara/spec/session/frame/within_frame_spec.rb +46 -19
  173. data/lib/capybara/spec/session/go_back_spec.rb +1 -1
  174. data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
  175. data/lib/capybara/spec/session/has_all_selectors_spec.rb +23 -23
  176. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  177. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  178. data/lib/capybara/spec/session/has_button_spec.rb +98 -12
  179. data/lib/capybara/spec/session/has_css_spec.rb +271 -137
  180. data/lib/capybara/spec/session/has_current_path_spec.rb +50 -35
  181. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  182. data/lib/capybara/spec/session/has_field_spec.rb +137 -58
  183. data/lib/capybara/spec/session/has_link_spec.rb +46 -6
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +33 -31
  185. data/lib/capybara/spec/session/has_select_spec.rb +84 -50
  186. data/lib/capybara/spec/session/has_selector_spec.rb +117 -69
  187. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  188. data/lib/capybara/spec/session/has_table_spec.rb +181 -4
  189. data/lib/capybara/spec/session/has_text_spec.rb +101 -53
  190. data/lib/capybara/spec/session/has_title_spec.rb +19 -14
  191. data/lib/capybara/spec/session/has_xpath_spec.rb +56 -38
  192. data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +1 -1
  193. data/lib/capybara/spec/session/html_spec.rb +13 -6
  194. data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
  195. data/lib/capybara/spec/session/node_spec.rb +958 -122
  196. data/lib/capybara/spec/session/node_wrapper_spec.rb +15 -12
  197. data/lib/capybara/spec/session/refresh_spec.rb +9 -7
  198. data/lib/capybara/spec/session/reset_session_spec.rb +65 -37
  199. data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +1 -1
  200. data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
  201. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +5 -4
  202. data/lib/capybara/spec/session/save_page_spec.rb +41 -38
  203. data/lib/capybara/spec/session/save_screenshot_spec.rb +13 -11
  204. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  205. data/lib/capybara/spec/session/scroll_spec.rb +119 -0
  206. data/lib/capybara/spec/session/select_spec.rb +102 -76
  207. data/lib/capybara/spec/session/selectors_spec.rb +51 -18
  208. data/lib/capybara/spec/session/sibling_spec.rb +9 -9
  209. data/lib/capybara/spec/session/text_spec.rb +26 -24
  210. data/lib/capybara/spec/session/title_spec.rb +8 -6
  211. data/lib/capybara/spec/session/uncheck_spec.rb +41 -22
  212. data/lib/capybara/spec/session/unselect_spec.rb +37 -37
  213. data/lib/capybara/spec/session/visit_spec.rb +79 -53
  214. data/lib/capybara/spec/session/window/become_closed_spec.rb +22 -19
  215. data/lib/capybara/spec/session/window/current_window_spec.rb +4 -3
  216. data/lib/capybara/spec/session/window/open_new_window_spec.rb +4 -3
  217. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +25 -21
  218. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +10 -5
  219. data/lib/capybara/spec/session/window/window_spec.rb +88 -54
  220. data/lib/capybara/spec/session/window/windows_spec.rb +11 -8
  221. data/lib/capybara/spec/session/window/within_window_spec.rb +17 -16
  222. data/lib/capybara/spec/session/within_spec.rb +82 -44
  223. data/lib/capybara/spec/spec_helper.rb +46 -52
  224. data/lib/capybara/spec/test_app.rb +148 -41
  225. data/lib/capybara/spec/views/animated.erb +49 -0
  226. data/lib/capybara/spec/views/form.erb +156 -42
  227. data/lib/capybara/spec/views/frame_child.erb +4 -3
  228. data/lib/capybara/spec/views/frame_one.erb +2 -1
  229. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  230. data/lib/capybara/spec/views/frame_two.erb +1 -1
  231. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  232. data/lib/capybara/spec/views/layout.erb +10 -0
  233. data/lib/capybara/spec/views/obscured.erb +47 -0
  234. data/lib/capybara/spec/views/offset.erb +33 -0
  235. data/lib/capybara/spec/views/path.erb +2 -2
  236. data/lib/capybara/spec/views/popup_one.erb +1 -1
  237. data/lib/capybara/spec/views/popup_two.erb +1 -1
  238. data/lib/capybara/spec/views/react.erb +45 -0
  239. data/lib/capybara/spec/views/scroll.erb +21 -0
  240. data/lib/capybara/spec/views/spatial.erb +31 -0
  241. data/lib/capybara/spec/views/tables.erb +68 -1
  242. data/lib/capybara/spec/views/with_animation.erb +81 -0
  243. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  244. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  245. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  246. data/lib/capybara/spec/views/with_hover.erb +3 -2
  247. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  248. data/lib/capybara/spec/views/with_html.erb +46 -11
  249. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  250. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  251. data/lib/capybara/spec/views/with_js.erb +30 -5
  252. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  253. data/lib/capybara/spec/views/with_namespace.erb +21 -0
  254. data/lib/capybara/spec/views/with_scope.erb +2 -2
  255. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  256. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  257. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  258. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  259. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  260. data/lib/capybara/spec/views/with_windows.erb +1 -1
  261. data/lib/capybara/spec/views/within_frames.erb +1 -1
  262. data/lib/capybara/version.rb +1 -1
  263. data/lib/capybara/window.rb +32 -26
  264. data/lib/capybara.rb +128 -104
  265. data/spec/basic_node_spec.rb +59 -34
  266. data/spec/capybara_spec.rb +65 -51
  267. data/spec/counter_spec.rb +35 -0
  268. data/spec/css_builder_spec.rb +101 -0
  269. data/spec/css_splitter_spec.rb +38 -0
  270. data/spec/dsl_spec.rb +84 -55
  271. data/spec/filter_set_spec.rb +24 -7
  272. data/spec/fixtures/certificate.pem +25 -0
  273. data/spec/fixtures/key.pem +27 -0
  274. data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -5
  275. data/spec/fixtures/selenium_driver_rspec_success.rb +5 -5
  276. data/spec/minitest_spec.rb +49 -5
  277. data/spec/minitest_spec_spec.rb +92 -62
  278. data/spec/per_session_config_spec.rb +6 -6
  279. data/spec/rack_test_spec.rb +183 -115
  280. data/spec/regexp_dissassembler_spec.rb +250 -0
  281. data/spec/result_spec.rb +99 -39
  282. data/spec/rspec/features_spec.rb +28 -25
  283. data/spec/rspec/scenarios_spec.rb +10 -6
  284. data/spec/rspec/shared_spec_matchers.rb +418 -364
  285. data/spec/rspec/views_spec.rb +4 -3
  286. data/spec/rspec_matchers_spec.rb +35 -10
  287. data/spec/rspec_spec.rb +109 -85
  288. data/spec/sauce_spec_chrome.rb +43 -0
  289. data/spec/selector_spec.rb +392 -62
  290. data/spec/selenium_spec_chrome.rb +183 -41
  291. data/spec/selenium_spec_chrome_remote.rb +96 -0
  292. data/spec/selenium_spec_edge.rb +41 -8
  293. data/spec/selenium_spec_firefox.rb +228 -0
  294. data/spec/selenium_spec_firefox_remote.rb +94 -0
  295. data/spec/selenium_spec_ie.rb +129 -11
  296. data/spec/selenium_spec_safari.rb +162 -0
  297. data/spec/server_spec.rb +192 -81
  298. data/spec/session_spec.rb +52 -16
  299. data/spec/shared_selenium_node.rb +79 -0
  300. data/spec/shared_selenium_session.rb +460 -123
  301. data/spec/spec_helper.rb +124 -2
  302. data/spec/whitespace_normalizer_spec.rb +54 -0
  303. data/spec/xpath_builder_spec.rb +93 -0
  304. metadata +344 -45
  305. data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
  306. data/.yard/templates_custom/default/class/html/setup.rb +0 -17
  307. data/.yard/yard_extensions.rb +0 -78
  308. data/lib/capybara/rspec/compound.rb +0 -90
  309. data/lib/capybara/spec/session/assert_selector.rb +0 -149
  310. data/lib/capybara/spec/session/source_spec.rb +0 -0
  311. data/lib/capybara/spec/views/with_title.erb +0 -5
  312. data/spec/selenium_spec_marionette.rb +0 -143
@@ -9,66 +9,67 @@ Capybara::SpecHelper.spec '#find' do
9
9
  Capybara::Selector.remove(:monkey)
10
10
  end
11
11
 
12
- it "should find the first element using the given locator" do
12
+ it 'should find the first element using the given locator' do
13
13
  expect(@session.find('//h1').text).to eq('This is a test')
14
14
  expect(@session.find("//input[@id='test_field']").value).to eq('monkey')
15
15
  end
16
16
 
17
- it "should find the first element using the given locator and options" do
17
+ it 'should find the first element using the given locator and options' do
18
18
  expect(@session.find('//a', text: 'Redirect')[:id]).to eq('red')
19
19
  expect(@session.find(:css, 'a', text: 'A link came first')[:title]).to eq('twas a fine link')
20
20
  end
21
21
 
22
- it "should raise an error if there are multiple matches" do
22
+ it 'should raise an error if there are multiple matches' do
23
23
  expect { @session.find('//a') }.to raise_error(Capybara::Ambiguous)
24
24
  end
25
25
 
26
- it "should wait for asynchronous load", requires: [:js] do
26
+ it 'should wait for asynchronous load', requires: [:js] do
27
+ Capybara.default_max_wait_time = 2
27
28
  @session.visit('/with_js')
28
29
  @session.click_link('Click me')
29
- expect(@session.find(:css, "a#has-been-clicked").text).to include('Has been clicked')
30
+ expect(@session.find(:css, 'a#has-been-clicked').text).to include('Has been clicked')
30
31
  end
31
32
 
32
- context "with :text option" do
33
+ context 'with :text option' do
33
34
  it "casts text's argument to string" do
34
- expect(@session.find(:css, '.number', text: 42)).to have_content("42")
35
+ expect(@session.find(:css, '.number', text: 42)).to have_content('42')
35
36
  end
36
37
  end
37
38
 
38
- context "with :wait option", requires: [:js] do
39
- it "should not wait for asynchronous load when `false` given" do
39
+ context 'with :wait option', requires: [:js] do
40
+ it 'should not wait for asynchronous load when `false` given' do
40
41
  @session.visit('/with_js')
41
42
  @session.click_link('Click me')
42
43
  expect do
43
- @session.find(:css, "a#has-been-clicked", wait: false)
44
+ @session.find(:css, 'a#has-been-clicked', wait: false)
44
45
  end.to raise_error(Capybara::ElementNotFound)
45
46
  end
46
47
 
47
- it "should not find element if it appears after given wait duration" do
48
+ it 'should not find element if it appears after given wait duration' do
48
49
  @session.visit('/with_js')
49
50
  @session.click_link('Slowly')
50
51
  expect do
51
- @session.find(:css, "a#slow-clicked", wait: 0.2)
52
+ @session.find(:css, 'a#slow-clicked', wait: 0.2)
52
53
  end.to raise_error(Capybara::ElementNotFound)
53
54
  end
54
55
 
55
- it "should find element if it appears before given wait duration" do
56
+ it 'should find element if it appears before given wait duration' do
56
57
  @session.visit('/with_js')
57
58
  @session.click_link('Click me')
58
- expect(@session.find(:css, "a#has-been-clicked", wait: 2.0).text).to include('Has been clicked')
59
+ expect(@session.find(:css, 'a#has-been-clicked', wait: 3.0).text).to include('Has been clicked')
59
60
  end
60
61
  end
61
62
 
62
- context "with frozen time", requires: [:js] do
63
+ context 'with frozen time', requires: [:js] do
63
64
  if defined?(Process::CLOCK_MONOTONIC)
64
- it "will time out even if time is frozen" do
65
+ it 'will time out even if time is frozen' do
65
66
  @session.visit('/with_js')
66
67
  now = Time.now
67
68
  allow(Time).to receive(:now).and_return(now)
68
69
  expect { @session.find('//isnotthere') }.to raise_error(Capybara::ElementNotFound)
69
70
  end
70
71
  else
71
- it "raises an error suggesting that Capybara is stuck in time" do
72
+ it 'raises an error suggesting that Capybara is stuck in time' do
72
73
  @session.visit('/with_js')
73
74
  now = Time.now
74
75
  allow(Time).to receive(:now).and_return(now)
@@ -77,31 +78,42 @@ Capybara::SpecHelper.spec '#find' do
77
78
  end
78
79
  end
79
80
 
80
- context "with css selectors" do
81
- it "should find the first element using the given locator" do
81
+ context 'with css selectors' do
82
+ it 'should find the first element using the given locator' do
82
83
  expect(@session.find(:css, 'h1').text).to eq('This is a test')
83
84
  expect(@session.find(:css, "input[id='test_field']").value).to eq('monkey')
84
85
  end
85
86
 
86
- it "should support pseudo selectors" do
87
+ it 'should support pseudo selectors' do
87
88
  expect(@session.find(:css, 'input:disabled').value).to eq('This is disabled')
88
89
  end
89
90
 
90
- it "should support escaping characters" do
91
+ it 'should support escaping characters' do
91
92
  expect(@session.find(:css, '#\31 escape\.me').text).to eq('needs escaping')
92
93
  expect(@session.find(:css, '.\32 escape').text).to eq('needs escaping')
93
94
  end
95
+
96
+ it 'should not warn about locator' do
97
+ expect { @session.find(:css, '#not_on_page') }.to raise_error Capybara::ElementNotFound do |e|
98
+ expect(e.message).not_to match(/you may be passing a CSS selector or XPath expression/)
99
+ end
100
+ end
94
101
  end
95
102
 
96
- context "with xpath selectors" do
97
- it "should find the first element using the given locator" do
103
+ context 'with xpath selectors' do
104
+ it 'should find the first element using the given locator' do
98
105
  expect(@session.find(:xpath, '//h1').text).to eq('This is a test')
99
106
  expect(@session.find(:xpath, "//input[@id='test_field']").value).to eq('monkey')
100
107
  end
108
+
109
+ it 'should warn if passed a non-valid locator type' do
110
+ expect { @session.find(:xpath, 123) }.to raise_error(Exception) # The exact error is not yet well defined
111
+ .and output(/must respond to to_xpath or be an instance of String/).to_stderr
112
+ end
101
113
  end
102
114
 
103
- context "with custom selector" do
104
- it "should use the custom selector" do
115
+ context 'with custom selector' do
116
+ it 'should use the custom selector' do
105
117
  Capybara.add_selector(:beatle) do
106
118
  xpath { |name| ".//*[@id='#{name}']" }
107
119
  end
@@ -110,8 +122,8 @@ Capybara::SpecHelper.spec '#find' do
110
122
  end
111
123
  end
112
124
 
113
- context "with custom selector with custom `match` block" do
114
- it "should use the custom selector when locator matches the block" do
125
+ context 'with custom selector with custom `match` block' do
126
+ it 'should use the custom selector when locator matches the block' do
115
127
  Capybara.add_selector(:beatle) do
116
128
  xpath { |num| ".//*[contains(@class, 'beatle')][#{num}]" }
117
129
  match { |value| value.is_a?(Integer) }
@@ -123,20 +135,21 @@ Capybara::SpecHelper.spec '#find' do
123
135
  end
124
136
  end
125
137
 
126
- context "with custom selector with custom filter" do
138
+ context 'with custom selector with custom filter' do
127
139
  before do
128
140
  Capybara.add_selector(:beatle) do
129
141
  xpath { |name| ".//li[contains(@class, 'beatle')][contains(text(), '#{name}')]" }
130
- filter(:type) { |node, type| node[:class].split(/\s+/).include?(type) }
142
+ node_filter(:type) { |node, type| node[:class].split(/\s+/).include?(type) }
143
+ node_filter(:fail) { |_node, _val| raise Capybara::ElementNotFound, 'fail' }
131
144
  end
132
145
  end
133
146
 
134
- it "should find elements that match the filter" do
147
+ it 'should find elements that match the filter' do
135
148
  expect(@session.find(:beatle, 'Paul', type: 'drummer').text).to eq('Paul')
136
149
  expect(@session.find(:beatle, 'Ringo', type: 'drummer').text).to eq('Ringo')
137
150
  end
138
151
 
139
- it "ignores filter when it is not given" do
152
+ it 'ignores filter when it is not given' do
140
153
  expect(@session.find(:beatle, 'Paul').text).to eq('Paul')
141
154
  expect(@session.find(:beatle, 'John').text).to eq('John')
142
155
  end
@@ -145,22 +158,26 @@ Capybara::SpecHelper.spec '#find' do
145
158
  expect { @session.find(:beatle, 'John', type: 'drummer') }.to raise_error(Capybara::ElementNotFound)
146
159
  expect { @session.find(:beatle, 'George', type: 'drummer') }.to raise_error(Capybara::ElementNotFound)
147
160
  end
161
+
162
+ it 'should not raise an ElementNotFound error from in a filter' do
163
+ expect { @session.find(:beatle, 'John', fail: 'something') }.to raise_error(Capybara::ElementNotFound, /beatle "John"/)
164
+ end
148
165
  end
149
166
 
150
- context "with custom selector with custom filter and default" do
167
+ context 'with custom selector with custom filter and default' do
151
168
  before do
152
169
  Capybara.add_selector(:beatle) do
153
170
  xpath { |name| ".//li[contains(@class, 'beatle')][contains(text(), '#{name}')]" }
154
- filter(:type, default: "drummer") { |node, type| node[:class].split(/\s+/).include?(type) }
171
+ node_filter(:type, default: 'drummer') { |node, type| node[:class].split(/\s+/).include?(type) }
155
172
  end
156
173
  end
157
174
 
158
- it "should find elements that match the filter" do
175
+ it 'should find elements that match the filter' do
159
176
  expect(@session.find(:beatle, 'Paul', type: 'drummer').text).to eq('Paul')
160
177
  expect(@session.find(:beatle, 'Ringo', type: 'drummer').text).to eq('Ringo')
161
178
  end
162
179
 
163
- it "should use default value when filter is not given" do
180
+ it 'should use default value when filter is not given' do
164
181
  expect(@session.find(:beatle, 'Paul').text).to eq('Paul')
165
182
  expect { @session.find(:beatle, 'John') }.to raise_error(Capybara::ElementNotFound)
166
183
  end
@@ -171,10 +188,10 @@ Capybara::SpecHelper.spec '#find' do
171
188
  end
172
189
  end
173
190
 
174
- context "with alternate filter set" do
191
+ context 'with alternate filter set' do
175
192
  before do
176
193
  Capybara::Selector::FilterSet.add(:value) do
177
- filter(:with) { |node, with| node.value == with.to_s }
194
+ node_filter(:with) { |node, with| node.value == with.to_s }
178
195
  end
179
196
 
180
197
  Capybara.add_selector(:id_with_field_filters) do
@@ -183,254 +200,346 @@ Capybara::SpecHelper.spec '#find' do
183
200
  end
184
201
  end
185
202
 
186
- it "should allow use of filters from custom filter set" do
203
+ it 'should allow use of filters from custom filter set' do
187
204
  expect(@session.find(:id, 'test_field', filter_set: :value, with: 'monkey').value).to eq('monkey')
188
205
  expect { @session.find(:id, 'test_field', filter_set: :value, with: 'not_monkey') }.to raise_error(Capybara::ElementNotFound)
189
206
  end
190
207
 
191
- it "should allow use of filter set from a different selector" do
208
+ it 'should allow use of filter set from a different selector' do
192
209
  expect(@session.find(:id, 'test_field', filter_set: :field, with: 'monkey').value).to eq('monkey')
193
210
  expect { @session.find(:id, 'test_field', filter_set: :field, with: 'not_monkey') }.to raise_error(Capybara::ElementNotFound)
194
211
  end
195
212
 
196
- it "should allow importing of filter set into selector" do
213
+ it 'should allow importing of filter set into selector' do
197
214
  expect(@session.find(:id_with_field_filters, 'test_field', with: 'monkey').value).to eq('monkey')
198
215
  expect { @session.find(:id_with_field_filters, 'test_field', with: 'not_monkey') }.to raise_error(Capybara::ElementNotFound)
199
216
  end
200
217
  end
201
218
 
202
- context "with css as default selector" do
219
+ context 'with css as default selector' do
203
220
  before { Capybara.default_selector = :css }
204
- it "should find the first element using the given locator" do
221
+
222
+ after { Capybara.default_selector = :xpath }
223
+
224
+ it 'should find the first element using the given locator' do
205
225
  expect(@session.find('h1').text).to eq('This is a test')
206
226
  expect(@session.find("input[id='test_field']").value).to eq('monkey')
207
227
  end
208
- after { Capybara.default_selector = :xpath }
209
228
  end
210
229
 
211
- it "should raise ElementNotFound with a useful default message if nothing was found" do
230
+ it 'should raise ElementNotFound with a useful default message if nothing was found' do
212
231
  expect do
213
232
  @session.find(:xpath, '//div[@id="nosuchthing"]').to be_nil
214
- end.to raise_error(Capybara::ElementNotFound, "Unable to find visible xpath \"//div[@id=\\\"nosuchthing\\\"]\"")
233
+ end.to raise_error(Capybara::ElementNotFound, 'Unable to find xpath "//div[@id=\\"nosuchthing\\"]"')
234
+ end
235
+
236
+ context 'without locator' do
237
+ it 'should not output `nil` in the ElementNotFound message if nothing was found' do
238
+ expect do
239
+ @session.find(:label, text: 'no such thing').to be_nil
240
+ end.to raise_error(Capybara::ElementNotFound, 'Unable to find label')
241
+ end
215
242
  end
216
243
 
217
- it "should accept an XPath instance" do
244
+ it 'should accept an XPath instance' do
218
245
  @session.visit('/form')
219
- @xpath = Capybara::Selector.all[:fillable_field].call('First Name')
220
- expect(@xpath).to be_a(::XPath::Union)
246
+ @xpath = Capybara::Selector.new(:fillable_field, config: {}, format: :xpath).call('First Name')
247
+ expect(@xpath).to be_a(XPath::Union)
221
248
  expect(@session.find(@xpath).value).to eq('John')
222
249
  end
223
250
 
224
- context "with :exact option" do
225
- it "matches exactly when true" do
226
- expect(@session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("test_field")], exact: true).value).to eq("monkey")
251
+ context 'with :exact option' do
252
+ it 'matches exactly when true' do
253
+ expect(@session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is('test_field')], exact: true).value).to eq('monkey')
227
254
  expect do
228
- @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")], exact: true)
255
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is('est_fiel')], exact: true)
229
256
  end.to raise_error(Capybara::ElementNotFound)
230
257
  end
231
258
 
232
- it "matches loosely when false" do
233
- expect(@session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("test_field")], exact: false).value).to eq("monkey")
234
- expect(@session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")], exact: false).value).to eq("monkey")
259
+ it 'matches loosely when false' do
260
+ expect(@session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is('test_field')], exact: false).value).to eq('monkey')
261
+ expect(@session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is('est_fiel')], exact: false).value).to eq('monkey')
235
262
  end
236
263
 
237
- it "defaults to `Capybara.exact`" do
264
+ it 'defaults to `Capybara.exact`' do
238
265
  Capybara.exact = true
239
266
  expect do
240
- @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")])
267
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is('est_fiel')])
241
268
  end.to raise_error(Capybara::ElementNotFound)
242
269
  Capybara.exact = false
243
- @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")])
270
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is('est_fiel')])
244
271
  end
245
272
 
246
- it "warns when the option has no effect" do
247
- expect_any_instance_of(Kernel).to receive(:warn)
248
- .with('The :exact option only has an effect on queries using the XPath#is method. Using it with the query "#test_field" has no effect.')
249
- @session.find(:css, '#test_field', exact: true)
273
+ it 'warns when the option has no effect' do
274
+ expect { @session.find(:css, '#test_field', exact: true) }.to \
275
+ output(/^The :exact option only has an effect on queries using the XPath#is method. Using it with the query "#test_field" has no effect/).to_stderr
250
276
  end
251
277
  end
252
278
 
253
- context "with :match option" do
254
- context "when set to `one`" do
255
- it "raises an error when multiple matches exist" do
279
+ context 'with :match option' do
280
+ context 'when set to `one`' do
281
+ it 'raises an error when multiple matches exist' do
256
282
  expect do
257
- @session.find(:css, ".multiple", match: :one)
283
+ @session.find(:css, '.multiple', match: :one)
258
284
  end.to raise_error(Capybara::Ambiguous)
259
285
  end
260
- it "raises an error even if there the match is exact and the others are inexact" do
286
+
287
+ it 'raises an error even if there the match is exact and the others are inexact' do
261
288
  expect do
262
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], exact: false, match: :one)
289
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], exact: false, match: :one)
263
290
  end.to raise_error(Capybara::Ambiguous)
264
291
  end
265
- it "returns the element if there is only one" do
266
- expect(@session.find(:css, ".singular", match: :one).text).to eq("singular")
292
+
293
+ it 'returns the element if there is only one' do
294
+ expect(@session.find(:css, '.singular', match: :one).text).to eq('singular')
267
295
  end
268
- it "raises an error if there is no match" do
296
+
297
+ it 'raises an error if there is no match' do
269
298
  expect do
270
- @session.find(:css, ".does-not-exist", match: :one)
299
+ @session.find(:css, '.does-not-exist', match: :one)
271
300
  end.to raise_error(Capybara::ElementNotFound)
272
301
  end
273
302
  end
274
303
 
275
- context "when set to `first`" do
276
- it "returns the first matched element" do
277
- expect(@session.find(:css, ".multiple", match: :first).text).to eq("multiple one")
304
+ context 'when set to `first`' do
305
+ it 'returns the first matched element' do
306
+ expect(@session.find(:css, '.multiple', match: :first).text).to eq('multiple one')
278
307
  end
279
- it "raises an error if there is no match" do
308
+
309
+ it 'raises an error if there is no match' do
280
310
  expect do
281
- @session.find(:css, ".does-not-exist", match: :first)
311
+ @session.find(:css, '.does-not-exist', match: :first)
282
312
  end.to raise_error(Capybara::ElementNotFound)
283
313
  end
284
314
  end
285
315
 
286
- context "when set to `smart`" do
287
- context "and `exact` set to `false`" do
288
- it "raises an error when there are multiple exact matches" do
316
+ context 'when set to `smart`' do
317
+ context 'and `exact` set to `false`' do
318
+ it 'raises an error when there are multiple exact matches' do
289
319
  expect do
290
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("multiple")], match: :smart, exact: false)
320
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :smart, exact: false)
291
321
  end.to raise_error(Capybara::Ambiguous)
292
322
  end
293
- it "finds a single exact match when there also are inexact matches" do
294
- result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], match: :smart, exact: false)
295
- expect(result.text).to eq("almost singular")
323
+
324
+ it 'finds a single exact match when there also are inexact matches' do
325
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :smart, exact: false)
326
+ expect(result.text).to eq('almost singular')
296
327
  end
297
- it "raises an error when there are multiple inexact matches" do
328
+
329
+ it 'raises an error when there are multiple inexact matches' do
298
330
  expect do
299
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], match: :smart, exact: false)
331
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :smart, exact: false)
300
332
  end.to raise_error(Capybara::Ambiguous)
301
333
  end
302
- it "finds a single inexact match" do
303
- result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular but")], match: :smart, exact: false)
304
- expect(result.text).to eq("almost singular but not quite")
334
+
335
+ it 'finds a single inexact match' do
336
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :smart, exact: false)
337
+ expect(result.text).to eq('almost singular but not quite')
305
338
  end
306
- it "raises an error if there is no match" do
339
+
340
+ it 'raises an error if there is no match' do
307
341
  expect do
308
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("does-not-exist")], match: :smart, exact: false)
342
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :smart, exact: false)
309
343
  end.to raise_error(Capybara::ElementNotFound)
310
344
  end
311
345
  end
312
346
 
313
- context "with `exact` set to `true`" do
314
- it "raises an error when there are multiple exact matches" do
347
+ context 'with `exact` set to `true`' do
348
+ it 'raises an error when there are multiple exact matches' do
315
349
  expect do
316
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("multiple")], match: :smart, exact: true)
350
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :smart, exact: true)
317
351
  end.to raise_error(Capybara::Ambiguous)
318
352
  end
319
- it "finds a single exact match when there also are inexact matches" do
320
- result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], match: :smart, exact: true)
321
- expect(result.text).to eq("almost singular")
353
+
354
+ it 'finds a single exact match when there also are inexact matches' do
355
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :smart, exact: true)
356
+ expect(result.text).to eq('almost singular')
322
357
  end
323
- it "raises an error when there are multiple inexact matches" do
358
+
359
+ it 'raises an error when there are multiple inexact matches' do
324
360
  expect do
325
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], match: :smart, exact: true)
361
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :smart, exact: true)
326
362
  end.to raise_error(Capybara::ElementNotFound)
327
363
  end
328
- it "raises an error when there is a single inexact matches" do
364
+
365
+ it 'raises an error when there is a single inexact matches' do
329
366
  expect do
330
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular but")], match: :smart, exact: true)
367
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :smart, exact: true)
331
368
  end.to raise_error(Capybara::ElementNotFound)
332
369
  end
333
- it "raises an error if there is no match" do
370
+
371
+ it 'raises an error if there is no match' do
334
372
  expect do
335
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("does-not-exist")], match: :smart, exact: true)
373
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :smart, exact: true)
336
374
  end.to raise_error(Capybara::ElementNotFound)
337
375
  end
338
376
  end
339
377
  end
340
378
 
341
- context "when set to `prefer_exact`" do
342
- context "and `exact` set to `false`" do
343
- it "picks the first one when there are multiple exact matches" do
344
- result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("multiple")], match: :prefer_exact, exact: false)
345
- expect(result.text).to eq("multiple one")
379
+ context 'when set to `prefer_exact`' do
380
+ context 'and `exact` set to `false`' do
381
+ it 'picks the first one when there are multiple exact matches' do
382
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :prefer_exact, exact: false)
383
+ expect(result.text).to eq('multiple one')
346
384
  end
347
- it "finds a single exact match when there also are inexact matches" do
348
- result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], match: :prefer_exact, exact: false)
349
- expect(result.text).to eq("almost singular")
385
+
386
+ it 'finds a single exact match when there also are inexact matches' do
387
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :prefer_exact, exact: false)
388
+ expect(result.text).to eq('almost singular')
350
389
  end
351
- it "picks the first one when there are multiple inexact matches" do
352
- result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], match: :prefer_exact, exact: false)
353
- expect(result.text).to eq("almost singular but not quite")
390
+
391
+ it 'picks the first one when there are multiple inexact matches' do
392
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :prefer_exact, exact: false)
393
+ expect(result.text).to eq('almost singular but not quite')
354
394
  end
355
- it "finds a single inexact match" do
356
- result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular but")], match: :prefer_exact, exact: false)
357
- expect(result.text).to eq("almost singular but not quite")
395
+
396
+ it 'finds a single inexact match' do
397
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :prefer_exact, exact: false)
398
+ expect(result.text).to eq('almost singular but not quite')
358
399
  end
359
- it "raises an error if there is no match" do
400
+
401
+ it 'raises an error if there is no match' do
360
402
  expect do
361
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("does-not-exist")], match: :prefer_exact, exact: false)
403
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :prefer_exact, exact: false)
362
404
  end.to raise_error(Capybara::ElementNotFound)
363
405
  end
364
406
  end
365
407
 
366
- context "with `exact` set to `true`" do
367
- it "picks the first one when there are multiple exact matches" do
368
- result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("multiple")], match: :prefer_exact, exact: true)
369
- expect(result.text).to eq("multiple one")
408
+ context 'with `exact` set to `true`' do
409
+ it 'picks the first one when there are multiple exact matches' do
410
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :prefer_exact, exact: true)
411
+ expect(result.text).to eq('multiple one')
370
412
  end
371
- it "finds a single exact match when there also are inexact matches" do
372
- result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], match: :prefer_exact, exact: true)
373
- expect(result.text).to eq("almost singular")
413
+
414
+ it 'finds a single exact match when there also are inexact matches' do
415
+ result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :prefer_exact, exact: true)
416
+ expect(result.text).to eq('almost singular')
374
417
  end
375
- it "raises an error if there are multiple inexact matches" do
418
+
419
+ it 'raises an error if there are multiple inexact matches' do
376
420
  expect do
377
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], match: :prefer_exact, exact: true)
421
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :prefer_exact, exact: true)
378
422
  end.to raise_error(Capybara::ElementNotFound)
379
423
  end
380
- it "raises an error if there is a single inexact match" do
424
+
425
+ it 'raises an error if there is a single inexact match' do
381
426
  expect do
382
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular but")], match: :prefer_exact, exact: true)
427
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :prefer_exact, exact: true)
383
428
  end.to raise_error(Capybara::ElementNotFound)
384
429
  end
385
- it "raises an error if there is no match" do
430
+
431
+ it 'raises an error if there is no match' do
386
432
  expect do
387
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("does-not-exist")], match: :prefer_exact, exact: true)
433
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :prefer_exact, exact: true)
388
434
  end.to raise_error(Capybara::ElementNotFound)
389
435
  end
390
436
  end
391
437
  end
392
438
 
393
- it "defaults to `Capybara.match`" do
439
+ it 'defaults to `Capybara.match`' do
394
440
  Capybara.match = :one
395
441
  expect do
396
- @session.find(:css, ".multiple")
442
+ @session.find(:css, '.multiple')
397
443
  end.to raise_error(Capybara::Ambiguous)
398
444
  Capybara.match = :first
399
- expect(@session.find(:css, ".multiple").text).to eq("multiple one")
445
+ expect(@session.find(:css, '.multiple').text).to eq('multiple one')
400
446
  end
401
447
 
402
- it "raises an error when unknown option given" do
448
+ it 'raises an error when unknown option given' do
403
449
  expect do
404
- @session.find(:css, ".singular", match: :schmoo)
450
+ @session.find(:css, '.singular', match: :schmoo)
405
451
  end.to raise_error(ArgumentError)
406
452
  end
407
453
  end
408
454
 
409
- it "supports a custom filter block" do
455
+ it 'supports a custom filter block' do
410
456
  expect(@session.find(:css, 'input', &:disabled?)[:name]).to eq('disabled_text')
411
457
  end
412
458
 
413
- context "within a scope" do
459
+ context 'with spatial filters', requires: [:spatial] do
460
+ before do
461
+ @session.visit('/spatial')
462
+ end
463
+
464
+ let :center do
465
+ @session.find(:css, 'div.center')
466
+ end
467
+
468
+ it 'should find an element above another element' do
469
+ expect(@session.find(:css, 'div:not(.corner)', above: center).text).to eq('2')
470
+ end
471
+
472
+ it 'should find an element below another element' do
473
+ expect(@session.find(:css, 'div:not(.corner):not(.footer)', below: center).text).to eq('8')
474
+ end
475
+
476
+ it 'should find an element left of another element' do
477
+ expect(@session.find(:css, 'div:not(.corner)', left_of: center).text).to eq('4')
478
+ end
479
+
480
+ it 'should find an element right of another element' do
481
+ expect(@session.find(:css, 'div:not(.corner)', right_of: center).text).to eq('6')
482
+ end
483
+
484
+ it 'should combine spatial filters' do
485
+ expect(@session.find(:css, 'div', left_of: center, above: center).text).to eq('1')
486
+ expect(@session.find(:css, 'div', right_of: center, below: center).text).to eq('9')
487
+ end
488
+
489
+ it 'should find an element "near" another element' do
490
+ expect(@session.find(:css, 'div.distance', near: center).text).to eq('2')
491
+ end
492
+ end
493
+
494
+ context 'within a scope' do
414
495
  before do
415
496
  @session.visit('/with_scope')
416
497
  end
417
498
 
418
- it "should find the an element using the given locator" do
499
+ it 'should find the an element using the given locator' do
419
500
  @session.within(:xpath, "//div[@id='for_bar']") do
420
501
  expect(@session.find('.//li[1]').text).to match(/With Simple HTML/)
421
502
  end
422
503
  end
423
504
 
424
- it "should support pseudo selectors" do
505
+ it 'should support pseudo selectors' do
425
506
  @session.within(:xpath, "//div[@id='for_bar']") do
426
507
  expect(@session.find(:css, 'input:disabled').value).to eq('James')
427
508
  end
428
509
  end
429
510
  end
430
511
 
431
- it "should raise if selector type is unknown" do
512
+ it 'should raise if selector type is unknown' do
432
513
  expect do
433
514
  @session.find(:unknown, '//h1')
434
515
  end.to raise_error(ArgumentError)
435
516
  end
517
+
518
+ context 'with Capybara.test_id' do
519
+ it 'should not match on it when nil' do
520
+ Capybara.test_id = nil
521
+ expect(@session).not_to have_field('test_id')
522
+ end
523
+
524
+ it 'should work with the attribute set to `data-test-id` attribute' do
525
+ Capybara.test_id = 'data-test-id'
526
+ expect(@session.find(:field, 'test_id')[:id]).to eq 'test_field'
527
+ end
528
+
529
+ it 'should use a different attribute if set' do
530
+ Capybara.test_id = 'data-other-test-id'
531
+ expect(@session.find(:field, 'test_id')[:id]).to eq 'normal'
532
+ end
533
+
534
+ it 'should find a link with the test_id' do
535
+ Capybara.test_id = 'data-test-id'
536
+ expect(@session.find(:link, 'test-foo')[:id]).to eq 'foo'
537
+ end
538
+ end
539
+
540
+ it 'should warn if passed count options' do
541
+ allow(Capybara::Helpers).to receive(:warn)
542
+ @session.find('//h1', count: 44)
543
+ expect(Capybara::Helpers).to have_received(:warn).with(/'find' does not support count options/)
544
+ end
436
545
  end