capybara 2.7.0 → 3.35.3

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 (318) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +1 -0
  3. data/History.md +1147 -11
  4. data/License.txt +1 -1
  5. data/README.md +252 -131
  6. data/lib/capybara/config.rb +92 -0
  7. data/lib/capybara/cucumber.rb +3 -3
  8. data/lib/capybara/driver/base.rb +52 -21
  9. data/lib/capybara/driver/node.rb +48 -14
  10. data/lib/capybara/dsl.rb +16 -9
  11. data/lib/capybara/helpers.rb +72 -81
  12. data/lib/capybara/minitest/spec.rb +267 -0
  13. data/lib/capybara/minitest.rb +385 -0
  14. data/lib/capybara/node/actions.rb +337 -89
  15. data/lib/capybara/node/base.rb +50 -32
  16. data/lib/capybara/node/document.rb +19 -3
  17. data/lib/capybara/node/document_matchers.rb +22 -24
  18. data/lib/capybara/node/element.rb +388 -125
  19. data/lib/capybara/node/finders.rb +231 -121
  20. data/lib/capybara/node/matchers.rb +503 -217
  21. data/lib/capybara/node/simple.rb +64 -27
  22. data/lib/capybara/queries/ancestor_query.rb +27 -0
  23. data/lib/capybara/queries/base_query.rb +87 -11
  24. data/lib/capybara/queries/current_path_query.rb +24 -24
  25. data/lib/capybara/queries/match_query.rb +15 -10
  26. data/lib/capybara/queries/selector_query.rb +675 -81
  27. data/lib/capybara/queries/sibling_query.rb +26 -0
  28. data/lib/capybara/queries/style_query.rb +45 -0
  29. data/lib/capybara/queries/text_query.rb +88 -20
  30. data/lib/capybara/queries/title_query.rb +9 -11
  31. data/lib/capybara/rack_test/browser.rb +63 -39
  32. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  33. data/lib/capybara/rack_test/driver.rb +26 -16
  34. data/lib/capybara/rack_test/errors.rb +6 -0
  35. data/lib/capybara/rack_test/form.rb +73 -58
  36. data/lib/capybara/rack_test/node.rb +187 -67
  37. data/lib/capybara/rails.rb +4 -8
  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 +142 -14
  43. data/lib/capybara/rspec/features.rb +17 -42
  44. data/lib/capybara/rspec/matcher_proxies.rb +82 -0
  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 +143 -244
  59. data/lib/capybara/rspec.rb +10 -12
  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 +102 -0
  63. data/lib/capybara/selector/definition/button.rb +63 -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 +278 -0
  85. data/lib/capybara/selector/filter.rb +3 -46
  86. data/lib/capybara/selector/filter_set.rb +124 -0
  87. data/lib/capybara/selector/filters/base.rb +77 -0
  88. data/lib/capybara/selector/filters/expression_filter.rb +22 -0
  89. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  90. data/lib/capybara/selector/filters/node_filter.rb +31 -0
  91. data/lib/capybara/selector/regexp_disassembler.rb +214 -0
  92. data/lib/capybara/selector/selector.rb +155 -0
  93. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  94. data/lib/capybara/selector.rb +232 -369
  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 +380 -142
  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 +528 -97
  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 +63 -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 +74 -71
  127. data/lib/capybara/session/config.rb +126 -0
  128. data/lib/capybara/session/matchers.rb +44 -27
  129. data/lib/capybara/session.rb +500 -297
  130. data/lib/capybara/spec/fixtures/no_extension +1 -0
  131. data/lib/capybara/spec/public/jquery.js +5 -5
  132. data/lib/capybara/spec/public/offset.js +6 -0
  133. data/lib/capybara/spec/public/test.js +168 -14
  134. data/lib/capybara/spec/session/accept_alert_spec.rb +37 -14
  135. data/lib/capybara/spec/session/accept_confirm_spec.rb +7 -6
  136. data/lib/capybara/spec/session/accept_prompt_spec.rb +38 -10
  137. data/lib/capybara/spec/session/all_spec.rb +179 -59
  138. data/lib/capybara/spec/session/ancestor_spec.rb +88 -0
  139. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +140 -0
  140. data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
  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_spec.rb +258 -0
  144. data/lib/capybara/spec/session/assert_title_spec.rb +93 -0
  145. data/lib/capybara/spec/session/attach_file_spec.rb +154 -48
  146. data/lib/capybara/spec/session/body_spec.rb +12 -13
  147. data/lib/capybara/spec/session/check_spec.rb +168 -41
  148. data/lib/capybara/spec/session/choose_spec.rb +75 -23
  149. data/lib/capybara/spec/session/click_button_spec.rb +243 -175
  150. data/lib/capybara/spec/session/click_link_or_button_spec.rb +57 -32
  151. data/lib/capybara/spec/session/click_link_spec.rb +100 -53
  152. data/lib/capybara/spec/session/current_scope_spec.rb +11 -10
  153. data/lib/capybara/spec/session/current_url_spec.rb +61 -35
  154. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +7 -7
  155. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +5 -4
  156. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +13 -6
  157. data/lib/capybara/spec/session/element/match_css_spec.rb +21 -7
  158. data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
  159. data/lib/capybara/spec/session/element/matches_selector_spec.rb +91 -34
  160. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
  161. data/lib/capybara/spec/session/evaluate_script_spec.rb +45 -3
  162. data/lib/capybara/spec/session/execute_script_spec.rb +24 -4
  163. data/lib/capybara/spec/session/fill_in_spec.rb +166 -64
  164. data/lib/capybara/spec/session/find_button_spec.rb +37 -18
  165. data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
  166. data/lib/capybara/spec/session/find_field_spec.rb +57 -34
  167. data/lib/capybara/spec/session/find_link_spec.rb +47 -10
  168. data/lib/capybara/spec/session/find_spec.rb +290 -144
  169. data/lib/capybara/spec/session/first_spec.rb +91 -48
  170. data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
  171. data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  172. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +116 -0
  173. data/lib/capybara/spec/session/frame/within_frame_spec.rb +112 -0
  174. data/lib/capybara/spec/session/go_back_spec.rb +3 -2
  175. data/lib/capybara/spec/session/go_forward_spec.rb +3 -2
  176. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  177. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  178. data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
  179. data/lib/capybara/spec/session/has_button_spec.rb +76 -19
  180. data/lib/capybara/spec/session/has_css_spec.rb +277 -131
  181. data/lib/capybara/spec/session/has_current_path_spec.rb +98 -26
  182. data/lib/capybara/spec/session/has_field_spec.rb +177 -107
  183. data/lib/capybara/spec/session/has_link_spec.rb +13 -12
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
  185. data/lib/capybara/spec/session/has_select_spec.rb +191 -95
  186. data/lib/capybara/spec/session/has_selector_spec.rb +128 -64
  187. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  188. data/lib/capybara/spec/session/has_table_spec.rb +172 -5
  189. data/lib/capybara/spec/session/has_text_spec.rb +126 -60
  190. data/lib/capybara/spec/session/has_title_spec.rb +35 -12
  191. data/lib/capybara/spec/session/has_xpath_spec.rb +74 -53
  192. data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
  193. data/lib/capybara/spec/session/html_spec.rb +14 -6
  194. data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
  195. data/lib/capybara/spec/session/node_spec.rb +1028 -131
  196. data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
  197. data/lib/capybara/spec/session/refresh_spec.rb +34 -0
  198. data/lib/capybara/spec/session/reset_session_spec.rb +75 -34
  199. data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
  200. data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
  201. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +11 -15
  202. data/lib/capybara/spec/session/save_page_spec.rb +42 -55
  203. data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
  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 +112 -85
  207. data/lib/capybara/spec/session/selectors_spec.rb +71 -8
  208. data/lib/capybara/spec/session/sibling_spec.rb +52 -0
  209. data/lib/capybara/spec/session/text_spec.rb +38 -23
  210. data/lib/capybara/spec/session/title_spec.rb +17 -5
  211. data/lib/capybara/spec/session/uncheck_spec.rb +71 -12
  212. data/lib/capybara/spec/session/unselect_spec.rb +44 -43
  213. data/lib/capybara/spec/session/visit_spec.rb +99 -32
  214. data/lib/capybara/spec/session/window/become_closed_spec.rb +33 -29
  215. data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
  216. data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
  217. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +39 -30
  218. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +17 -10
  219. data/lib/capybara/spec/session/window/window_spec.rb +121 -73
  220. data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
  221. data/lib/capybara/spec/session/window/within_window_spec.rb +52 -82
  222. data/lib/capybara/spec/session/within_spec.rb +76 -43
  223. data/lib/capybara/spec/spec_helper.rb +67 -33
  224. data/lib/capybara/spec/test_app.rb +85 -36
  225. data/lib/capybara/spec/views/animated.erb +49 -0
  226. data/lib/capybara/spec/views/buttons.erb +1 -1
  227. data/lib/capybara/spec/views/fieldsets.erb +1 -1
  228. data/lib/capybara/spec/views/form.erb +227 -20
  229. data/lib/capybara/spec/views/frame_child.erb +10 -2
  230. data/lib/capybara/spec/views/frame_one.erb +2 -1
  231. data/lib/capybara/spec/views/frame_parent.erb +2 -2
  232. data/lib/capybara/spec/views/frame_two.erb +1 -1
  233. data/lib/capybara/spec/views/header_links.erb +1 -1
  234. data/lib/capybara/spec/views/host_links.erb +1 -1
  235. data/lib/capybara/spec/views/initial_alert.erb +10 -0
  236. data/lib/capybara/spec/views/obscured.erb +47 -0
  237. data/lib/capybara/spec/views/offset.erb +32 -0
  238. data/lib/capybara/spec/views/path.erb +1 -1
  239. data/lib/capybara/spec/views/popup_one.erb +1 -1
  240. data/lib/capybara/spec/views/popup_two.erb +1 -1
  241. data/lib/capybara/spec/views/postback.erb +1 -1
  242. data/lib/capybara/spec/views/react.erb +45 -0
  243. data/lib/capybara/spec/views/scroll.erb +20 -0
  244. data/lib/capybara/spec/views/spatial.erb +31 -0
  245. data/lib/capybara/spec/views/tables.erb +69 -2
  246. data/lib/capybara/spec/views/with_animation.erb +82 -0
  247. data/lib/capybara/spec/views/with_base_tag.erb +1 -1
  248. data/lib/capybara/spec/views/with_count.erb +1 -1
  249. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  250. data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
  251. data/lib/capybara/spec/views/with_hover.erb +7 -1
  252. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  253. data/lib/capybara/spec/views/with_html.erb +100 -10
  254. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  255. data/lib/capybara/spec/views/with_html_entities.erb +1 -1
  256. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  257. data/lib/capybara/spec/views/with_js.erb +49 -3
  258. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  259. data/lib/capybara/spec/views/with_namespace.erb +20 -0
  260. data/lib/capybara/spec/views/with_scope.erb +1 -1
  261. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  262. data/lib/capybara/spec/views/with_simple_html.erb +1 -1
  263. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  264. data/lib/capybara/spec/views/with_title.erb +1 -1
  265. data/lib/capybara/spec/views/with_unload_alert.erb +3 -1
  266. data/lib/capybara/spec/views/with_windows.erb +7 -1
  267. data/lib/capybara/spec/views/within_frames.erb +6 -3
  268. data/lib/capybara/version.rb +2 -1
  269. data/lib/capybara/window.rb +39 -21
  270. data/lib/capybara.rb +208 -186
  271. data/spec/basic_node_spec.rb +52 -39
  272. data/spec/capybara_spec.rb +72 -50
  273. data/spec/css_builder_spec.rb +101 -0
  274. data/spec/css_splitter_spec.rb +38 -0
  275. data/spec/dsl_spec.rb +81 -61
  276. data/spec/filter_set_spec.rb +46 -0
  277. data/spec/fixtures/capybara.csv +1 -0
  278. data/spec/fixtures/certificate.pem +25 -0
  279. data/spec/fixtures/key.pem +27 -0
  280. data/spec/fixtures/selenium_driver_rspec_failure.rb +7 -3
  281. data/spec/fixtures/selenium_driver_rspec_success.rb +7 -3
  282. data/spec/minitest_spec.rb +164 -0
  283. data/spec/minitest_spec_spec.rb +162 -0
  284. data/spec/per_session_config_spec.rb +68 -0
  285. data/spec/rack_test_spec.rb +189 -96
  286. data/spec/regexp_dissassembler_spec.rb +250 -0
  287. data/spec/result_spec.rb +143 -13
  288. data/spec/rspec/features_spec.rb +38 -32
  289. data/spec/rspec/scenarios_spec.rb +9 -7
  290. data/spec/rspec/shared_spec_matchers.rb +959 -0
  291. data/spec/rspec/views_spec.rb +9 -3
  292. data/spec/rspec_matchers_spec.rb +62 -0
  293. data/spec/rspec_spec.rb +127 -30
  294. data/spec/sauce_spec_chrome.rb +43 -0
  295. data/spec/selector_spec.rb +458 -37
  296. data/spec/selenium_spec_chrome.rb +196 -9
  297. data/spec/selenium_spec_chrome_remote.rb +100 -0
  298. data/spec/selenium_spec_edge.rb +47 -0
  299. data/spec/selenium_spec_firefox.rb +210 -0
  300. data/spec/selenium_spec_firefox_remote.rb +80 -0
  301. data/spec/selenium_spec_ie.rb +150 -0
  302. data/spec/selenium_spec_safari.rb +148 -0
  303. data/spec/server_spec.rb +200 -101
  304. data/spec/session_spec.rb +91 -0
  305. data/spec/shared_selenium_node.rb +83 -0
  306. data/spec/shared_selenium_session.rb +558 -0
  307. data/spec/spec_helper.rb +94 -2
  308. data/spec/xpath_builder_spec.rb +93 -0
  309. metadata +420 -60
  310. data/lib/capybara/query.rb +0 -7
  311. data/lib/capybara/spec/session/assert_current_path.rb +0 -60
  312. data/lib/capybara/spec/session/assert_selector.rb +0 -148
  313. data/lib/capybara/spec/session/assert_text.rb +0 -196
  314. data/lib/capybara/spec/session/assert_title.rb +0 -70
  315. data/lib/capybara/spec/session/source_spec.rb +0 -0
  316. data/lib/capybara/spec/session/within_frame_spec.rb +0 -53
  317. data/spec/rspec/matchers_spec.rb +0 -827
  318. data/spec/selenium_spec.rb +0 -151
@@ -1,113 +1,156 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  Capybara::SpecHelper.spec '#first' do
3
4
  before do
4
5
  @session.visit('/with_html')
5
6
  end
6
7
 
7
- it "should find the first element using the given locator" do
8
+ it 'should find the first element using the given locator' do
8
9
  expect(@session.first('//h1').text).to eq('This is a test')
9
- expect(@session.first("//input[@id='test_field']")[:value]).to eq('monkey')
10
+ expect(@session.first("//input[@id='test_field']").value).to eq('monkey')
11
+ end
12
+
13
+ it 'should raise ElementNotFound when nothing was found' do
14
+ expect do
15
+ @session.first('//div[@id="nosuchthing"]')
16
+ end.to raise_error Capybara::ElementNotFound
10
17
  end
11
18
 
12
- it "should return nil when nothing was found" do
13
- expect(@session.first('//div[@id="nosuchthing"]')).to be_nil
19
+ it 'should return nil when nothing was found if count options allow no results' do
20
+ expect(@session.first('//div[@id="nosuchthing"]', minimum: 0)).to be_nil
21
+ expect(@session.first('//div[@id="nosuchthing"]', count: 0)).to be_nil
22
+ expect(@session.first('//div[@id="nosuchthing"]', between: (0..3))).to be_nil
14
23
  end
15
24
 
16
- it "should accept an XPath instance" do
25
+ it 'should accept an XPath instance' do
17
26
  @session.visit('/form')
18
- @xpath = XPath::HTML.fillable_field('First Name')
27
+ @xpath = Capybara::Selector.new(:fillable_field, config: {}, format: :xpath).call('First Name')
28
+ expect(@xpath).to be_a(::XPath::Union)
19
29
  expect(@session.first(@xpath).value).to eq('John')
20
30
  end
21
31
 
22
- context "with css selectors" do
23
- it "should find the first element using the given selector" do
32
+ it 'should raise when unused parameters are passed' do
33
+ expect do
34
+ @session.first(:css, 'h1', 'unused text')
35
+ end.to raise_error ArgumentError, /Unused parameters passed.*unused text/
36
+ end
37
+
38
+ context 'with css selectors' do
39
+ it 'should find the first element using the given selector' do
24
40
  expect(@session.first(:css, 'h1').text).to eq('This is a test')
25
- expect(@session.first(:css, "input[id='test_field']")[:value]).to eq('monkey')
41
+ expect(@session.first(:css, "input[id='test_field']").value).to eq('monkey')
26
42
  end
27
43
  end
28
44
 
29
- context "with xpath selectors" do
30
- it "should find the first element using the given locator" do
45
+ context 'with xpath selectors' do
46
+ it 'should find the first element using the given locator' do
31
47
  expect(@session.first(:xpath, '//h1').text).to eq('This is a test')
32
- expect(@session.first(:xpath, "//input[@id='test_field']")[:value]).to eq('monkey')
48
+ expect(@session.first(:xpath, "//input[@id='test_field']").value).to eq('monkey')
33
49
  end
34
50
  end
35
51
 
36
- context "with css as default selector" do
52
+ context 'with css as default selector' do
37
53
  before { Capybara.default_selector = :css }
38
- it "should find the first element using the given locator" do
54
+
55
+ it 'should find the first element using the given locator' do
39
56
  expect(@session.first('h1').text).to eq('This is a test')
40
- expect(@session.first("input[id='test_field']")[:value]).to eq('monkey')
57
+ expect(@session.first("input[id='test_field']").value).to eq('monkey')
41
58
  end
42
59
  end
43
60
 
44
- context "with visible filter" do
45
- it "should only find visible nodes when true" do
46
- expect(@session.first(:css, "a#invisible", :visible => true)).to be_nil
61
+ context 'with visible filter' do
62
+ it 'should only find visible nodes when true' do
63
+ expect do
64
+ @session.first(:css, 'a#invisible', visible: true)
65
+ end.to raise_error Capybara::ElementNotFound
47
66
  end
48
67
 
49
- it "should find nodes regardless of whether they are invisible when false" do
50
- expect(@session.first(:css, "a#invisible", :visible => false)).not_to be_nil
51
- expect(@session.first(:css, "a#visible", :visible => false)).not_to be_nil
68
+ it 'should find nodes regardless of whether they are invisible when false' do
69
+ expect(@session.first(:css, 'a#invisible', visible: false)).to be_truthy
70
+ expect(@session.first(:css, 'a#invisible', visible: false, text: 'hidden link')).to be_truthy
71
+ expect(@session.first(:css, 'a#visible', visible: false)).to be_truthy
52
72
  end
53
73
 
54
- it "should find nodes regardless of whether they are invisible when :all" do
55
- expect(@session.first(:css, "a#invisible", :visible => :all)).not_to be_nil
56
- expect(@session.first(:css, "a#visible", :visible => :all)).not_to be_nil
74
+ it 'should find nodes regardless of whether they are invisible when :all' do
75
+ expect(@session.first(:css, 'a#invisible', visible: :all)).to be_truthy
76
+ expect(@session.first(:css, 'a#invisible', visible: :all, text: 'hidden link')).to be_truthy
77
+ expect(@session.first(:css, 'a#visible', visible: :all)).to be_truthy
57
78
  end
58
79
 
59
- it "should find only hidden nodes when :hidden" do
60
- expect(@session.first(:css, "a#invisible", :visible => :hidden)).not_to be_nil
61
- expect(@session.first(:css, "a#visible", :visible => :hidden)).to be_nil
80
+ it 'should find only hidden nodes when :hidden' do
81
+ expect(@session.first(:css, 'a#invisible', visible: :hidden)).to be_truthy
82
+ expect(@session.first(:css, 'a#invisible', visible: :hidden, text: 'hidden link')).to be_truthy
83
+ expect do
84
+ @session.first(:css, 'a#invisible', visible: :hidden, text: 'not hidden link')
85
+ end.to raise_error Capybara::ElementNotFound
86
+ expect do
87
+ @session.first(:css, 'a#visible', visible: :hidden)
88
+ end.to raise_error Capybara::ElementNotFound
62
89
  end
63
90
 
64
- it "should find only visible nodes when :visible" do
65
- expect(@session.first(:css, "a#invisible", :visible => :visible)).to be_nil
66
- expect(@session.first(:css, "a#visible", :visible => :visible)).not_to be_nil
91
+ it 'should find only visible nodes when :visible' do
92
+ expect do
93
+ @session.first(:css, 'a#invisible', visible: :visible)
94
+ end.to raise_error Capybara::ElementNotFound
95
+ expect do
96
+ @session.first(:css, 'a#invisible', visible: :visible, text: 'hidden link')
97
+ end.to raise_error Capybara::ElementNotFound
98
+ expect(@session.first(:css, 'a#visible', visible: :visible)).to be_truthy
67
99
  end
68
100
 
69
- it "should default to Capybara.ignore_hidden_elements" do
101
+ it 'should default to Capybara.ignore_hidden_elements' do
70
102
  Capybara.ignore_hidden_elements = true
71
- expect(@session.first(:css, "a#invisible")).to be_nil
103
+ expect do
104
+ @session.first(:css, 'a#invisible')
105
+ end.to raise_error Capybara::ElementNotFound
72
106
  Capybara.ignore_hidden_elements = false
73
- expect(@session.first(:css, "a#invisible")).not_to be_nil
74
- expect(@session.first(:css, "a")).not_to be_nil
107
+ expect(@session.first(:css, 'a#invisible')).to be_truthy
108
+ expect(@session.first(:css, 'a')).to be_truthy
75
109
  end
76
110
  end
77
111
 
78
- context "within a scope" do
112
+ context 'within a scope' do
79
113
  before do
80
114
  @session.visit('/with_scope')
81
115
  end
82
116
 
83
- it "should find the first element using the given locator" do
117
+ it 'should find the first element using the given locator' do
84
118
  @session.within(:xpath, "//div[@id='for_bar']") do
85
- expect(@session.first('.//form')).not_to be_nil
119
+ expect(@session.first('.//form')).to be_truthy
86
120
  end
87
121
  end
88
122
  end
89
123
 
90
- context "with Capybara.wait_on_first_by_default", requires: [:js] do
124
+ context 'waiting behavior', requires: [:js] do
91
125
  before do
92
126
  @session.visit('/with_js')
93
127
  end
94
128
 
95
- it "should not wait if false" do
96
- Capybara.wait_on_first_by_default = false
129
+ it 'should not wait if minimum: 0' do
97
130
  @session.click_link('clickable')
98
- expect(@session.first(:css, 'a#has-been-clicked')).to be_nil
131
+ Capybara.using_wait_time(3) do
132
+ start_time = Time.now
133
+ expect(@session.first(:css, 'a#has-been-clicked', minimum: 0)).to be_nil
134
+ expect(Time.now - start_time).to be < 3
135
+ end
99
136
  end
100
137
 
101
- it "should wait for at least one match if true" do
102
- Capybara.wait_on_first_by_default = true
103
- @session.click_link('clickable')
104
- expect(@session.first(:css, 'a#has-been-clicked')).not_to be_nil
138
+ it 'should wait for at least one match by default' do
139
+ Capybara.using_wait_time(3) do
140
+ @session.click_link('clickable')
141
+ expect(@session.first(:css, 'a#has-been-clicked')).not_to be_nil
142
+ end
105
143
  end
106
144
 
107
- it "should return nil after waiting if no match" do
108
- Capybara.wait_on_first_by_default = true
145
+ it 'should raise an error after waiting if no match' do
109
146
  @session.click_link('clickable')
110
- expect(@session.first(:css, 'a#not-a-real-link')).to be_nil
147
+ Capybara.using_wait_time(3) do
148
+ start_time = Time.now
149
+ expect do
150
+ @session.first(:css, 'a#not-a-real-link')
151
+ end.to raise_error Capybara::ElementNotFound
152
+ expect(Time.now - start_time).to be > 3
153
+ end
111
154
  end
112
155
  end
113
156
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ Capybara::SpecHelper.spec '#frame_title', requires: [:frames] do
4
+ before do
5
+ @session.visit('/within_frames')
6
+ end
7
+
8
+ it 'should return the title in a frame' do
9
+ @session.within_frame('frameOne') do
10
+ expect(@session.driver.frame_title).to eq 'This is the title of frame one'
11
+ end
12
+ end
13
+
14
+ it 'should return the title in FrameTwo' do
15
+ @session.within_frame('frameTwo') do
16
+ expect(@session.driver.frame_title).to eq 'This is the title of frame two'
17
+ end
18
+ end
19
+
20
+ it 'should return the title in the main frame' do
21
+ expect(@session.driver.frame_title).to eq 'With Frames'
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ Capybara::SpecHelper.spec '#frame_url', requires: [:frames] do
4
+ before do
5
+ @session.visit('/within_frames')
6
+ end
7
+
8
+ it 'should return the url in a frame' do
9
+ @session.within_frame('frameOne') do
10
+ expect(@session.driver.frame_url).to end_with '/frame_one'
11
+ end
12
+ end
13
+
14
+ it 'should return the url in FrameTwo' do
15
+ @session.within_frame('frameTwo') do
16
+ expect(@session.driver.frame_url).to end_with '/frame_two'
17
+ end
18
+ end
19
+
20
+ it 'should return the url in the main frame' do
21
+ expect(@session.driver.frame_url).to end_with('/within_frames')
22
+ end
23
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ Capybara::SpecHelper.spec '#switch_to_frame', requires: [:frames] do
4
+ before do
5
+ @session.visit('/within_frames')
6
+ end
7
+
8
+ after do
9
+ # Ensure we clean up after the frame changes
10
+ @session.switch_to_frame(:top)
11
+ end
12
+
13
+ it 'should find the div in frameOne' do
14
+ frame = @session.find(:frame, 'frameOne')
15
+ @session.switch_to_frame(frame)
16
+ expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne'
17
+ end
18
+
19
+ it 'should find the div in FrameTwo' do
20
+ frame = @session.find(:frame, 'frameTwo')
21
+ @session.switch_to_frame(frame)
22
+ expect(@session.find("//*[@id='divInFrameTwo']").text).to eql 'This is the text of divInFrameTwo'
23
+ end
24
+
25
+ it 'should return to the parent frame when told to' do
26
+ frame = @session.find(:frame, 'frameOne')
27
+ @session.switch_to_frame(frame)
28
+ @session.switch_to_frame(:parent)
29
+ expect(@session.find("//*[@id='divInMainWindow']").text).to eql 'This is the text for divInMainWindow'
30
+ end
31
+
32
+ it 'should be able to switch to nested frames' do
33
+ frame = @session.find(:frame, 'parentFrame')
34
+ @session.switch_to_frame frame
35
+ frame = @session.find(:frame, 'childFrame')
36
+ @session.switch_to_frame frame
37
+ frame = @session.find(:frame, 'grandchildFrame1')
38
+ @session.switch_to_frame frame
39
+ expect(@session).to have_selector(:css, '#divInFrameOne', text: 'This is the text of divInFrameOne')
40
+ end
41
+
42
+ it 'should reset scope when changing frames' do
43
+ frame = @session.find(:frame, 'parentFrame')
44
+ @session.within(:css, '#divInMainWindow') do
45
+ @session.switch_to_frame(frame)
46
+ expect(@session.has_selector?(:css, 'iframe#childFrame')).to be true
47
+ @session.switch_to_frame(:parent)
48
+ end
49
+ end
50
+
51
+ it 'works if the frame is closed', requires: %i[frames js] do
52
+ frame = @session.find(:frame, 'parentFrame')
53
+ @session.switch_to_frame frame
54
+ frame = @session.find(:frame, 'childFrame')
55
+ @session.switch_to_frame frame
56
+ @session.click_link 'Close Window Now'
57
+ @session.switch_to_frame :parent # Go back to parentFrame
58
+ expect(@session).to have_selector(:css, 'body#parentBody')
59
+ expect(@session).not_to have_selector(:css, '#childFrame')
60
+ @session.switch_to_frame :parent # Go back to top
61
+ end
62
+
63
+ it 'works if the frame is closed with a slight delay', requires: %i[frames js] do
64
+ frame = @session.find(:frame, 'parentFrame')
65
+ @session.switch_to_frame frame
66
+ frame = @session.find(:frame, 'childFrame')
67
+ @session.switch_to_frame frame
68
+ @session.click_link 'Close Window Soon'
69
+ sleep 1
70
+ @session.switch_to_frame :parent # Go back to parentFrame
71
+ expect(@session).to have_selector(:css, 'body#parentBody')
72
+ expect(@session).not_to have_selector(:css, '#childFrame')
73
+ @session.switch_to_frame :parent # Go back to top
74
+ end
75
+
76
+ it 'can return to the top frame', requires: [:frames] do
77
+ frame = @session.find(:frame, 'parentFrame')
78
+ @session.switch_to_frame frame
79
+ frame = @session.find(:frame, 'childFrame')
80
+ @session.switch_to_frame frame
81
+ @session.switch_to_frame :top
82
+ expect(@session.find("//*[@id='divInMainWindow']").text).to eql 'This is the text for divInMainWindow'
83
+ end
84
+
85
+ it "should raise error if switching to parent unmatched inside `within` as it's nonsense" do
86
+ expect do
87
+ frame = @session.find(:frame, 'parentFrame')
88
+ @session.switch_to_frame(frame)
89
+ @session.within(:css, '#parentBody') do
90
+ @session.switch_to_frame(:parent)
91
+ end
92
+ end.to raise_error(Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's `within` block.")
93
+ end
94
+
95
+ it "should raise error if switching to top inside a `within` in a frame as it's nonsense" do
96
+ frame = @session.find(:frame, 'parentFrame')
97
+ @session.switch_to_frame(frame)
98
+ @session.within(:css, '#parentBody') do
99
+ expect do
100
+ @session.switch_to_frame(:top)
101
+ end.to raise_error(Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's `within` block.")
102
+ end
103
+ end
104
+
105
+ it "should raise error if switching to top inside a nested `within` in a frame as it's nonsense" do
106
+ frame = @session.find(:frame, 'parentFrame')
107
+ @session.switch_to_frame(frame)
108
+ @session.within(:css, '#parentBody') do
109
+ @session.switch_to_frame(@session.find(:frame, 'childFrame'))
110
+ expect do
111
+ @session.switch_to_frame(:top)
112
+ end.to raise_error(Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's `within` block.")
113
+ @session.switch_to_frame(:parent)
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ Capybara::SpecHelper.spec '#within_frame', requires: [:frames] do
4
+ before do
5
+ @session.visit('/within_frames')
6
+ end
7
+
8
+ it 'should find the div in frameOne' do
9
+ @session.within_frame('frameOne') do
10
+ expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne'
11
+ end
12
+ end
13
+
14
+ it 'should find the div in FrameTwo' do
15
+ @session.within_frame('frameTwo') do
16
+ expect(@session.find("//*[@id='divInFrameTwo']").text).to eql 'This is the text of divInFrameTwo'
17
+ end
18
+ end
19
+
20
+ it 'should find the text div in the main window after finding text in frameOne' do
21
+ @session.within_frame('frameOne') do
22
+ expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne'
23
+ end
24
+ expect(@session.find("//*[@id='divInMainWindow']").text).to eql 'This is the text for divInMainWindow'
25
+ end
26
+
27
+ it 'should find the text div in the main window after finding text in frameTwo' do
28
+ @session.within_frame('frameTwo') do
29
+ expect(@session.find("//*[@id='divInFrameTwo']").text).to eql 'This is the text of divInFrameTwo'
30
+ end
31
+ expect(@session.find("//*[@id='divInMainWindow']").text).to eql 'This is the text for divInMainWindow'
32
+ end
33
+
34
+ it 'should return the result of executing the block' do
35
+ expect(@session.within_frame('frameOne') { 'return value' }).to eql 'return value'
36
+ end
37
+
38
+ it 'should find the div given Element' do
39
+ element = @session.find(:id, 'frameOne')
40
+ @session.within_frame element do
41
+ expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne'
42
+ end
43
+ end
44
+
45
+ it 'should find the div given selector and locator' do
46
+ @session.within_frame(:css, '#frameOne') do
47
+ expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne'
48
+ end
49
+ end
50
+
51
+ it 'should default to the :frame selector kind when only options passed' do
52
+ @session.within_frame(name: 'my frame one') do
53
+ expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne'
54
+ end
55
+ end
56
+
57
+ it 'should default to the :frame selector when no options passed' do
58
+ container = @session.find(:css, '#divInMainWindow')
59
+ @session.within(container) do
60
+ # Ensure only one frame in scope
61
+ @session.within_frame do
62
+ expect(@session).to have_css('body#parentBody')
63
+ end
64
+ end
65
+ expect do
66
+ # Multiple frames in scope here
67
+ @session.within_frame { ; }
68
+ end.to raise_error Capybara::Ambiguous
69
+ end
70
+
71
+ it 'should find multiple nested frames' do
72
+ @session.within_frame 'parentFrame' do
73
+ @session.within_frame 'childFrame' do
74
+ @session.within_frame 'grandchildFrame1' do
75
+ # dummy
76
+ end
77
+ @session.within_frame 'grandchildFrame2' do
78
+ # dummy
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ it 'should reset scope when changing frames' do
85
+ @session.within(:css, '#divInMainWindow') do
86
+ @session.within_frame 'innerParentFrame' do
87
+ expect(@session.has_selector?(:css, 'iframe#childFrame')).to be true
88
+ end
89
+ end
90
+ end
91
+
92
+ it 'works if the frame is closed', requires: %i[frames js] do
93
+ @session.within_frame 'parentFrame' do
94
+ @session.within_frame 'childFrame' do
95
+ @session.click_link 'Close Window Now'
96
+ end
97
+ expect(@session).to have_selector(:css, 'body#parentBody')
98
+ expect(@session).not_to have_selector(:css, '#childFrame')
99
+ end
100
+ end
101
+
102
+ it 'works if the frame is closed with a slight delay', requires: %i[frames js] do
103
+ @session.within_frame 'parentFrame' do
104
+ @session.within_frame 'childFrame' do
105
+ @session.click_link 'Close Window Soon'
106
+ sleep 1
107
+ end
108
+ expect(@session).to have_selector(:css, 'body#parentBody')
109
+ expect(@session).not_to have_selector(:css, '#childFrame')
110
+ end
111
+ end
112
+ end