capybara 3.0.0 → 3.36.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 (308) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +777 -10
  4. data/License.txt +1 -1
  5. data/README.md +75 -58
  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 +34 -9
  10. data/lib/capybara/dsl.rb +14 -6
  11. data/lib/capybara/helpers.rb +52 -7
  12. data/lib/capybara/minitest/spec.rb +173 -84
  13. data/lib/capybara/minitest.rb +250 -144
  14. data/lib/capybara/node/actions.rb +248 -124
  15. data/lib/capybara/node/base.rb +34 -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 +339 -113
  19. data/lib/capybara/node/finders.rb +95 -82
  20. data/lib/capybara/node/matchers.rb +338 -157
  21. data/lib/capybara/node/simple.rb +54 -15
  22. data/lib/capybara/queries/active_element_query.rb +18 -0
  23. data/lib/capybara/queries/ancestor_query.rb +9 -10
  24. data/lib/capybara/queries/base_query.rb +25 -18
  25. data/lib/capybara/queries/current_path_query.rb +16 -6
  26. data/lib/capybara/queries/match_query.rb +11 -0
  27. data/lib/capybara/queries/selector_query.rb +600 -103
  28. data/lib/capybara/queries/sibling_query.rb +9 -7
  29. data/lib/capybara/queries/style_query.rb +45 -0
  30. data/lib/capybara/queries/text_query.rb +40 -22
  31. data/lib/capybara/queries/title_query.rb +2 -2
  32. data/lib/capybara/rack_test/browser.rb +47 -28
  33. data/lib/capybara/rack_test/driver.rb +12 -3
  34. data/lib/capybara/rack_test/errors.rb +6 -0
  35. data/lib/capybara/rack_test/form.rb +53 -50
  36. data/lib/capybara/rack_test/node.rb +114 -37
  37. data/lib/capybara/rails.rb +1 -1
  38. data/lib/capybara/registration_container.rb +44 -0
  39. data/lib/capybara/registrations/drivers.rb +42 -0
  40. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  41. data/lib/capybara/registrations/servers.rb +45 -0
  42. data/lib/capybara/result.rb +86 -52
  43. data/lib/capybara/rspec/features.rb +8 -10
  44. data/lib/capybara/rspec/matcher_proxies.rb +39 -18
  45. data/lib/capybara/rspec/matchers/base.rb +111 -0
  46. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  47. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  48. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  49. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  50. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  51. data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
  52. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  53. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  54. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  55. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  56. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  57. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  58. data/lib/capybara/rspec/matchers.rb +138 -316
  59. data/lib/capybara/rspec.rb +3 -2
  60. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  61. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  62. data/lib/capybara/selector/css.rb +89 -12
  63. data/lib/capybara/selector/definition/button.rb +68 -0
  64. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  65. data/lib/capybara/selector/definition/css.rb +10 -0
  66. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  67. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  68. data/lib/capybara/selector/definition/element.rb +28 -0
  69. data/lib/capybara/selector/definition/field.rb +40 -0
  70. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  71. data/lib/capybara/selector/definition/file_field.rb +13 -0
  72. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  73. data/lib/capybara/selector/definition/frame.rb +17 -0
  74. data/lib/capybara/selector/definition/id.rb +6 -0
  75. data/lib/capybara/selector/definition/label.rb +62 -0
  76. data/lib/capybara/selector/definition/link.rb +54 -0
  77. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  78. data/lib/capybara/selector/definition/option.rb +27 -0
  79. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  80. data/lib/capybara/selector/definition/select.rb +81 -0
  81. data/lib/capybara/selector/definition/table.rb +109 -0
  82. data/lib/capybara/selector/definition/table_row.rb +21 -0
  83. data/lib/capybara/selector/definition/xpath.rb +5 -0
  84. data/lib/capybara/selector/definition.rb +279 -0
  85. data/lib/capybara/selector/filter.rb +1 -0
  86. data/lib/capybara/selector/filter_set.rb +72 -27
  87. data/lib/capybara/selector/filters/base.rb +45 -2
  88. data/lib/capybara/selector/filters/expression_filter.rb +5 -6
  89. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  90. data/lib/capybara/selector/filters/node_filter.rb +18 -4
  91. data/lib/capybara/selector/regexp_disassembler.rb +214 -0
  92. data/lib/capybara/selector/selector.rb +85 -200
  93. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  94. data/lib/capybara/selector.rb +226 -537
  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 +296 -238
  100. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  101. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -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 +76 -0
  110. data/lib/capybara/selenium/logger_suppressor.rb +40 -0
  111. data/lib/capybara/selenium/node.rb +436 -166
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +104 -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/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 +45 -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/animation_disabler.rb +69 -0
  124. data/lib/capybara/server/checker.rb +44 -0
  125. data/lib/capybara/server/middleware.rb +71 -0
  126. data/lib/capybara/server.rb +58 -67
  127. data/lib/capybara/session/config.rb +38 -6
  128. data/lib/capybara/session/matchers.rb +26 -19
  129. data/lib/capybara/session.rb +258 -190
  130. data/lib/capybara/spec/public/jquery.js +5 -5
  131. data/lib/capybara/spec/public/offset.js +6 -0
  132. data/lib/capybara/spec/public/test.js +122 -8
  133. data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
  134. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
  135. data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
  136. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  137. data/lib/capybara/spec/session/all_spec.rb +135 -42
  138. data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
  139. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
  140. data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +20 -18
  141. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  142. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  143. data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +62 -38
  144. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +12 -12
  145. data/lib/capybara/spec/session/attach_file_spec.rb +120 -72
  146. data/lib/capybara/spec/session/body_spec.rb +11 -13
  147. data/lib/capybara/spec/session/check_spec.rb +111 -51
  148. data/lib/capybara/spec/session/choose_spec.rb +62 -30
  149. data/lib/capybara/spec/session/click_button_spec.rb +227 -161
  150. data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -30
  151. data/lib/capybara/spec/session/click_link_spec.rb +78 -55
  152. data/lib/capybara/spec/session/current_scope_spec.rb +7 -7
  153. data/lib/capybara/spec/session/current_url_spec.rb +44 -37
  154. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
  155. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
  156. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
  157. data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
  158. data/lib/capybara/spec/session/element/match_xpath_spec.rb +8 -6
  159. data/lib/capybara/spec/session/element/matches_selector_spec.rb +70 -56
  160. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
  161. data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
  162. data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
  163. data/lib/capybara/spec/session/fill_in_spec.rb +104 -44
  164. data/lib/capybara/spec/session/find_button_spec.rb +23 -23
  165. data/lib/capybara/spec/session/find_by_id_spec.rb +8 -8
  166. data/lib/capybara/spec/session/find_field_spec.rb +33 -31
  167. data/lib/capybara/spec/session/find_link_spec.rb +32 -14
  168. data/lib/capybara/spec/session/find_spec.rb +236 -141
  169. data/lib/capybara/spec/session/first_spec.rb +44 -43
  170. data/lib/capybara/spec/session/frame/frame_title_spec.rb +6 -6
  171. data/lib/capybara/spec/session/frame/frame_url_spec.rb +6 -6
  172. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +32 -20
  173. data/lib/capybara/spec/session/frame/within_frame_spec.rb +44 -19
  174. data/lib/capybara/spec/session/go_back_spec.rb +1 -1
  175. data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
  176. data/lib/capybara/spec/session/has_all_selectors_spec.rb +18 -18
  177. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  178. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  179. data/lib/capybara/spec/session/has_button_spec.rb +92 -12
  180. data/lib/capybara/spec/session/has_css_spec.rb +271 -137
  181. data/lib/capybara/spec/session/has_current_path_spec.rb +48 -33
  182. data/lib/capybara/spec/session/has_field_spec.rb +137 -58
  183. data/lib/capybara/spec/session/has_link_spec.rb +30 -6
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +26 -24
  185. data/lib/capybara/spec/session/has_select_spec.rb +75 -47
  186. data/lib/capybara/spec/session/has_selector_spec.rb +102 -69
  187. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  188. data/lib/capybara/spec/session/has_table_spec.rb +170 -4
  189. data/lib/capybara/spec/session/has_text_spec.rb +108 -52
  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 +35 -0
  195. data/lib/capybara/spec/session/node_spec.rb +871 -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 +52 -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 +117 -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 +40 -21
  212. data/lib/capybara/spec/session/unselect_spec.rb +37 -37
  213. data/lib/capybara/spec/session/visit_spec.rb +59 -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 +10 -7
  221. data/lib/capybara/spec/session/window/within_window_spec.rb +17 -16
  222. data/lib/capybara/spec/session/within_spec.rb +69 -44
  223. data/lib/capybara/spec/spec_helper.rb +41 -53
  224. data/lib/capybara/spec/test_app.rb +79 -40
  225. data/lib/capybara/spec/views/animated.erb +49 -0
  226. data/lib/capybara/spec/views/form.erb +134 -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 +43 -10
  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_other.erb +6 -0
  255. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  256. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  257. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  258. data/lib/capybara/spec/views/with_windows.erb +1 -1
  259. data/lib/capybara/spec/views/within_frames.erb +1 -1
  260. data/lib/capybara/version.rb +1 -1
  261. data/lib/capybara/window.rb +31 -25
  262. data/lib/capybara.rb +120 -100
  263. data/spec/basic_node_spec.rb +59 -34
  264. data/spec/capybara_spec.rb +54 -52
  265. data/spec/css_builder_spec.rb +101 -0
  266. data/spec/css_splitter_spec.rb +38 -0
  267. data/spec/dsl_spec.rb +80 -53
  268. data/spec/filter_set_spec.rb +24 -7
  269. data/spec/fixtures/certificate.pem +25 -0
  270. data/spec/fixtures/key.pem +27 -0
  271. data/spec/fixtures/selenium_driver_rspec_failure.rb +4 -4
  272. data/spec/fixtures/selenium_driver_rspec_success.rb +4 -4
  273. data/spec/minitest_spec.rb +38 -5
  274. data/spec/minitest_spec_spec.rb +88 -62
  275. data/spec/per_session_config_spec.rb +5 -5
  276. data/spec/rack_test_spec.rb +169 -115
  277. data/spec/regexp_dissassembler_spec.rb +250 -0
  278. data/spec/result_spec.rb +86 -33
  279. data/spec/rspec/features_spec.rb +26 -23
  280. data/spec/rspec/scenarios_spec.rb +8 -4
  281. data/spec/rspec/shared_spec_matchers.rb +393 -363
  282. data/spec/rspec/views_spec.rb +4 -3
  283. data/spec/rspec_matchers_spec.rb +10 -10
  284. data/spec/rspec_spec.rb +109 -85
  285. data/spec/sauce_spec_chrome.rb +43 -0
  286. data/spec/selector_spec.rb +391 -61
  287. data/spec/selenium_spec_chrome.rb +180 -41
  288. data/spec/selenium_spec_chrome_remote.rb +101 -0
  289. data/spec/selenium_spec_edge.rb +28 -8
  290. data/spec/selenium_spec_firefox.rb +211 -0
  291. data/spec/selenium_spec_firefox_remote.rb +80 -0
  292. data/spec/selenium_spec_ie.rb +127 -11
  293. data/spec/selenium_spec_safari.rb +156 -0
  294. data/spec/server_spec.rb +177 -78
  295. data/spec/session_spec.rb +52 -16
  296. data/spec/shared_selenium_node.rb +79 -0
  297. data/spec/shared_selenium_session.rb +455 -123
  298. data/spec/spec_helper.rb +91 -2
  299. data/spec/xpath_builder_spec.rb +93 -0
  300. metadata +343 -42
  301. data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
  302. data/.yard/templates_custom/default/class/html/setup.rb +0 -17
  303. data/.yard/yard_extensions.rb +0 -78
  304. data/lib/capybara/rspec/compound.rb +0 -90
  305. data/lib/capybara/spec/session/assert_selector.rb +0 -149
  306. data/lib/capybara/spec/session/source_spec.rb +0 -0
  307. data/lib/capybara/spec/views/with_title.erb +0 -5
  308. 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,332 @@ 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\\"]"')
215
234
  end
216
235
 
217
- it "should accept an XPath instance" do
236
+ it 'should accept an XPath instance' do
218
237
  @session.visit('/form')
219
- @xpath = Capybara::Selector.all[:fillable_field].call('First Name')
238
+ @xpath = Capybara::Selector.new(:fillable_field, config: {}, format: :xpath).call('First Name')
220
239
  expect(@xpath).to be_a(::XPath::Union)
221
240
  expect(@session.find(@xpath).value).to eq('John')
222
241
  end
223
242
 
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")
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')
227
246
  expect do
228
- @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")], exact: true)
247
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is('est_fiel')], exact: true)
229
248
  end.to raise_error(Capybara::ElementNotFound)
230
249
  end
231
250
 
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")
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')
235
254
  end
236
255
 
237
- it "defaults to `Capybara.exact`" do
256
+ it 'defaults to `Capybara.exact`' do
238
257
  Capybara.exact = true
239
258
  expect do
240
- @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")])
259
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is('est_fiel')])
241
260
  end.to raise_error(Capybara::ElementNotFound)
242
261
  Capybara.exact = false
243
- @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is("est_fiel")])
262
+ @session.find(:xpath, XPath.descendant(:input)[XPath.attr(:id).is('est_fiel')])
244
263
  end
245
264
 
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)
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
250
268
  end
251
269
  end
252
270
 
253
- context "with :match option" do
254
- context "when set to `one`" do
255
- it "raises an error when multiple matches exist" do
271
+ context 'with :match option' do
272
+ context 'when set to `one`' do
273
+ it 'raises an error when multiple matches exist' do
256
274
  expect do
257
- @session.find(:css, ".multiple", match: :one)
275
+ @session.find(:css, '.multiple', match: :one)
258
276
  end.to raise_error(Capybara::Ambiguous)
259
277
  end
260
- it "raises an error even if there the match is exact and the others are inexact" do
278
+
279
+ it 'raises an error even if there the match is exact and the others are inexact' do
261
280
  expect do
262
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular")], exact: false, match: :one)
281
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], exact: false, match: :one)
263
282
  end.to raise_error(Capybara::Ambiguous)
264
283
  end
265
- it "returns the element if there is only one" do
266
- expect(@session.find(:css, ".singular", match: :one).text).to eq("singular")
284
+
285
+ it 'returns the element if there is only one' do
286
+ expect(@session.find(:css, '.singular', match: :one).text).to eq('singular')
267
287
  end
268
- it "raises an error if there is no match" do
288
+
289
+ it 'raises an error if there is no match' do
269
290
  expect do
270
- @session.find(:css, ".does-not-exist", match: :one)
291
+ @session.find(:css, '.does-not-exist', match: :one)
271
292
  end.to raise_error(Capybara::ElementNotFound)
272
293
  end
273
294
  end
274
295
 
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")
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')
278
299
  end
279
- it "raises an error if there is no match" do
300
+
301
+ it 'raises an error if there is no match' do
280
302
  expect do
281
- @session.find(:css, ".does-not-exist", match: :first)
303
+ @session.find(:css, '.does-not-exist', match: :first)
282
304
  end.to raise_error(Capybara::ElementNotFound)
283
305
  end
284
306
  end
285
307
 
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
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
289
311
  expect do
290
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("multiple")], match: :smart, exact: false)
312
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :smart, exact: false)
291
313
  end.to raise_error(Capybara::Ambiguous)
292
314
  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")
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')
296
319
  end
297
- it "raises an error when there are multiple inexact matches" do
320
+
321
+ it 'raises an error when there are multiple inexact matches' do
298
322
  expect do
299
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], match: :smart, exact: false)
323
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :smart, exact: false)
300
324
  end.to raise_error(Capybara::Ambiguous)
301
325
  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")
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')
305
330
  end
306
- it "raises an error if there is no match" do
331
+
332
+ it 'raises an error if there is no match' do
307
333
  expect do
308
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("does-not-exist")], match: :smart, exact: false)
334
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :smart, exact: false)
309
335
  end.to raise_error(Capybara::ElementNotFound)
310
336
  end
311
337
  end
312
338
 
313
- context "with `exact` set to `true`" do
314
- it "raises an error when there are multiple exact matches" do
339
+ context 'with `exact` set to `true`' do
340
+ it 'raises an error when there are multiple exact matches' do
315
341
  expect do
316
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("multiple")], match: :smart, exact: true)
342
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :smart, exact: true)
317
343
  end.to raise_error(Capybara::Ambiguous)
318
344
  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")
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')
322
349
  end
323
- it "raises an error when there are multiple inexact matches" do
350
+
351
+ it 'raises an error when there are multiple inexact matches' do
324
352
  expect do
325
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], match: :smart, exact: true)
353
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :smart, exact: true)
326
354
  end.to raise_error(Capybara::ElementNotFound)
327
355
  end
328
- it "raises an error when there is a single inexact matches" do
356
+
357
+ it 'raises an error when there is a single inexact matches' do
329
358
  expect do
330
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular but")], match: :smart, exact: true)
359
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :smart, exact: true)
331
360
  end.to raise_error(Capybara::ElementNotFound)
332
361
  end
333
- it "raises an error if there is no match" do
362
+
363
+ it 'raises an error if there is no match' do
334
364
  expect do
335
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("does-not-exist")], match: :smart, exact: true)
365
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :smart, exact: true)
336
366
  end.to raise_error(Capybara::ElementNotFound)
337
367
  end
338
368
  end
339
369
  end
340
370
 
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")
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')
346
376
  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")
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')
350
381
  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")
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')
354
386
  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")
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')
358
391
  end
359
- it "raises an error if there is no match" do
392
+
393
+ it 'raises an error if there is no match' do
360
394
  expect do
361
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("does-not-exist")], match: :prefer_exact, exact: false)
395
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :prefer_exact, exact: false)
362
396
  end.to raise_error(Capybara::ElementNotFound)
363
397
  end
364
398
  end
365
399
 
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")
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')
370
404
  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")
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')
374
409
  end
375
- it "raises an error if there are multiple inexact matches" do
410
+
411
+ it 'raises an error if there are multiple inexact matches' do
376
412
  expect do
377
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singul")], match: :prefer_exact, exact: true)
413
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :prefer_exact, exact: true)
378
414
  end.to raise_error(Capybara::ElementNotFound)
379
415
  end
380
- it "raises an error if there is a single inexact match" do
416
+
417
+ it 'raises an error if there is a single inexact match' do
381
418
  expect do
382
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("almost_singular but")], match: :prefer_exact, exact: true)
419
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :prefer_exact, exact: true)
383
420
  end.to raise_error(Capybara::ElementNotFound)
384
421
  end
385
- it "raises an error if there is no match" do
422
+
423
+ it 'raises an error if there is no match' do
386
424
  expect do
387
- @session.find(:xpath, XPath.descendant[XPath.attr(:class).is("does-not-exist")], match: :prefer_exact, exact: true)
425
+ @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :prefer_exact, exact: true)
388
426
  end.to raise_error(Capybara::ElementNotFound)
389
427
  end
390
428
  end
391
429
  end
392
430
 
393
- it "defaults to `Capybara.match`" do
431
+ it 'defaults to `Capybara.match`' do
394
432
  Capybara.match = :one
395
433
  expect do
396
- @session.find(:css, ".multiple")
434
+ @session.find(:css, '.multiple')
397
435
  end.to raise_error(Capybara::Ambiguous)
398
436
  Capybara.match = :first
399
- expect(@session.find(:css, ".multiple").text).to eq("multiple one")
437
+ expect(@session.find(:css, '.multiple').text).to eq('multiple one')
400
438
  end
401
439
 
402
- it "raises an error when unknown option given" do
440
+ it 'raises an error when unknown option given' do
403
441
  expect do
404
- @session.find(:css, ".singular", match: :schmoo)
442
+ @session.find(:css, '.singular', match: :schmoo)
405
443
  end.to raise_error(ArgumentError)
406
444
  end
407
445
  end
408
446
 
409
- it "supports a custom filter block" do
447
+ it 'supports a custom filter block' do
410
448
  expect(@session.find(:css, 'input', &:disabled?)[:name]).to eq('disabled_text')
411
449
  end
412
450
 
413
- context "within a scope" do
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
414
487
  before do
415
488
  @session.visit('/with_scope')
416
489
  end
417
490
 
418
- it "should find the an element using the given locator" do
491
+ it 'should find the an element using the given locator' do
419
492
  @session.within(:xpath, "//div[@id='for_bar']") do
420
493
  expect(@session.find('.//li[1]').text).to match(/With Simple HTML/)
421
494
  end
422
495
  end
423
496
 
424
- it "should support pseudo selectors" do
497
+ it 'should support pseudo selectors' do
425
498
  @session.within(:xpath, "//div[@id='for_bar']") do
426
499
  expect(@session.find(:css, 'input:disabled').value).to eq('James')
427
500
  end
428
501
  end
429
502
  end
430
503
 
431
- it "should raise if selector type is unknown" do
504
+ it 'should raise if selector type is unknown' do
432
505
  expect do
433
506
  @session.find(:unknown, '//h1')
434
507
  end.to raise_error(ArgumentError)
435
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
436
531
  end