capybara 3.3.0 → 3.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +803 -13
  4. data/License.txt +1 -1
  5. data/README.md +257 -84
  6. data/lib/capybara/config.rb +25 -9
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/base.rb +17 -3
  9. data/lib/capybara/driver/node.rb +31 -6
  10. data/lib/capybara/dsl.rb +9 -7
  11. data/lib/capybara/helpers.rb +31 -7
  12. data/lib/capybara/minitest/spec.rb +180 -88
  13. data/lib/capybara/minitest.rb +262 -149
  14. data/lib/capybara/node/actions.rb +202 -116
  15. data/lib/capybara/node/base.rb +34 -19
  16. data/lib/capybara/node/document.rb +14 -2
  17. data/lib/capybara/node/document_matchers.rb +10 -12
  18. data/lib/capybara/node/element.rb +269 -115
  19. data/lib/capybara/node/finders.rb +99 -77
  20. data/lib/capybara/node/matchers.rb +327 -151
  21. data/lib/capybara/node/simple.rb +48 -13
  22. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  23. data/lib/capybara/queries/active_element_query.rb +18 -0
  24. data/lib/capybara/queries/ancestor_query.rb +8 -9
  25. data/lib/capybara/queries/base_query.rb +23 -16
  26. data/lib/capybara/queries/current_path_query.rb +16 -6
  27. data/lib/capybara/queries/match_query.rb +1 -0
  28. data/lib/capybara/queries/selector_query.rb +587 -130
  29. data/lib/capybara/queries/sibling_query.rb +8 -6
  30. data/lib/capybara/queries/style_query.rb +6 -2
  31. data/lib/capybara/queries/text_query.rb +28 -14
  32. data/lib/capybara/queries/title_query.rb +2 -2
  33. data/lib/capybara/rack_test/browser.rb +92 -25
  34. data/lib/capybara/rack_test/driver.rb +16 -7
  35. data/lib/capybara/rack_test/errors.rb +6 -0
  36. data/lib/capybara/rack_test/form.rb +68 -41
  37. data/lib/capybara/rack_test/node.rb +106 -39
  38. data/lib/capybara/rails.rb +1 -1
  39. data/lib/capybara/registration_container.rb +41 -0
  40. data/lib/capybara/registrations/drivers.rb +42 -0
  41. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  42. data/lib/capybara/registrations/servers.rb +66 -0
  43. data/lib/capybara/result.rb +75 -52
  44. data/lib/capybara/rspec/features.rb +7 -7
  45. data/lib/capybara/rspec/matcher_proxies.rb +39 -18
  46. data/lib/capybara/rspec/matchers/base.rb +113 -0
  47. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  48. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  49. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  50. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  51. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  52. data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
  53. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  54. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  55. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  56. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  57. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  58. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  59. data/lib/capybara/rspec/matchers.rb +141 -339
  60. data/lib/capybara/rspec.rb +2 -0
  61. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  62. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  63. data/lib/capybara/selector/css.rb +27 -25
  64. data/lib/capybara/selector/definition/button.rb +68 -0
  65. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  66. data/lib/capybara/selector/definition/css.rb +10 -0
  67. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  68. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  69. data/lib/capybara/selector/definition/element.rb +28 -0
  70. data/lib/capybara/selector/definition/field.rb +40 -0
  71. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  72. data/lib/capybara/selector/definition/file_field.rb +13 -0
  73. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  74. data/lib/capybara/selector/definition/frame.rb +17 -0
  75. data/lib/capybara/selector/definition/id.rb +6 -0
  76. data/lib/capybara/selector/definition/label.rb +62 -0
  77. data/lib/capybara/selector/definition/link.rb +55 -0
  78. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  79. data/lib/capybara/selector/definition/option.rb +27 -0
  80. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  81. data/lib/capybara/selector/definition/select.rb +81 -0
  82. data/lib/capybara/selector/definition/table.rb +109 -0
  83. data/lib/capybara/selector/definition/table_row.rb +21 -0
  84. data/lib/capybara/selector/definition/xpath.rb +5 -0
  85. data/lib/capybara/selector/definition.rb +280 -0
  86. data/lib/capybara/selector/filter.rb +1 -0
  87. data/lib/capybara/selector/filter_set.rb +73 -25
  88. data/lib/capybara/selector/filters/base.rb +24 -5
  89. data/lib/capybara/selector/filters/expression_filter.rb +3 -3
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +16 -2
  92. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  93. data/lib/capybara/selector/selector.rb +85 -348
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/lib/capybara/selector.rb +474 -447
  96. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  97. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  98. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  99. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  100. data/lib/capybara/selenium/driver.rb +255 -143
  101. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +93 -11
  102. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  103. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
  104. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  105. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  106. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  107. data/lib/capybara/selenium/extensions/find.rb +110 -0
  108. data/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
  109. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  110. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  111. data/lib/capybara/selenium/node.rb +436 -134
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
  114. data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  115. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  116. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  117. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  118. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  119. data/lib/capybara/selenium/patches/logs.rb +45 -0
  120. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  121. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  122. data/lib/capybara/server/animation_disabler.rb +56 -19
  123. data/lib/capybara/server/checker.rb +9 -3
  124. data/lib/capybara/server/middleware.rb +28 -12
  125. data/lib/capybara/server.rb +33 -10
  126. data/lib/capybara/session/config.rb +34 -10
  127. data/lib/capybara/session/matchers.rb +23 -16
  128. data/lib/capybara/session.rb +230 -170
  129. data/lib/capybara/spec/public/jquery.js +5 -5
  130. data/lib/capybara/spec/public/offset.js +6 -0
  131. data/lib/capybara/spec/public/test.js +121 -8
  132. data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
  133. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
  134. data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
  135. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  136. data/lib/capybara/spec/session/all_spec.rb +127 -40
  137. data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
  138. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
  139. data/lib/capybara/spec/session/assert_current_path_spec.rb +21 -18
  140. data/lib/capybara/spec/session/assert_selector_spec.rb +52 -58
  141. data/lib/capybara/spec/session/assert_style_spec.rb +7 -7
  142. data/lib/capybara/spec/session/assert_text_spec.rb +74 -50
  143. data/lib/capybara/spec/session/assert_title_spec.rb +12 -12
  144. data/lib/capybara/spec/session/attach_file_spec.rb +126 -72
  145. data/lib/capybara/spec/session/body_spec.rb +6 -6
  146. data/lib/capybara/spec/session/check_spec.rb +102 -47
  147. data/lib/capybara/spec/session/choose_spec.rb +58 -32
  148. data/lib/capybara/spec/session/click_button_spec.rb +219 -163
  149. data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -23
  150. data/lib/capybara/spec/session/click_link_spec.rb +77 -54
  151. data/lib/capybara/spec/session/current_scope_spec.rb +8 -8
  152. data/lib/capybara/spec/session/current_url_spec.rb +38 -29
  153. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
  154. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
  155. data/lib/capybara/spec/session/element/assert_match_selector_spec.rb +8 -8
  156. data/lib/capybara/spec/session/element/match_css_spec.rb +16 -10
  157. data/lib/capybara/spec/session/element/match_xpath_spec.rb +6 -6
  158. data/lib/capybara/spec/session/element/matches_selector_spec.rb +68 -56
  159. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
  160. data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
  161. data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
  162. data/lib/capybara/spec/session/fill_in_spec.rb +101 -46
  163. data/lib/capybara/spec/session/find_button_spec.rb +23 -23
  164. data/lib/capybara/spec/session/find_by_id_spec.rb +7 -7
  165. data/lib/capybara/spec/session/find_field_spec.rb +32 -30
  166. data/lib/capybara/spec/session/find_link_spec.rb +31 -21
  167. data/lib/capybara/spec/session/find_spec.rb +244 -141
  168. data/lib/capybara/spec/session/first_spec.rb +43 -43
  169. data/lib/capybara/spec/session/frame/frame_title_spec.rb +5 -5
  170. data/lib/capybara/spec/session/frame/frame_url_spec.rb +5 -5
  171. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +30 -18
  172. data/lib/capybara/spec/session/frame/within_frame_spec.rb +45 -18
  173. data/lib/capybara/spec/session/go_back_spec.rb +1 -1
  174. data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
  175. data/lib/capybara/spec/session/has_all_selectors_spec.rb +23 -23
  176. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  177. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  178. data/lib/capybara/spec/session/has_button_spec.rb +94 -13
  179. data/lib/capybara/spec/session/has_css_spec.rb +272 -132
  180. data/lib/capybara/spec/session/has_current_path_spec.rb +50 -35
  181. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  182. data/lib/capybara/spec/session/has_field_spec.rb +137 -58
  183. data/lib/capybara/spec/session/has_link_spec.rb +44 -4
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +31 -31
  185. data/lib/capybara/spec/session/has_select_spec.rb +84 -50
  186. data/lib/capybara/spec/session/has_selector_spec.rb +111 -71
  187. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  188. data/lib/capybara/spec/session/has_table_spec.rb +181 -4
  189. data/lib/capybara/spec/session/has_text_spec.rb +101 -53
  190. data/lib/capybara/spec/session/has_title_spec.rb +19 -14
  191. data/lib/capybara/spec/session/has_xpath_spec.rb +56 -38
  192. data/lib/capybara/spec/session/headers_spec.rb +1 -1
  193. data/lib/capybara/spec/session/html_spec.rb +13 -6
  194. data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
  195. data/lib/capybara/spec/session/node_spec.rb +894 -142
  196. data/lib/capybara/spec/session/node_wrapper_spec.rb +10 -7
  197. data/lib/capybara/spec/session/refresh_spec.rb +9 -7
  198. data/lib/capybara/spec/session/reset_session_spec.rb +63 -35
  199. data/lib/capybara/spec/session/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 +2 -2
  202. data/lib/capybara/spec/session/save_page_spec.rb +37 -37
  203. data/lib/capybara/spec/session/save_screenshot_spec.rb +10 -10
  204. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  205. data/lib/capybara/spec/session/scroll_spec.rb +119 -0
  206. data/lib/capybara/spec/session/select_spec.rb +85 -85
  207. data/lib/capybara/spec/session/selectors_spec.rb +49 -18
  208. data/lib/capybara/spec/session/sibling_spec.rb +9 -9
  209. data/lib/capybara/spec/session/text_spec.rb +25 -24
  210. data/lib/capybara/spec/session/title_spec.rb +7 -6
  211. data/lib/capybara/spec/session/uncheck_spec.rb +33 -21
  212. data/lib/capybara/spec/session/unselect_spec.rb +37 -37
  213. data/lib/capybara/spec/session/visit_spec.rb +68 -49
  214. data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
  215. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -1
  216. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +20 -16
  217. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +6 -2
  218. data/lib/capybara/spec/session/window/window_spec.rb +62 -63
  219. data/lib/capybara/spec/session/window/windows_spec.rb +5 -1
  220. data/lib/capybara/spec/session/window/within_window_spec.rb +14 -14
  221. data/lib/capybara/spec/session/within_spec.rb +79 -42
  222. data/lib/capybara/spec/spec_helper.rb +41 -53
  223. data/lib/capybara/spec/test_app.rb +132 -43
  224. data/lib/capybara/spec/views/animated.erb +49 -0
  225. data/lib/capybara/spec/views/form.erb +139 -42
  226. data/lib/capybara/spec/views/frame_child.erb +4 -3
  227. data/lib/capybara/spec/views/frame_one.erb +2 -1
  228. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  229. data/lib/capybara/spec/views/frame_two.erb +1 -1
  230. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  231. data/lib/capybara/spec/views/layout.erb +10 -0
  232. data/lib/capybara/spec/views/obscured.erb +47 -0
  233. data/lib/capybara/spec/views/offset.erb +33 -0
  234. data/lib/capybara/spec/views/path.erb +2 -2
  235. data/lib/capybara/spec/views/popup_one.erb +1 -1
  236. data/lib/capybara/spec/views/popup_two.erb +1 -1
  237. data/lib/capybara/spec/views/react.erb +45 -0
  238. data/lib/capybara/spec/views/scroll.erb +21 -0
  239. data/lib/capybara/spec/views/spatial.erb +31 -0
  240. data/lib/capybara/spec/views/tables.erb +67 -0
  241. data/lib/capybara/spec/views/with_animation.erb +39 -4
  242. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  243. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  244. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  245. data/lib/capybara/spec/views/with_hover.erb +3 -2
  246. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  247. data/lib/capybara/spec/views/with_html.erb +37 -9
  248. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  249. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  250. data/lib/capybara/spec/views/with_js.erb +26 -5
  251. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  252. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  253. data/lib/capybara/spec/views/with_scope.erb +2 -2
  254. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  255. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  256. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  257. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  258. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  259. data/lib/capybara/spec/views/with_windows.erb +1 -1
  260. data/lib/capybara/spec/views/within_frames.erb +1 -1
  261. data/lib/capybara/version.rb +1 -1
  262. data/lib/capybara/window.rb +19 -25
  263. data/lib/capybara.rb +126 -111
  264. data/spec/basic_node_spec.rb +59 -34
  265. data/spec/capybara_spec.rb +56 -44
  266. data/spec/counter_spec.rb +35 -0
  267. data/spec/css_builder_spec.rb +101 -0
  268. data/spec/css_splitter_spec.rb +8 -8
  269. data/spec/dsl_spec.rb +79 -52
  270. data/spec/filter_set_spec.rb +9 -9
  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 +45 -7
  274. data/spec/minitest_spec_spec.rb +87 -64
  275. data/spec/per_session_config_spec.rb +6 -6
  276. data/spec/rack_test_spec.rb +172 -116
  277. data/spec/regexp_dissassembler_spec.rb +250 -0
  278. data/spec/result_spec.rb +80 -72
  279. data/spec/rspec/features_spec.rb +21 -16
  280. data/spec/rspec/scenarios_spec.rb +10 -6
  281. data/spec/rspec/shared_spec_matchers.rb +407 -365
  282. data/spec/rspec/views_spec.rb +3 -3
  283. data/spec/rspec_matchers_spec.rb +35 -10
  284. data/spec/rspec_spec.rb +63 -41
  285. data/spec/sauce_spec_chrome.rb +43 -0
  286. data/spec/selector_spec.rb +334 -89
  287. data/spec/selenium_spec_chrome.rb +176 -62
  288. data/spec/selenium_spec_chrome_remote.rb +54 -14
  289. data/spec/selenium_spec_edge.rb +41 -8
  290. data/spec/selenium_spec_firefox.rb +228 -0
  291. data/spec/selenium_spec_firefox_remote.rb +94 -0
  292. data/spec/selenium_spec_ie.rb +129 -11
  293. data/spec/selenium_spec_safari.rb +162 -0
  294. data/spec/server_spec.rb +171 -97
  295. data/spec/session_spec.rb +34 -18
  296. data/spec/shared_selenium_node.rb +79 -0
  297. data/spec/shared_selenium_session.rb +344 -80
  298. data/spec/spec_helper.rb +124 -2
  299. data/spec/whitespace_normalizer_spec.rb +54 -0
  300. data/spec/xpath_builder_spec.rb +93 -0
  301. metadata +326 -28
  302. data/lib/capybara/rspec/compound.rb +0 -94
  303. data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +0 -31
  304. data/lib/capybara/selenium/nodes/marionette_node.rb +0 -31
  305. data/lib/capybara/spec/session/has_style_spec.rb +0 -25
  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 -167
@@ -18,120 +18,166 @@ skipped_tests = %i[
18
18
  about_scheme
19
19
  download
20
20
  css
21
+ scroll
22
+ spatial
23
+ html_validation
24
+ shadow_dom
25
+ active_element
21
26
  ]
22
- Capybara::SpecHelper.run_specs TestSessions::RackTest, "RackTest", capybara_skip: skipped_tests
27
+ Capybara::SpecHelper.run_specs TestSessions::RackTest, 'RackTest', capybara_skip: skipped_tests do |example|
28
+ case example.metadata[:full_description]
29
+ when /has_css\? should support case insensitive :class and :id options/
30
+ skip "Nokogiri doesn't support case insensitive CSS attribute matchers"
31
+ when /#click_button should follow permanent redirects that maintain method/
32
+ skip "Rack < 2 doesn't support 308" if Gem.loaded_specs['rack'].version < Gem::Version.new('2.0.0')
33
+ when /#attach_file with multipart form should send prior hidden field if no file submitted/
34
+ skip 'Rack-test < 2 needs an empty file to detect multipart form' if Gem.loaded_specs['rack-test'].version < Gem::Version.new('2.0.0')
35
+ end
36
+ end
23
37
 
24
38
  RSpec.describe Capybara::Session do # rubocop:disable RSpec/MultipleDescribes
39
+ include Capybara::RSpecMatchers
25
40
  context 'with rack test driver' do
26
- before do
27
- @session = TestSessions::RackTest
28
- end
41
+ let(:session) { TestSessions::RackTest }
29
42
 
30
43
  describe '#driver' do
31
- it "should be a rack test driver" do
32
- expect(@session.driver).to be_an_instance_of(Capybara::RackTest::Driver)
44
+ it 'should be a rack test driver' do
45
+ expect(session.driver).to be_an_instance_of(Capybara::RackTest::Driver)
33
46
  end
34
47
  end
35
48
 
36
49
  describe '#mode' do
37
- it "should remember the mode" do
38
- expect(@session.mode).to eq(:rack_test)
50
+ it 'should remember the mode' do
51
+ expect(session.mode).to eq(:rack_test)
39
52
  end
40
53
  end
41
54
 
42
55
  describe '#click_link' do
43
- it "should use data-method if option is true" do
44
- @session.driver.options[:respect_data_method] = true
45
- @session.visit "/with_html"
46
- @session.click_link "A link with data-method"
47
- expect(@session.html).to include('The requested object was deleted')
56
+ after do
57
+ session.driver.options[:respect_data_method] = false
48
58
  end
49
59
 
50
- it "should not use data-method if option is false" do
51
- @session.driver.options[:respect_data_method] = false
52
- @session.visit "/with_html"
53
- @session.click_link "A link with data-method"
54
- expect(@session.html).to include('Not deleted')
60
+ it 'should use data-method if option is true' do
61
+ session.driver.options[:respect_data_method] = true
62
+ session.visit '/with_html'
63
+ session.click_link 'A link with data-method'
64
+ expect(session.html).to include('The requested object was deleted')
55
65
  end
56
66
 
57
- it "should use data-method if available even if it's capitalized" do
58
- @session.driver.options[:respect_data_method] = true
59
- @session.visit "/with_html"
60
- @session.click_link "A link with capitalized data-method"
61
- expect(@session.html).to include('The requested object was deleted')
67
+ it 'should not use data-method if option is false' do
68
+ session.driver.options[:respect_data_method] = false
69
+ session.visit '/with_html'
70
+ session.click_link 'A link with data-method'
71
+ expect(session.html).to include('Not deleted')
62
72
  end
63
73
 
64
- after do
65
- @session.driver.options[:respect_data_method] = false
74
+ it "should use data-method if available even if it's capitalized" do
75
+ session.driver.options[:respect_data_method] = true
76
+ session.visit '/with_html'
77
+ session.click_link 'A link with capitalized data-method'
78
+ expect(session.html).to include('The requested object was deleted')
66
79
  end
67
80
  end
68
81
 
69
- describe "#fill_in" do
70
- it "should warn that :fill_options are not supported" do
71
- allow_any_instance_of(Capybara::RackTest::Node).to receive(:warn)
72
- @session.visit "/with_html"
73
- field = @session.fill_in 'test_field', with: 'not_monkey', fill_options: { random: true }
74
- expect(@session).to have_field('test_field', with: 'not_monkey')
75
- expect(field.base).to have_received(:warn).with("Options passed to Node#set but the RackTest driver doesn't support any - ignoring")
82
+ describe '#fill_in' do
83
+ it 'should warn that :fill_options are not supported' do
84
+ session.visit '/with_html'
85
+ expect { session.fill_in 'test_field', with: 'not_monkey', fill_options: { random: true } }.to \
86
+ output(/^Options passed to Node#set but the RackTest driver doesn't support any - ignoring/).to_stderr
87
+ expect(session).to have_field('test_field', with: 'not_monkey')
76
88
  end
77
89
  end
78
90
 
79
- describe "#attach_file" do
80
- context "with multipart form" do
81
- it "should submit an empty form-data section if no file is submitted" do
82
- @session.visit("/form")
83
- @session.click_button("Upload Empty")
84
- expect(@session.html).to include('Successfully ignored empty file field.')
91
+ describe '#attach_file' do
92
+ context 'with multipart form' do
93
+ it 'should submit an empty form-data section if no file is submitted' do
94
+ session.visit('/form')
95
+ session.click_button('Upload Empty')
96
+ expect(session.html).to include('Successfully ignored empty file field.')
97
+ end
98
+
99
+ it 'should submit multipart even if no file is submitted' do
100
+ session.visit('/form')
101
+ session.click_button('Upload Empty')
102
+ expect(session.html).to include('Content type was multipart/form-data;')
85
103
  end
86
104
  end
87
105
 
88
- it "should not submit an obsolete mime type" do
89
- @test_jpg_file_path = File.expand_path('fixtures/capybara.csv', File.dirname(__FILE__))
90
- @session.visit("/form")
91
- @session.attach_file "form_document", @test_jpg_file_path
92
- @session.click_button('Upload Single')
93
- expect(@session).to have_content("Content-type: text/csv")
106
+ it 'should not submit an obsolete mime type' do
107
+ test_jpg_file_path = File.expand_path('fixtures/capybara.csv', File.dirname(__FILE__))
108
+ session.visit('/form')
109
+ session.attach_file 'form_document', test_jpg_file_path
110
+ session.click_button('Upload Single')
111
+ expect(session).to have_content('Content-type: text/csv')
94
112
  end
95
113
  end
96
114
 
97
- describe "#click" do
98
- context "on a label" do
99
- it "should toggle the associated checkbox" do
100
- @session.visit("/form")
101
- expect(@session).to have_unchecked_field('form_pets_cat')
102
- @session.find(:label, 'Cat').click
103
- expect(@session).to have_checked_field('form_pets_cat')
104
- @session.find(:label, 'Cat').click
105
- expect(@session).to have_unchecked_field('form_pets_cat')
106
- @session.find(:label, 'McLaren').click
107
- expect(@session).to have_checked_field('form_cars_mclaren', visible: :hidden)
115
+ describe '#click' do
116
+ context 'on a label' do
117
+ it 'should toggle the associated checkbox' do
118
+ session.visit('/form')
119
+ expect(session).to have_unchecked_field('form_pets_cat')
120
+ session.find(:label, 'Cat').click
121
+ expect(session).to have_checked_field('form_pets_cat')
122
+ session.find(:label, 'Cat').click
123
+ expect(session).to have_unchecked_field('form_pets_cat')
124
+ session.find(:label, 'McLaren').click
125
+ expect(session).to have_checked_field('form_cars_mclaren', visible: :hidden)
126
+ end
127
+
128
+ it 'should toggle the associated radio' do
129
+ session.visit('/form')
130
+ expect(session).to have_unchecked_field('gender_male')
131
+ session.find(:label, 'Male').click
132
+ expect(session).to have_checked_field('gender_male')
133
+ session.find(:label, 'Female').click
134
+ expect(session).to have_unchecked_field('gender_male')
108
135
  end
109
136
 
110
- it "should toggle the associated radio" do
111
- @session.visit("/form")
112
- expect(@session).to have_unchecked_field('gender_male')
113
- @session.find(:label, 'Male').click
114
- expect(@session).to have_checked_field('gender_male')
115
- @session.find(:label, 'Female').click
116
- expect(@session).to have_unchecked_field('gender_male')
137
+ it 'should rewrite the forms action query for get submission' do
138
+ session.visit('/form')
139
+ session.click_button('mediocre')
140
+ expect(session).not_to have_current_path(/foo|bar/)
141
+ end
142
+
143
+ it 'should rewrite the submit buttons formaction query for get submission' do
144
+ session.visit('/form')
145
+ session.click_button('mediocre2')
146
+ expect(session).not_to have_current_path(/foo|bar/)
117
147
  end
118
148
  end
119
149
  end
120
150
 
151
+ describe '#send_keys' do
152
+ it 'raises an UnsupportedMethodError' do
153
+ session.visit('/form')
154
+
155
+ expect { session.send_keys(:tab) }.to raise_error(Capybara::NotSupportedByDriverError)
156
+ end
157
+ end
158
+
159
+ describe '#active_element' do
160
+ it 'raises an UnsupportedMethodError' do
161
+ session.visit('/form')
162
+
163
+ expect { session.active_element }.to raise_error(Capybara::NotSupportedByDriverError)
164
+ end
165
+ end
166
+
121
167
  describe '#text' do
122
- it "should return original text content for textareas" do
123
- @session.visit('/with_html')
124
- @session.find_field('normal', type: 'textarea', with: 'banana').set('hello')
125
- normal = @session.find(:css, '#normal')
168
+ it 'should return original text content for textareas' do
169
+ session.visit('/with_html')
170
+ session.find_field('normal', type: 'textarea', with: 'banana').set('hello')
171
+ normal = session.find(:css, '#normal')
126
172
  expect(normal.value).to eq 'hello'
127
173
  expect(normal.text).to eq 'banana'
128
174
  end
129
175
  end
130
176
 
131
177
  describe '#style' do
132
- it "should raise an error" do
133
- @session.visit('/with_html')
134
- el = @session.find(:css, '#first')
178
+ it 'should raise an error' do
179
+ session.visit('/with_html')
180
+ el = session.find(:css, '#first')
135
181
  expect { el.style('display') }.to raise_error NotImplementedError, /not process CSS/
136
182
  end
137
183
  end
@@ -139,93 +185,103 @@ RSpec.describe Capybara::Session do # rubocop:disable RSpec/MultipleDescribes
139
185
  end
140
186
 
141
187
  RSpec.describe Capybara::RackTest::Driver do
142
- before do
143
- @driver = TestSessions::RackTest.driver
144
- end
188
+ let(:driver) { TestSessions::RackTest.driver }
145
189
 
146
190
  describe ':headers option' do
147
191
  it 'should always set headers' do
148
- @driver = Capybara::RackTest::Driver.new(TestApp, headers: { 'HTTP_FOO' => 'foobar' })
149
- @driver.visit('/get_header')
150
- expect(@driver.html).to include('foobar')
192
+ driver = described_class.new(TestApp, headers: { 'HTTP_FOO' => 'foobar' })
193
+ driver.visit('/get_header')
194
+ expect(driver.html).to include('foobar')
151
195
  end
152
196
 
153
197
  it 'should keep headers on link clicks' do
154
- @driver = Capybara::RackTest::Driver.new(TestApp, headers: { 'HTTP_FOO' => 'foobar' })
155
- @driver.visit('/header_links')
156
- @driver.find_xpath('.//a').first.click
157
- expect(@driver.html).to include('foobar')
198
+ driver = described_class.new(TestApp, headers: { 'HTTP_FOO' => 'foobar' })
199
+ driver.visit('/header_links')
200
+ driver.find_xpath('.//a').first.click
201
+ expect(driver.html).to include('foobar')
158
202
  end
159
203
 
160
204
  it 'should keep headers on form submit' do
161
- @driver = Capybara::RackTest::Driver.new(TestApp, headers: { 'HTTP_FOO' => 'foobar' })
162
- @driver.visit('/header_links')
163
- @driver.find_xpath('.//input').first.click
164
- expect(@driver.html).to include('foobar')
205
+ driver = described_class.new(TestApp, headers: { 'HTTP_FOO' => 'foobar' })
206
+ driver.visit('/header_links')
207
+ driver.find_xpath('.//input').first.click
208
+ expect(driver.html).to include('foobar')
165
209
  end
166
210
 
167
211
  it 'should keep headers on redirects' do
168
- @driver = Capybara::RackTest::Driver.new(TestApp, headers: { 'HTTP_FOO' => 'foobar' })
169
- @driver.visit('/get_header_via_redirect')
170
- expect(@driver.html).to include('foobar')
212
+ driver = described_class.new(TestApp, headers: { 'HTTP_FOO' => 'foobar' })
213
+ driver.visit('/get_header_via_redirect')
214
+ expect(driver.html).to include('foobar')
171
215
  end
172
216
  end
173
217
 
174
218
  describe ':follow_redirects option' do
175
- it "defaults to following redirects" do
176
- @driver = Capybara::RackTest::Driver.new(TestApp)
219
+ it 'defaults to following redirects' do
220
+ driver = described_class.new(TestApp)
177
221
 
178
- @driver.visit('/redirect')
179
- expect(@driver.response.header['Location']).to be_nil
180
- expect(@driver.current_url).to match %r{/landed$}
222
+ driver.visit('/redirect')
223
+ expect(driver.response.headers['Location']).to be_nil
224
+ expect(driver.current_url).to match %r{/landed$}
181
225
  end
182
226
 
183
- it "is possible to not follow redirects" do
184
- @driver = Capybara::RackTest::Driver.new(TestApp, follow_redirects: false)
227
+ it 'should not include fragments in the referer header' do
228
+ driver.visit('/header_links#an-anchor')
229
+ driver.find_xpath('.//input').first.click
230
+ expect(driver.request.get_header('HTTP_REFERER')).to eq('http://www.example.com/header_links')
231
+ end
232
+
233
+ it 'is possible to not follow redirects' do
234
+ driver = described_class.new(TestApp, follow_redirects: false)
185
235
 
186
- @driver.visit('/redirect')
187
- expect(@driver.response.header['Location']).to match %r{/redirect_again$}
188
- expect(@driver.current_url).to match %r{/redirect$}
236
+ driver.visit('/redirect')
237
+ expect(driver.response.headers['Location']).to match %r{/redirect_again$}
238
+ expect(driver.current_url).to match %r{/redirect$}
189
239
  end
190
240
  end
191
241
 
192
242
  describe ':redirect_limit option' do
193
- context "with default redirect limit" do
194
- before do
195
- @driver = Capybara::RackTest::Driver.new(TestApp)
196
- end
243
+ context 'with default redirect limit' do
244
+ let(:driver) { described_class.new(TestApp) }
197
245
 
198
- it "should follow 5 redirects" do
199
- @driver.visit("/redirect/5/times")
200
- expect(@driver.html).to include('redirection complete')
246
+ it 'should follow 5 redirects' do
247
+ driver.visit('/redirect/5/times')
248
+ expect(driver.html).to include('redirection complete')
201
249
  end
202
250
 
203
- it "should not follow more than 6 redirects" do
251
+ it 'should not follow more than 6 redirects' do
204
252
  expect do
205
- @driver.visit("/redirect/6/times")
253
+ driver.visit('/redirect/6/times')
206
254
  end.to raise_error(Capybara::InfiniteRedirectError)
207
255
  end
208
256
  end
209
257
 
210
- context "with 21 redirect limit" do
211
- before do
212
- @driver = Capybara::RackTest::Driver.new(TestApp, redirect_limit: 21)
213
- end
258
+ context 'with 21 redirect limit' do
259
+ let(:driver) { described_class.new(TestApp, redirect_limit: 21) }
214
260
 
215
- it "should follow 21 redirects" do
216
- @driver.visit("/redirect/21/times")
217
- expect(@driver.html).to include('redirection complete')
261
+ it 'should follow 21 redirects' do
262
+ driver.visit('/redirect/21/times')
263
+ expect(driver.html).to include('redirection complete')
218
264
  end
219
265
 
220
- it "should not follow more than 21 redirects" do
266
+ it 'should not follow more than 21 redirects' do
221
267
  expect do
222
- @driver.visit("/redirect/22/times")
268
+ driver.visit('/redirect/22/times')
223
269
  end.to raise_error(Capybara::InfiniteRedirectError)
224
270
  end
225
271
  end
226
272
  end
227
273
  end
228
274
 
275
+ RSpec.describe 'Capybara::String' do
276
+ it 'should use HTML5 parsing' do
277
+ skip 'Only valid if Nokogiri >= 1.12.0 or gumbo is included' unless defined? Nokogiri::HTML5
278
+ Capybara.use_html5_parsing = true
279
+ allow(Nokogiri::HTML5).to receive(:parse).and_call_original
280
+ Capybara.string('<div id=test_div></div>')
281
+ expect(Nokogiri::HTML5).to have_received(:parse)
282
+ end
283
+ end
284
+
229
285
  module CSSHandlerIncludeTester
230
286
  def dont_extend_css_handler
231
287
  raise 'should never be called'
@@ -235,7 +291,7 @@ end
235
291
  RSpec.describe Capybara::RackTest::CSSHandlers do
236
292
  include CSSHandlerIncludeTester
237
293
 
238
- it "should not be extended by global includes" do
239
- expect(Capybara::RackTest::CSSHandlers.new).not_to respond_to(:dont_extend_css_handler)
294
+ it 'should not be extended by global includes' do
295
+ expect(described_class.new).not_to respond_to(:dont_extend_css_handler)
240
296
  end
241
297
  end
@@ -0,0 +1,250 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Capybara::Selector::RegexpDisassembler, :aggregate_failures do
6
+ it 'handles strings' do
7
+ verify_strings(
8
+ /abcdef/ => %w[abcdef],
9
+ /abc def/ => ['abc def']
10
+ )
11
+ end
12
+
13
+ it 'handles escaped characters' do
14
+ verify_strings(
15
+ /abc\\def/ => %w[abc\def],
16
+ /abc\.def/ => %w[abc.def],
17
+ /\nabc/ => ["\nabc"],
18
+ %r{abc/} => %w[abc/],
19
+ /ab\++cd/ => %w[ab+ cd]
20
+ )
21
+ end
22
+
23
+ it 'handles wildcards' do
24
+ verify_strings(
25
+ /abc.*def/ => %w[abc def],
26
+ /.*def/ => %w[def],
27
+ /abc./ => %w[abc],
28
+ /abc.*/ => %w[abc],
29
+ /abc.def/ => %w[abc def],
30
+ /abc.def.ghi/ => %w[abc def ghi],
31
+ /abc.abcd.abcde/ => %w[abcde],
32
+ /.*/ => []
33
+ )
34
+ end
35
+
36
+ it 'ignores optional characters for substrings' do
37
+ {
38
+ /abc*def/ => %w[ab def],
39
+ /abc*/ => %w[ab],
40
+ /c*/ => [],
41
+ /abc?def/ => %w[ab def],
42
+ /abc?/ => %w[ab],
43
+ /abc?def?/ => %w[ab de],
44
+ /abc?def?g/ => %w[ab de g],
45
+ /d?/ => []
46
+ }.each do |regexp, expected|
47
+ expect(described_class.new(regexp).substrings).to eq expected
48
+ end
49
+ end
50
+
51
+ it 'handles optional characters for #alternated_substrings' do
52
+ verify_alternated_strings(
53
+ {
54
+ /abc*def/ => [%w[ab def]],
55
+ /abc*/ => [%w[ab]],
56
+ /c*/ => [],
57
+ /abc?def/ => [%w[abdef], %w[abcdef]],
58
+ /abc?/ => [%w[ab]],
59
+ /abc?def?/ => [%w[abde], %w[abcde]],
60
+ /abc?def?g/ => [%w[abdeg], %w[abdefg], %w[abcdeg], %w[abcdefg]],
61
+ /d?/ => []
62
+ }
63
+ )
64
+ end
65
+
66
+ it 'handles character classes' do
67
+ verify_strings(
68
+ /abc[a-z]/ => %w[abc],
69
+ /abc[a-z]def[0-9]g/ => %w[abc def g],
70
+ /[0-9]abc/ => %w[abc],
71
+ /[0-9]+/ => [],
72
+ /abc[0-9&&[^7]]/ => %w[abc]
73
+ )
74
+ end
75
+
76
+ it 'handles posix bracket expressions' do
77
+ verify_strings(
78
+ /abc[[:alpha:]]/ => %w[abc],
79
+ /[[:digit:]]abc/ => %w[abc],
80
+ /abc[[:print:]]def/ => %w[abc def]
81
+ )
82
+ end
83
+
84
+ it 'handles repitition' do
85
+ verify_strings(
86
+ /abc{3}/ => %w[abccc],
87
+ /abc{3}d/ => %w[abcccd],
88
+ /abc{0}/ => %w[ab],
89
+ /abc{,2}/ => %w[ab],
90
+ /abc{2,}/ => %w[abcc],
91
+ /def{1,5}/ => %w[def],
92
+ /abc+def/ => %w[abc def],
93
+ /ab(cde){,4}/ => %w[ab],
94
+ /(ab){,2}cd/ => %w[cd],
95
+ /(abc){2,3}/ => %w[abcabc],
96
+ /(abc){3}/ => %w[abcabcabc],
97
+ /ab{2,3}cd/ => %w[abb cd],
98
+ /(ab){2,3}cd/ => %w[abab cd]
99
+ )
100
+ end
101
+
102
+ it 'handles non-greedy repetition' do
103
+ verify_strings(
104
+ /abc.*?/ => %w[abc],
105
+ /abc+?/ => %w[abc],
106
+ /abc*?cde/ => %w[ab cde],
107
+ /(abc)+?def/ => %w[abc def],
108
+ /ab(cde)*?fg/ => %w[ab fg]
109
+ )
110
+ end
111
+
112
+ it 'ignores alternation for #substrings' do
113
+ {
114
+ /abc|def/ => [],
115
+ /ab(?:c|d)/ => %w[ab],
116
+ /ab(c|d|e)fg/ => %w[ab fg],
117
+ /ab?(c|d)fg/ => %w[a fg],
118
+ /ab(c|d)ef/ => %w[ab ef],
119
+ /ab(cd?|ef)g/ => %w[ab g],
120
+ /ab(cd|ef*)g/ => %w[ab g],
121
+ /ab|cd*/ => [],
122
+ /cd(?:ef|gh)|xyz/ => [],
123
+ /(cd(?:ef|gh)|xyz)/ => [],
124
+ /cd(ef|gh)+/ => %w[cd],
125
+ /cd(ef|gh)?/ => %w[cd],
126
+ /cd(ef|gh)?ij/ => %w[cd ij],
127
+ /cd(ef|gh)+ij/ => %w[cd ij],
128
+ /cd(ef|gh){2}ij/ => %w[cd ij],
129
+ /(cd(ef|g*))/ => %w[cd],
130
+ /ab(cd){0,2}ef/ => %w[ab ef],
131
+ /ab(cd){0,1}ef/ => %w[ab ef],
132
+ /ab(cd|cd)ef/ => %w[ab ef],
133
+ /ab(cd|cd)?ef/ => %w[ab ef],
134
+ /ab\\?cd/ => %w[ab cd]
135
+ }.each do |regexp, expected|
136
+ expect(described_class.new(regexp).substrings).to eq expected
137
+ end
138
+ end
139
+
140
+ it 'handles alternation for #alternated_substrings' do
141
+ verify_alternated_strings(
142
+ {
143
+ /abc|def/ => [%w[abc], %w[def]],
144
+ /ab(?:c|d)/ => [%w[abc], %w[abd]],
145
+ /ab(c|d|e)fg/ => [%w[abcfg], %w[abdfg], %w[abefg]],
146
+ /ab?(c|d)fg/ => [%w[acfg], %w[adfg], %w[abcfg], %w[abdfg]],
147
+ /ab(c|d)ef/ => [%w[abcef], %w[abdef]],
148
+ /ab(cd?|ef)g/ => [%w[abcg], %w[abcdg], %w[abefg]],
149
+ /ab(cd|ef*)g/ => [%w[abcdg], %w[abe g]],
150
+ /ab|cd*/ => [%w[ab], %w[c]],
151
+ /cd(?:ef|gh)|xyz/ => [%w[cdef], %w[cdgh], %w[xyz]],
152
+ /(cd(?:ef|gh)|xyz)/ => [%w[cdef], %w[cdgh], %w[xyz]],
153
+ /cd(ef|gh)+/ => [%w[cdef], %w[cdgh]],
154
+ /cd(ef|gh)?/ => [%w[cd]],
155
+ /cd(ef|gh)?ij/ => [%w[cdij], %w[cdefij], %w[cdghij]],
156
+ /cd(ef|gh)+ij/ => [%w[cdef ij], %w[cdgh ij]],
157
+ /cd(ef|gh){2}ij/ => [%w[cdefefij], %w[cdefghij], %w[cdghefij], %w[cdghghij]],
158
+ /(cd(ef|g*))/ => [%w[cd]],
159
+ /a|b*/ => [],
160
+ /ab(?:c|d?)/ => [%w[ab]],
161
+ /ab(c|d)|a*/ => [],
162
+ /(abc)?(d|e)/ => [%w[d], %w[e]],
163
+ /(abc*de)?(d|e)/ => [%w[d], %w[e]],
164
+ /(abc*de)?(d|e?)/ => [],
165
+ /(abc)?(d|e?)/ => [],
166
+ /ab(cd){0,2}ef/ => [%w[ab ef]],
167
+ /ab(cd){0,1}ef/ => [%w[abef], %w[abcdef]],
168
+ /ab(cd|cd)ef/ => [%w[abcdef]],
169
+ /ab(cd|cd)?ef/ => [%w[abef], %w[abcdef]],
170
+ /ab\\?cd/ => [%w[abcd], %w[ab\cd]]
171
+ }
172
+ )
173
+ end
174
+
175
+ it 'handles grouping' do
176
+ verify_strings(
177
+ /(abc)/ => %w[abc],
178
+ /(abc)?/ => [],
179
+ /ab(cde)/ => %w[abcde],
180
+ /(abc)de/ => %w[abcde],
181
+ /ab(cde)fg/ => %w[abcdefg],
182
+ /ab(?<name>cd)ef/ => %w[abcdef],
183
+ /gh(?>ij)kl/ => %w[ghijkl],
184
+ /m(n.*p)q/ => %w[mn pq],
185
+ /(?:ab(cd)*){2,3}/ => %w[ab],
186
+ /(ab(cd){3})?/ => [],
187
+ /(ab(cd)+){2}/ => %w[abcd]
188
+ )
189
+ end
190
+
191
+ it 'handles meta characters' do
192
+ verify_strings(
193
+ /abc\d/ => %w[abc],
194
+ /abc\wdef/ => %w[abc def],
195
+ /\habc/ => %w[abc]
196
+ )
197
+ end
198
+
199
+ it 'handles character properties' do
200
+ verify_strings(
201
+ /ab\p{Alpha}cd/ => %w[ab cd],
202
+ /ab\p{Blank}/ => %w[ab],
203
+ /\p{Digit}cd/ => %w[cd]
204
+ )
205
+ end
206
+
207
+ it 'handles backreferences' do
208
+ verify_strings(
209
+ /a(?<group>abc).\k<group>.+/ => %w[aabc]
210
+ )
211
+ end
212
+
213
+ it 'handles subexpressions' do
214
+ verify_strings(
215
+ /\A(?<paren>a\g<paren>*b)+\z/ => %w[a b]
216
+ )
217
+ end
218
+
219
+ it 'ignores negative lookaheads' do
220
+ verify_strings(
221
+ /^(?!.*\bContributing Editor\b).*$/ => %w[],
222
+ /abc(?!.*def).*/ => %w[abc],
223
+ /(?!.*def)abc/ => %w[abc],
224
+ /abc(?!.*def.*).*ghi/ => %w[abc ghi],
225
+ /abc(?!.*bcd)def/ => %w[abcdef]
226
+ )
227
+ end
228
+
229
+ it 'handles anchors' do
230
+ verify_strings(
231
+ /^abc/ => %w[abc],
232
+ /def$/ => %w[def],
233
+ /^abc$/ => %w[abc]
234
+ )
235
+ end
236
+
237
+ def verify_strings(hsh)
238
+ hsh.each do |regexp, expected|
239
+ expect(Capybara::Selector::RegexpDisassembler.new(regexp).substrings).to eq expected
240
+ end
241
+ verify_alternated_strings(hsh, wrap: true)
242
+ end
243
+
244
+ def verify_alternated_strings(hsh, wrap: false)
245
+ hsh.each do |regexp, expected|
246
+ expected = [expected] if wrap && (expected != [])
247
+ expect(Capybara::Selector::RegexpDisassembler.new(regexp).alternated_substrings).to eq expected
248
+ end
249
+ end
250
+ end