capybara 3.32.2

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