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
@@ -2,9 +2,9 @@
2
2
 
3
3
  module Capybara
4
4
  ##
5
- # The Window class represents a browser window.
5
+ # The {Window} class represents a browser window.
6
6
  #
7
- # You can get an instance of the class by calling either of:
7
+ # You can get an instance of the class by calling any of:
8
8
  #
9
9
  # * {Capybara::Session#windows}
10
10
  # * {Capybara::Session#current_window}
@@ -12,12 +12,12 @@ module Capybara
12
12
  # * {Capybara::Session#switch_to_window}
13
13
  #
14
14
  # Note that some drivers (e.g. Selenium) support getting size of/resizing/closing only
15
- # current window. So if you invoke such method for:
15
+ # current window. So if you invoke such method for:
16
16
  #
17
- # * window that is current, Capybara will make 2 Selenium method invocations
18
- # (get handle of current window + get size/resize/close).
19
- # * window that is not current, Capybara will make 4 Selenium method invocations
20
- # (get handle of current window + switch to given handle + get size/resize/close + switch to original handle)
17
+ # * window that is current, Capybara will make 2 Selenium method invocations
18
+ # (get handle of current window + get size/resize/close).
19
+ # * window that is not current, Capybara will make 4 Selenium method invocations
20
+ # (get handle of current window + switch to given handle + get size/resize/close + switch to original handle)
21
21
  #
22
22
  class Window
23
23
  # @return [String] a string that uniquely identifies window within session
@@ -57,12 +57,12 @@ module Capybara
57
57
  # Close window.
58
58
  #
59
59
  # If this method was called for window that is current, then after calling this method
60
- # future invocations of other Capybara methods should raise
61
- # `session.driver.no_such_window_error` until another window will be switched to.
60
+ # future invocations of other Capybara methods should raise
61
+ # {Capybara::Driver::Base#no_such_window_error session.driver.no_such_window_error} until another window will be switched to.
62
62
  #
63
63
  # @!macro about_current
64
64
  # If this method was called for window that is not current, then after calling this method
65
- # current window shouldn remain the same as it was before calling this method.
65
+ # current window should remain the same as it was before calling this method.
66
66
  #
67
67
  def close
68
68
  @driver.close_window(handle)
@@ -82,8 +82,8 @@ module Capybara
82
82
  # Resize window.
83
83
  #
84
84
  # @macro about_current
85
- # @param width [String] the new window width in pixels
86
- # @param height [String] the new window height in pixels
85
+ # @param width [Integer] the new window width in pixels
86
+ # @param height [Integer] the new window height in pixels
87
87
  #
88
88
  def resize_to(width, height)
89
89
  wait_for_stable_size { @driver.resize_window_to(handle, width, height) }
@@ -93,7 +93,7 @@ module Capybara
93
93
  # Maximize window.
94
94
  #
95
95
  # If a particular driver (e.g. headless driver) doesn't have concept of maximizing it
96
- # may not support this method.
96
+ # may not support this method.
97
97
  #
98
98
  # @macro about_current
99
99
  #
@@ -101,6 +101,17 @@ module Capybara
101
101
  wait_for_stable_size { @driver.maximize_window(handle) }
102
102
  end
103
103
 
104
+ ##
105
+ # Fullscreen window.
106
+ #
107
+ # If a particular driver doesn't have concept of fullscreen it may not support this method.
108
+ #
109
+ # @macro about_current
110
+ #
111
+ def fullscreen
112
+ @driver.fullscreen_window(handle)
113
+ end
114
+
104
115
  def eql?(other)
105
116
  other.is_a?(self.class) && @session == other.session && @handle == other.handle
106
117
  end
@@ -118,19 +129,14 @@ module Capybara
118
129
 
119
130
  def wait_for_stable_size(seconds = session.config.default_max_wait_time)
120
131
  res = yield if block_given?
121
- prev_size = size
122
- start_time = Capybara::Helpers.monotonic_time
123
- begin
124
- sleep 0.05
125
- cur_size = size
126
- return res if cur_size == prev_size
127
- prev_size = cur_size
128
- end while (Capybara::Helpers.monotonic_time - start_time) < seconds
132
+ timer = Capybara::Helpers.timer(expire_in: seconds)
133
+ loop do
134
+ prev_size = size
135
+ sleep 0.025
136
+ return res if prev_size == size
137
+ break if timer.expired?
138
+ end
129
139
  raise Capybara::WindowError, "Window size not stable within #{seconds} seconds."
130
140
  end
131
-
132
- def raise_unless_current(what)
133
- raise Capybara::WindowError, "#{what} not current window is not possible." unless current?
134
- end
135
141
  end
136
142
  end
data/lib/capybara.rb CHANGED
@@ -5,6 +5,7 @@ require 'nokogiri'
5
5
  require 'xpath'
6
6
  require 'forwardable'
7
7
  require 'capybara/config'
8
+ require 'capybara/registration_container'
8
9
 
9
10
  module Capybara
10
11
  class CapybaraError < StandardError; end
@@ -38,6 +39,8 @@ module Capybara
38
39
  # See {Capybara.configure}
39
40
  # @!method javascript_driver
40
41
  # See {Capybara.configure}
42
+ # @!method use_html5_parsing
43
+ # See {Capybara.configure}
41
44
  Config::OPTIONS.each do |method|
42
45
  def_delegators :config, method, "#{method}="
43
46
  end
@@ -64,31 +67,47 @@ module Capybara
64
67
  # config.app_host = 'http://www.google.com'
65
68
  # end
66
69
  #
67
- # === Configurable options
68
- #
69
- # [app_host = String/nil] The default host to use when giving a relative URL to visit, must be a valid URL e.g. http://www.example.com
70
- # [always_include_port = Boolean] Whether the Rack server's port should automatically be inserted into every visited URL unless another port is explicitly specified (Default: false)
71
- # [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil)
72
- # [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true)
73
- # [raise_server_errors = Boolean] Should errors raised in the server be raised in the tests? (Default: true)
74
- # [server_errors = Array\<Class\>] Error classes that should be raised in the tests if they are raised in the server and Capybara.raise_server_errors is true (Default: [StandardError])
75
- # [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: :css)
76
- # [default_max_wait_time = Numeric] The maximum number of seconds to wait for asynchronous processes to finish (Default: 2)
77
- # [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: true)
78
- # [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
79
- # [save_path = String] Where to put pages saved through save_(page|screenshot), save_and_open_(page|screenshot) (Default: Dir.pwd)
80
- # [automatic_label_click = Boolean] Whether Node#choose, Node#check, Node#uncheck will attempt to click the associated label element if the checkbox/radio button are non-visible (Default: false)
81
- # [enable_aria_label = Boolean] Whether fields, links, and buttons will match against aria-label attribute (Default: false)
82
- # [reuse_server = Boolean] Reuse the server thread between multiple sessions using the same app object (Default: true)
83
- # [threadsafe = Boolean] Whether sessions can be configured individually (Default: false)
84
- # [server = Symbol] The name of the registered server to use when running the app under test (Default: :webrick)
85
- #
86
- # === DSL Options
87
- #
88
- # when using capybara/dsl, the following options are also available:
89
- #
90
- # [default_driver = Symbol] The name of the driver to use by default. (Default: :rack_test)
91
- # [javascript_driver = Symbol] The name of a driver to use for JavaScript enabled tests. (Default: :selenium)
70
+ # #### Configurable options
71
+ #
72
+ # - **use_html5_parsing** (Boolean = `false`) - When Nokogiri >= 1.12.0 or `nokogumbo` is installed, whether HTML5 parsing will be used for HTML strings.
73
+ # - **always_include_port** (Boolean = `false`) - Whether the Rack server's port should automatically be inserted into every visited URL
74
+ # unless another port is explicitly specified.
75
+ # - **app_host** (String, `nil`) - The default host to use when giving a relative URL to visit, must be a valid URL e.g. `http://www.example.com`.
76
+ # - **asset_host** (String = `nil`) - Where dynamic assets are hosted - will be prepended to relative asset locations if present.
77
+ # - **automatic_label_click** (Boolean = `false`) - Whether {Capybara::Node::Element#choose Element#choose}, {Capybara::Node::Element#check Element#check},
78
+ # {Capybara::Node::Element#uncheck Element#uncheck} will attempt to click the associated `<label>` element if the checkbox/radio button are non-visible.
79
+ # - **automatic_reload** (Boolean = `true`) - Whether to automatically reload elements as Capybara is waiting.
80
+ # - **default_max_wait_time** (Numeric = `2`) - The maximum number of seconds to wait for asynchronous processes to finish.
81
+ # - **default_normalize_ws** (Boolean = `false`) - Whether text predicates and matchers use normalize whitespace behavior.
82
+ # - **default_selector** (`:css`, `:xpath` = `:css`) - Methods which take a selector use the given type by default. See also {Capybara::Selector}.
83
+ # - **default_set_options** (Hash = `{}`) - The default options passed to {Capybara::Node::Element#set Element#set}.
84
+ # - **enable_aria_label** (Boolean = `false`) - Whether fields, links, and buttons will match against `aria-label` attribute.
85
+ # - **enable_aria_role** (Boolean = `false`) - Selectors will check for relevant aria role (currently only `button`).
86
+ # - **exact** (Boolean = `false`) - Whether locators are matched exactly or with substrings. Only affects selector conditions
87
+ # written using the `XPath#is` method.
88
+ # - **exact_text** (Boolean = `false`) - Whether the text matchers and `:text` filter match exactly or on substrings.
89
+ # - **ignore_hidden_elements** (Boolean = `true`) - Whether to ignore hidden elements on the page.
90
+ # - **match** (`:one`, `:first`, `:prefer_exact`, `:smart` = `:smart`) - The matching strategy to find nodes.
91
+ # - **predicates_wait** (Boolean = `true`) - Whether Capybara's predicate matchers use waiting behavior by default.
92
+ # - **raise_server_errors** (Boolean = `true`) - Should errors raised in the server be raised in the tests?
93
+ # - **reuse_server** (Boolean = `true`) - Whether to reuse the server thread between multiple sessions using the same app object.
94
+ # - **run_server** (Boolean = `true`) - Whether to start a Rack server for the given Rack app.
95
+ # - **save_path** (String = `Dir.pwd`) - Where to put pages saved through {Capybara::Session#save_page save_page}, {Capybara::Session#save_screenshot save_screenshot},
96
+ # {Capybara::Session#save_and_open_page save_and_open_page}, or {Capybara::Session#save_and_open_screenshot save_and_open_screenshot}.
97
+ # - **server** (Symbol = `:default` (which uses puma)) - The name of the registered server to use when running the app under test.
98
+ # - **server_port** (Integer) - The port Capybara will run the application server on, if not specified a random port will be used.
99
+ # - **server_errors** (Array\<Class> = `[Exception]`) - Error classes that should be raised in the tests if they are raised in the server
100
+ # and {configure raise_server_errors} is `true`.
101
+ # - **test_id** (Symbol, String, `nil` = `nil`) - Optional attribute to match locator against with built-in selectors along with id.
102
+ # - **threadsafe** (Boolean = `false`) - Whether sessions can be configured individually.
103
+ # - **w3c_click_offset** (Boolean = 'false') - Whether click offsets should be from element center (true) or top left (false)
104
+ #
105
+ # #### DSL Options
106
+ #
107
+ # When using `capybara/dsl`, the following options are also available:
108
+ #
109
+ # - **default_driver** (Symbol = `:rack_test`) - The name of the driver to use by default.
110
+ # - **javascript_driver** (Symbol = `:selenium`) - The name of a driver to use for JavaScript enabled tests.
92
111
  #
93
112
  def configure
94
113
  yield config
@@ -108,7 +127,7 @@ module Capybara
108
127
  # @yieldreturn [Capybara::Driver::Base] A Capybara driver instance
109
128
  #
110
129
  def register_driver(name, &block)
111
- drivers[name] = block
130
+ drivers.send(:register, name, block)
112
131
  end
113
132
 
114
133
  ##
@@ -127,7 +146,7 @@ module Capybara
127
146
  # @yieldparam host The host/ip to bind to
128
147
  #
129
148
  def register_server(name, &block)
130
- servers[name.to_sym] = block
149
+ servers.send(:register, name.to_sym, block)
131
150
  end
132
151
 
133
152
  ##
@@ -158,8 +177,8 @@ module Capybara
158
177
  # @param [Symbol] name The name of the selector to add
159
178
  # @yield A block executed in the context of the new {Capybara::Selector}
160
179
  #
161
- def add_selector(name, &block)
162
- Capybara::Selector.add(name, &block)
180
+ def add_selector(name, **options, &block)
181
+ Capybara::Selector.add(name, **options, &block)
163
182
  end
164
183
 
165
184
  ##
@@ -169,7 +188,7 @@ module Capybara
169
188
  # button style (a class) might look like this
170
189
  #
171
190
  # Capybara.modify_selector(:button) do
172
- # filter (:style, valid_values: [:primary, :secondary]) { |node, style| node[:class].split.include? "btn-#{style}" }
191
+ # filter (:btn_style, valid_values: [:primary, :secondary]) { |node, style| node[:class].split.include? "btn-#{style}" }
173
192
  # end
174
193
  #
175
194
  #
@@ -181,11 +200,11 @@ module Capybara
181
200
  end
182
201
 
183
202
  def drivers
184
- @drivers ||= {}
203
+ @drivers ||= RegistrationContainer.new
185
204
  end
186
205
 
187
206
  def servers
188
- @servers ||= {}
207
+ @servers ||= RegistrationContainer.new
189
208
  end
190
209
 
191
210
  # Wraps the given string, which should contain an HTML document or fragment
@@ -194,15 +213,13 @@ module Capybara
194
213
  # any string containing HTML in the exact same way you would query the current document in a Capybara
195
214
  # session.
196
215
  #
197
- # Example: A single element
198
- #
216
+ # @example A single element
199
217
  # node = Capybara.string('<a href="foo">bar</a>')
200
218
  # anchor = node.first('a')
201
219
  # anchor[:href] #=> 'foo'
202
220
  # anchor.text #=> 'bar'
203
221
  #
204
- # Example: Multiple elements
205
- #
222
+ # @example Multiple elements
206
223
  # node = Capybara.string <<-HTML
207
224
  # <ul>
208
225
  # <li id="home">Home</li>
@@ -290,12 +307,12 @@ module Capybara
290
307
 
291
308
  ##
292
309
  #
293
- # The current Capybara::Session based on what is set as Capybara.app and Capybara.current_driver
310
+ # The current {Capybara::Session} based on what is set as {app} and {current_driver}.
294
311
  #
295
312
  # @return [Capybara::Session] The currently used session
296
313
  #
297
314
  def current_session
298
- session_pool["#{current_driver}:#{session_name}:#{app.object_id}"] ||= Capybara::Session.new(current_driver, app)
315
+ specified_session || session_pool["#{current_driver}:#{session_name}:#{app.object_id}"]
299
316
  end
300
317
 
301
318
  ##
@@ -333,22 +350,31 @@ module Capybara
333
350
 
334
351
  ##
335
352
  #
336
- # Yield a block using a specific session name.
353
+ # Yield a block using a specific session name or {Capybara::Session} instance.
337
354
  #
338
- def using_session(name)
355
+ def using_session(name_or_session, &block)
356
+ previous_session = current_session
339
357
  previous_session_info = {
358
+ specified_session: specified_session,
340
359
  session_name: session_name,
341
360
  current_driver: current_driver,
342
361
  app: app
343
362
  }
344
- self.session_name = name
345
- yield
346
- ensure
347
- self.session_name = previous_session_info[:session_name]
348
- if threadsafe
349
- self.current_driver = previous_session_info[:current_driver]
350
- self.app = previous_session_info[:app]
363
+ self.specified_session = self.session_name = nil
364
+ if name_or_session.is_a? Capybara::Session
365
+ self.specified_session = name_or_session
366
+ else
367
+ self.session_name = name_or_session
351
368
  end
369
+
370
+ if block.arity.zero?
371
+ yield
372
+ else
373
+ yield current_session, previous_session
374
+ end
375
+ ensure
376
+ self.session_name, self.specified_session = previous_session_info.values_at(:session_name, :specified_session)
377
+ self.current_driver, self.app = previous_session_info.values_at(:current_driver, :app) if threadsafe
352
378
  end
353
379
 
354
380
  ##
@@ -359,9 +385,21 @@ module Capybara
359
385
  # @return [Nokogiri::HTML::Document] HTML document
360
386
  #
361
387
  def HTML(html) # rubocop:disable Naming/MethodName
362
- Nokogiri::HTML(html).tap do |document|
388
+ # Nokogiri >= 1.12.0 or Nokogumbo installed and allowed for use
389
+ html_parser, using_html5 = if defined?(Nokogiri::HTML5) && Capybara.use_html5_parsing
390
+ [Nokogiri::HTML5, true]
391
+ else
392
+ [defined?(Nokogiri::HTML4) ? Nokogiri::HTML4 : Nokogiri::HTML, false]
393
+ end
394
+
395
+ html_parser.parse(html).tap do |document|
396
+ document.xpath('//template').each do |template|
397
+ # template elements content is not part of the document
398
+ template.inner_html = ''
399
+ end
363
400
  document.xpath('//textarea').each do |textarea|
364
- textarea['_capybara_raw_value'] = textarea.content.sub(/\A\n/, '')
401
+ # The Nokogiri HTML5 parser already returns spec compliant contents
402
+ textarea['_capybara_raw_value'] = using_html5 ? textarea.content : textarea.content.delete_prefix("\n")
365
403
  end
366
404
  end
367
405
  end
@@ -377,7 +415,25 @@ module Capybara
377
415
  end
378
416
 
379
417
  def session_pool
380
- @session_pool ||= {}
418
+ @session_pool ||= Hash.new do |hash, name|
419
+ hash[name] = Capybara::Session.new(current_driver, app)
420
+ end
421
+ end
422
+
423
+ def specified_session
424
+ if threadsafe
425
+ Thread.current['capybara_specified_session']
426
+ else
427
+ @specified_session ||= nil
428
+ end
429
+ end
430
+
431
+ def specified_session=(session)
432
+ if threadsafe
433
+ Thread.current['capybara_specified_session'] = session
434
+ else
435
+ @specified_session = session
436
+ end
381
437
  end
382
438
  end
383
439
 
@@ -405,6 +461,8 @@ module Capybara
405
461
  require 'capybara/queries/match_query'
406
462
  require 'capybara/queries/ancestor_query'
407
463
  require 'capybara/queries/sibling_query'
464
+ require 'capybara/queries/style_query'
465
+ require 'capybara/queries/active_element_query'
408
466
 
409
467
  require 'capybara/node/finders'
410
468
  require 'capybara/node/matchers'
@@ -422,40 +480,14 @@ module Capybara
422
480
  require 'capybara/rack_test/node'
423
481
  require 'capybara/rack_test/form'
424
482
  require 'capybara/rack_test/browser'
425
- require 'capybara/rack_test/css_handlers.rb'
483
+ require 'capybara/rack_test/css_handlers'
426
484
 
427
485
  require 'capybara/selenium/node'
428
486
  require 'capybara/selenium/driver'
429
487
  end
430
488
 
431
- Capybara.register_server :default do |app, port, _host|
432
- Capybara.run_default_server(app, port)
433
- end
434
-
435
- Capybara.register_server :webrick do |app, port, host, **options|
436
- require 'rack/handler/webrick'
437
- Rack::Handler::WEBrick.run(app, { Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log.new(nil, 0) }.merge(options))
438
- end
439
-
440
- Capybara.register_server :puma do |app, port, host, **options|
441
- require 'rack/handler/puma'
442
- # If we just run the Puma Rack handler it installs signal handlers which prevent us from being able to interrupt tests.
443
- # Therefore construct and run the Server instance ourselves.
444
- # Rack::Handler::Puma.run(app, { Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false }.merge(options))
445
-
446
- conf = Rack::Handler::Puma.config(app, { Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false }.merge(options))
447
- events = conf.options[:Silent] ? ::Puma::Events.strings : ::Puma::Events.stdio
448
-
449
- events.log "Capybara starting Puma..."
450
- events.log "* Version #{Puma::Const::PUMA_VERSION} , codename: #{Puma::Const::CODE_NAME}"
451
- events.log "* Min threads: #{conf.options[:min_threads]}, max threads: #{conf.options[:max_threads]}"
452
-
453
- Puma::Server.new(conf.app, events, conf.options).tap do |s|
454
- s.binder.parse conf.options[:binds], s.events
455
- s.min_threads = conf.options[:min_threads]
456
- s.max_threads = conf.options[:max_threads]
457
- end.run.join
458
- end
489
+ require 'capybara/registrations/servers'
490
+ require 'capybara/registrations/drivers'
459
491
 
460
492
  Capybara.configure do |config|
461
493
  config.always_include_port = false
@@ -464,34 +496,22 @@ Capybara.configure do |config|
464
496
  config.default_selector = :css
465
497
  config.default_max_wait_time = 2
466
498
  config.ignore_hidden_elements = true
467
- config.default_host = "http://www.example.com"
499
+ config.default_host = 'http://www.example.com'
468
500
  config.automatic_reload = true
469
501
  config.match = :smart
470
502
  config.exact = false
471
503
  config.exact_text = false
472
504
  config.raise_server_errors = true
473
- config.server_errors = [StandardError]
505
+ config.server_errors = [Exception]
474
506
  config.visible_text_only = false
475
507
  config.automatic_label_click = false
476
508
  config.enable_aria_label = false
509
+ config.enable_aria_role = false
477
510
  config.reuse_server = true
478
- end
479
-
480
- Capybara.register_driver :rack_test do |app|
481
- Capybara::RackTest::Driver.new(app)
482
- end
483
-
484
- Capybara.register_driver :selenium do |app|
485
- Capybara::Selenium::Driver.new(app)
486
- end
487
-
488
- Capybara.register_driver :selenium_chrome do |app|
489
- Capybara::Selenium::Driver.new(app, browser: :chrome)
490
- end
491
-
492
- Capybara.register_driver :selenium_chrome_headless do |app|
493
- browser_options = ::Selenium::WebDriver::Chrome::Options.new
494
- browser_options.args << '--headless'
495
- browser_options.args << '--disable-gpu'
496
- Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
511
+ config.default_set_options = {}
512
+ config.test_id = nil
513
+ config.predicates_wait = true
514
+ config.default_normalize_ws = false
515
+ config.use_html5_parsing = false
516
+ config.w3c_click_offset = false
497
517
  end
@@ -3,9 +3,10 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe Capybara do
6
+ include Capybara::RSpecMatchers
6
7
  describe '.string' do
7
8
  let :string do
8
- Capybara.string <<-STRING
9
+ described_class.string <<-STRING
9
10
  <html>
10
11
  <head>
11
12
  <title>simple_node</title>
@@ -46,97 +47,121 @@ RSpec.describe Capybara do
46
47
  STRING
47
48
  end
48
49
 
49
- it "allows using matchers" do
50
+ it 'allows using matchers' do
50
51
  expect(string).to have_css('#page')
51
52
  expect(string).not_to have_css('#does-not-exist')
52
53
  end
53
54
 
54
- it "allows using custom matchers" do
55
- Capybara.add_selector :lifeform do
55
+ it 'allows using custom matchers' do
56
+ described_class.add_selector :lifeform do
56
57
  xpath { |name| ".//option[contains(.,'#{name}')]" }
57
58
  end
58
- expect(string).to have_selector(:id, "page")
59
+ expect(string).to have_selector(:id, 'page')
59
60
  expect(string).not_to have_selector(:id, 'does-not-exist')
60
- expect(string).to have_selector(:lifeform, "Monkey")
61
- expect(string).not_to have_selector(:lifeform, "Gorilla")
61
+ expect(string).to have_selector(:lifeform, 'Monkey')
62
+ expect(string).not_to have_selector(:lifeform, 'Gorilla')
62
63
  end
63
64
 
64
65
  it 'allows custom matcher using css' do
65
- Capybara.add_selector :section do
66
+ described_class.add_selector :section do
66
67
  css { |css_class| "section .#{css_class}" }
67
68
  end
68
69
  expect(string).to have_selector(:section, 'subsection')
69
70
  expect(string).not_to have_selector(:section, 'section_8')
70
71
  end
71
72
 
72
- it "allows using matchers with text option" do
73
+ it 'allows using matchers with text option' do
73
74
  expect(string).to have_css('h1', text: 'Totally awesome')
74
75
  expect(string).not_to have_css('h1', text: 'Not so awesome')
75
76
  end
76
77
 
77
- it "allows finding only visible nodes" do
78
+ it 'allows finding only visible nodes' do
78
79
  expect(string.all(:css, '#secret', visible: true)).to be_empty
79
80
  expect(string.all(:css, '#secret', visible: false).size).to eq(1)
80
81
  end
81
82
 
82
- it "allows finding elements and extracting text from them" do
83
+ it 'allows finding elements and extracting text from them' do
83
84
  expect(string.find('//h1').text).to eq('Totally awesome')
84
85
  end
85
86
 
86
- it "allows finding elements and extracting attributes from them" do
87
+ it 'allows finding elements and extracting attributes from them' do
87
88
  expect(string.find('//h1')[:data]).to eq('fantastic')
88
89
  end
89
90
 
90
- it "allows finding elements and extracting the tag name from them" do
91
+ it 'allows finding elements and extracting the tag name from them' do
91
92
  expect(string.find('//h1').tag_name).to eq('h1')
92
93
  end
93
94
 
94
- it "allows finding elements and extracting the path" do
95
+ it 'allows finding elements and extracting the path' do
95
96
  expect(string.find('//h1').path).to eq('/html/body/div/div[1]/h1')
96
97
  end
97
98
 
98
- it "allows finding elements and extracting the path" do
99
+ it 'allows finding elements and extracting the value' do
99
100
  expect(string.find('//div/input').value).to eq('bar')
100
101
  expect(string.find('//select').value).to eq('Capybara')
101
102
  end
102
103
 
103
- it "allows finding elements and checking if they are visible" do
104
+ it 'allows finding elements and checking if they are visible' do
104
105
  expect(string.find('//h1')).to be_visible
105
- expect(string.find(:css, "#secret", visible: false)).not_to be_visible
106
+ expect(string.find(:css, '#secret', visible: false)).not_to be_visible
106
107
  end
107
108
 
108
- it "allows finding elements and checking if they are disabled" do
109
+ it 'allows finding elements and checking if they are disabled' do
109
110
  expect(string.find('//form/input[@name="bleh"]')).to be_disabled
110
111
  expect(string.find('//form/input[@name="meh"]')).not_to be_disabled
111
112
  end
112
113
 
113
- describe "#title" do
114
- it "returns the page title" do
115
- expect(string.title).to eq("simple_node")
114
+ it 'allows finding siblings' do
115
+ h1 = string.find(:css, 'h1')
116
+ expect(h1).to have_sibling(:css, 'p', text: 'Yes it is')
117
+ expect(h1).not_to have_sibling(:css, 'p', text: 'Jonas Nicklas')
118
+ end
119
+
120
+ it 'allows finding ancestor' do
121
+ h1 = string.find(:css, 'h1')
122
+ expect(h1).to have_ancestor(:css, '#content')
123
+ expect(h1).not_to have_ancestor(:css, '#footer')
124
+ end
125
+
126
+ it 'drops illegal fragments when using gumbo' do
127
+ skip 'libxml is less strict than Gumbo' unless Nokogiri.respond_to?(:HTML5)
128
+ described_class.use_html5_parsing = true
129
+ expect(described_class.string('<td>1</td>')).not_to have_css('td')
130
+ end
131
+
132
+ it 'can disable use of HTML5 parsing' do
133
+ skip "Test doesn't make sense unlesss HTML5 parsing is loaded (Nokogumbo or Nokogiri >= 1.12.0)" unless Nokogiri.respond_to?(:HTML5)
134
+ described_class.use_html5_parsing = false
135
+ expect(described_class.string('<td>1</td>')).to have_css('td')
136
+ end
137
+
138
+ describe '#title' do
139
+ it 'returns the page title' do
140
+ expect(string.title).to eq('simple_node')
116
141
  end
117
142
  end
118
143
 
119
- describe "#has_title?" do
120
- it "returns whether the page has the given title" do
121
- expect(string.has_title?('simple_node')).to be_truthy
122
- expect(string.has_title?('monkey')).to be_falsey
144
+ describe '#has_title?' do
145
+ it 'returns whether the page has the given title' do
146
+ expect(string.has_title?('simple_node')).to be true
147
+ expect(string.has_title?('monkey')).to be false
123
148
  end
124
149
 
125
- it "allows regexp matches" do
126
- expect(string.has_title?(/s[a-z]+_node/)).to be_truthy
127
- expect(string.has_title?(/monkey/)).to be_falsey
150
+ it 'allows regexp matches' do
151
+ expect(string.has_title?(/s[a-z]+_node/)).to be true
152
+ expect(string.has_title?(/monkey/)).to be false
128
153
  end
129
154
  end
130
155
 
131
156
  describe '#has_no_title?' do
132
- it "returns whether the page does not have the given title" do
133
- expect(string.has_no_title?('simple_node')).to be_falsey
134
- expect(string.has_no_title?('monkey')).to be_truthy
157
+ it 'returns whether the page does not have the given title' do
158
+ expect(string.has_no_title?('simple_node')).to be false
159
+ expect(string.has_no_title?('monkey')).to be true
135
160
  end
136
161
 
137
- it "allows regexp matches" do
138
- expect(string.has_no_title?(/s[a-z]+_node/)).to be_falsey
139
- expect(string.has_no_title?(/monkey/)).to be_truthy
162
+ it 'allows regexp matches' do
163
+ expect(string.has_no_title?(/s[a-z]+_node/)).to be false
164
+ expect(string.has_no_title?(/monkey/)).to be true
140
165
  end
141
166
  end
142
167
  end