capybara 2.18.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 (316) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +945 -12
  4. data/License.txt +1 -1
  5. data/README.md +264 -90
  6. data/lib/capybara/config.rb +29 -57
  7. data/lib/capybara/cucumber.rb +2 -3
  8. data/lib/capybara/driver/base.rb +35 -18
  9. data/lib/capybara/driver/node.rb +40 -10
  10. data/lib/capybara/dsl.rb +10 -7
  11. data/lib/capybara/helpers.rb +70 -31
  12. data/lib/capybara/minitest/spec.rb +185 -83
  13. data/lib/capybara/minitest.rb +232 -112
  14. data/lib/capybara/node/actions.rb +274 -171
  15. data/lib/capybara/node/base.rb +42 -34
  16. data/lib/capybara/node/document.rb +15 -3
  17. data/lib/capybara/node/document_matchers.rb +19 -21
  18. data/lib/capybara/node/element.rb +362 -135
  19. data/lib/capybara/node/finders.rb +151 -137
  20. data/lib/capybara/node/matchers.rb +394 -209
  21. data/lib/capybara/node/simple.rb +59 -26
  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 +12 -9
  25. data/lib/capybara/queries/base_query.rb +39 -28
  26. data/lib/capybara/queries/current_path_query.rb +21 -27
  27. data/lib/capybara/queries/match_query.rb +14 -7
  28. data/lib/capybara/queries/selector_query.rb +659 -149
  29. data/lib/capybara/queries/sibling_query.rb +11 -9
  30. data/lib/capybara/queries/style_query.rb +45 -0
  31. data/lib/capybara/queries/text_query.rb +56 -38
  32. data/lib/capybara/queries/title_query.rb +8 -11
  33. data/lib/capybara/rack_test/browser.rb +114 -42
  34. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  35. data/lib/capybara/rack_test/driver.rb +22 -17
  36. data/lib/capybara/rack_test/errors.rb +6 -0
  37. data/lib/capybara/rack_test/form.rb +93 -58
  38. data/lib/capybara/rack_test/node.rb +184 -81
  39. data/lib/capybara/rails.rb +3 -7
  40. data/lib/capybara/registration_container.rb +41 -0
  41. data/lib/capybara/registrations/drivers.rb +42 -0
  42. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  43. data/lib/capybara/registrations/servers.rb +66 -0
  44. data/lib/capybara/result.rb +97 -63
  45. data/lib/capybara/rspec/features.rb +17 -50
  46. data/lib/capybara/rspec/matcher_proxies.rb +52 -15
  47. data/lib/capybara/rspec/matchers/base.rb +113 -0
  48. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  49. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  50. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  51. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  52. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  53. data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
  54. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  55. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  56. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  57. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  58. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  59. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  60. data/lib/capybara/rspec/matchers.rb +146 -310
  61. data/lib/capybara/rspec.rb +7 -11
  62. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  63. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  64. data/lib/capybara/selector/css.rb +85 -13
  65. data/lib/capybara/selector/definition/button.rb +68 -0
  66. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  67. data/lib/capybara/selector/definition/css.rb +10 -0
  68. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  69. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  70. data/lib/capybara/selector/definition/element.rb +28 -0
  71. data/lib/capybara/selector/definition/field.rb +40 -0
  72. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  73. data/lib/capybara/selector/definition/file_field.rb +13 -0
  74. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  75. data/lib/capybara/selector/definition/frame.rb +17 -0
  76. data/lib/capybara/selector/definition/id.rb +6 -0
  77. data/lib/capybara/selector/definition/label.rb +62 -0
  78. data/lib/capybara/selector/definition/link.rb +55 -0
  79. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  80. data/lib/capybara/selector/definition/option.rb +27 -0
  81. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  82. data/lib/capybara/selector/definition/select.rb +81 -0
  83. data/lib/capybara/selector/definition/table.rb +109 -0
  84. data/lib/capybara/selector/definition/table_row.rb +21 -0
  85. data/lib/capybara/selector/definition/xpath.rb +5 -0
  86. data/lib/capybara/selector/definition.rb +280 -0
  87. data/lib/capybara/selector/filter.rb +2 -17
  88. data/lib/capybara/selector/filter_set.rb +80 -33
  89. data/lib/capybara/selector/filters/base.rb +50 -6
  90. data/lib/capybara/selector/filters/expression_filter.rb +8 -26
  91. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  92. data/lib/capybara/selector/filters/node_filter.rb +16 -12
  93. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  94. data/lib/capybara/selector/selector.rb +93 -210
  95. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  96. data/lib/capybara/selector.rb +475 -523
  97. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  98. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  99. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  100. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  101. data/lib/capybara/selenium/driver.rb +298 -267
  102. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  103. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  104. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
  105. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  106. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  107. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  108. data/lib/capybara/selenium/extensions/find.rb +110 -0
  109. data/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
  110. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  111. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  112. data/lib/capybara/selenium/node.rb +517 -145
  113. data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
  114. data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
  115. data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  116. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  117. data/lib/capybara/selenium/nodes/safari_node.rb +118 -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 +80 -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 +59 -67
  127. data/lib/capybara/session/config.rb +81 -67
  128. data/lib/capybara/session/matchers.rb +28 -20
  129. data/lib/capybara/session.rb +337 -365
  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 +151 -12
  133. data/lib/capybara/spec/session/accept_alert_spec.rb +12 -11
  134. data/lib/capybara/spec/session/accept_confirm_spec.rb +6 -5
  135. data/lib/capybara/spec/session/accept_prompt_spec.rb +10 -10
  136. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  137. data/lib/capybara/spec/session/all_spec.rb +161 -57
  138. data/lib/capybara/spec/session/ancestor_spec.rb +27 -24
  139. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +68 -38
  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.rb → assert_title_spec.rb} +22 -12
  145. data/lib/capybara/spec/session/attach_file_spec.rb +144 -69
  146. data/lib/capybara/spec/session/body_spec.rb +12 -13
  147. data/lib/capybara/spec/session/check_spec.rb +117 -55
  148. data/lib/capybara/spec/session/choose_spec.rb +64 -31
  149. data/lib/capybara/spec/session/click_button_spec.rb +231 -173
  150. data/lib/capybara/spec/session/click_link_or_button_spec.rb +55 -35
  151. data/lib/capybara/spec/session/click_link_spec.rb +93 -58
  152. data/lib/capybara/spec/session/current_scope_spec.rb +12 -11
  153. data/lib/capybara/spec/session/current_url_spec.rb +57 -39
  154. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +4 -4
  155. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +3 -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 +9 -7
  159. data/lib/capybara/spec/session/element/matches_selector_spec.rb +71 -57
  160. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +8 -7
  161. data/lib/capybara/spec/session/evaluate_script_spec.rb +29 -8
  162. data/lib/capybara/spec/session/execute_script_spec.rb +10 -8
  163. data/lib/capybara/spec/session/fill_in_spec.rb +134 -43
  164. data/lib/capybara/spec/session/find_button_spec.rb +25 -24
  165. data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
  166. data/lib/capybara/spec/session/find_field_spec.rb +37 -41
  167. data/lib/capybara/spec/session/find_link_spec.rb +46 -17
  168. data/lib/capybara/spec/session/find_spec.rb +260 -145
  169. data/lib/capybara/spec/session/first_spec.rb +80 -52
  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 +33 -20
  173. data/lib/capybara/spec/session/frame/within_frame_spec.rb +52 -32
  174. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  175. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  176. data/lib/capybara/spec/session/has_all_selectors_spec.rb +31 -31
  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 +100 -13
  180. data/lib/capybara/spec/session/has_css_spec.rb +272 -137
  181. data/lib/capybara/spec/session/has_current_path_spec.rb +60 -61
  182. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  183. data/lib/capybara/spec/session/has_field_spec.rb +139 -59
  184. data/lib/capybara/spec/session/has_link_spec.rb +47 -6
  185. data/lib/capybara/spec/session/has_none_selectors_spec.rb +42 -40
  186. data/lib/capybara/spec/session/has_select_spec.rb +107 -72
  187. data/lib/capybara/spec/session/has_selector_spec.rb +120 -71
  188. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  189. data/lib/capybara/spec/session/has_table_spec.rb +183 -5
  190. data/lib/capybara/spec/session/has_text_spec.rb +106 -62
  191. data/lib/capybara/spec/session/has_title_spec.rb +20 -14
  192. data/lib/capybara/spec/session/has_xpath_spec.rb +57 -38
  193. data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
  194. data/lib/capybara/spec/session/html_spec.rb +14 -6
  195. data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
  196. data/lib/capybara/spec/session/node_spec.rb +1024 -153
  197. data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
  198. data/lib/capybara/spec/session/refresh_spec.rb +12 -6
  199. data/lib/capybara/spec/session/reset_session_spec.rb +82 -35
  200. data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
  201. data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
  202. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +8 -12
  203. data/lib/capybara/spec/session/save_page_spec.rb +42 -55
  204. data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
  205. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  206. data/lib/capybara/spec/session/scroll_spec.rb +119 -0
  207. data/lib/capybara/spec/session/select_spec.rb +107 -81
  208. data/lib/capybara/spec/session/selectors_spec.rb +52 -19
  209. data/lib/capybara/spec/session/sibling_spec.rb +10 -10
  210. data/lib/capybara/spec/session/text_spec.rb +37 -21
  211. data/lib/capybara/spec/session/title_spec.rb +17 -5
  212. data/lib/capybara/spec/session/uncheck_spec.rb +43 -23
  213. data/lib/capybara/spec/session/unselect_spec.rb +39 -38
  214. data/lib/capybara/spec/session/visit_spec.rb +85 -53
  215. data/lib/capybara/spec/session/window/become_closed_spec.rb +24 -20
  216. data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
  217. data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
  218. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +27 -22
  219. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +12 -6
  220. data/lib/capybara/spec/session/window/window_spec.rb +97 -63
  221. data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
  222. data/lib/capybara/spec/session/window/within_window_spec.rb +31 -86
  223. data/lib/capybara/spec/session/within_spec.rb +83 -44
  224. data/lib/capybara/spec/spec_helper.rb +54 -44
  225. data/lib/capybara/spec/test_app.rb +158 -43
  226. data/lib/capybara/spec/views/animated.erb +49 -0
  227. data/lib/capybara/spec/views/form.erb +163 -42
  228. data/lib/capybara/spec/views/frame_child.erb +4 -3
  229. data/lib/capybara/spec/views/frame_one.erb +2 -1
  230. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  231. data/lib/capybara/spec/views/frame_two.erb +1 -1
  232. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  233. data/lib/capybara/spec/views/layout.erb +10 -0
  234. data/lib/capybara/spec/views/obscured.erb +47 -0
  235. data/lib/capybara/spec/views/offset.erb +33 -0
  236. data/lib/capybara/spec/views/path.erb +2 -2
  237. data/lib/capybara/spec/views/popup_one.erb +1 -1
  238. data/lib/capybara/spec/views/popup_two.erb +1 -1
  239. data/lib/capybara/spec/views/react.erb +45 -0
  240. data/lib/capybara/spec/views/scroll.erb +21 -0
  241. data/lib/capybara/spec/views/spatial.erb +31 -0
  242. data/lib/capybara/spec/views/tables.erb +68 -1
  243. data/lib/capybara/spec/views/with_animation.erb +81 -0
  244. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  245. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  246. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  247. data/lib/capybara/spec/views/with_hover.erb +3 -2
  248. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  249. data/lib/capybara/spec/views/with_html.erb +69 -12
  250. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  251. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  252. data/lib/capybara/spec/views/with_js.erb +30 -5
  253. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  254. data/lib/capybara/spec/views/with_namespace.erb +21 -0
  255. data/lib/capybara/spec/views/with_scope.erb +2 -2
  256. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  257. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  258. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  259. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  260. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  261. data/lib/capybara/spec/views/with_windows.erb +1 -1
  262. data/lib/capybara/spec/views/within_frames.erb +5 -2
  263. data/lib/capybara/version.rb +2 -1
  264. data/lib/capybara/window.rb +36 -34
  265. data/lib/capybara.rb +134 -107
  266. data/spec/basic_node_spec.rb +60 -34
  267. data/spec/capybara_spec.rb +63 -88
  268. data/spec/counter_spec.rb +35 -0
  269. data/spec/css_builder_spec.rb +101 -0
  270. data/spec/css_splitter_spec.rb +38 -0
  271. data/spec/dsl_spec.rb +85 -64
  272. data/spec/filter_set_spec.rb +27 -9
  273. data/spec/fixtures/certificate.pem +25 -0
  274. data/spec/fixtures/key.pem +27 -0
  275. data/spec/fixtures/selenium_driver_rspec_failure.rb +6 -5
  276. data/spec/fixtures/selenium_driver_rspec_success.rb +6 -5
  277. data/spec/minitest_spec.rb +52 -7
  278. data/spec/minitest_spec_spec.rb +94 -63
  279. data/spec/per_session_config_spec.rb +14 -13
  280. data/spec/rack_test_spec.rb +194 -125
  281. data/spec/regexp_dissassembler_spec.rb +250 -0
  282. data/spec/result_spec.rb +111 -50
  283. data/spec/rspec/features_spec.rb +37 -31
  284. data/spec/rspec/scenarios_spec.rb +10 -8
  285. data/spec/rspec/shared_spec_matchers.rb +473 -422
  286. data/spec/rspec/views_spec.rb +5 -3
  287. data/spec/rspec_matchers_spec.rb +52 -11
  288. data/spec/rspec_spec.rb +109 -89
  289. data/spec/sauce_spec_chrome.rb +43 -0
  290. data/spec/selector_spec.rb +397 -68
  291. data/spec/selenium_spec_chrome.rb +187 -40
  292. data/spec/selenium_spec_chrome_remote.rb +96 -0
  293. data/spec/selenium_spec_edge.rb +60 -0
  294. data/spec/selenium_spec_firefox.rb +201 -41
  295. data/spec/selenium_spec_firefox_remote.rb +94 -0
  296. data/spec/selenium_spec_ie.rb +149 -0
  297. data/spec/selenium_spec_safari.rb +162 -0
  298. data/spec/server_spec.rb +213 -102
  299. data/spec/session_spec.rb +53 -16
  300. data/spec/shared_selenium_node.rb +79 -0
  301. data/spec/shared_selenium_session.rb +473 -122
  302. data/spec/spec_helper.rb +126 -7
  303. data/spec/whitespace_normalizer_spec.rb +54 -0
  304. data/spec/xpath_builder_spec.rb +93 -0
  305. metadata +355 -73
  306. data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
  307. data/.yard/templates_custom/default/class/html/setup.rb +0 -17
  308. data/.yard/yard_extensions.rb +0 -78
  309. data/lib/capybara/query.rb +0 -7
  310. data/lib/capybara/rspec/compound.rb +0 -95
  311. data/lib/capybara/spec/session/assert_current_path.rb +0 -72
  312. data/lib/capybara/spec/session/assert_selector.rb +0 -148
  313. data/lib/capybara/spec/session/assert_text.rb +0 -234
  314. data/lib/capybara/spec/session/source_spec.rb +0 -0
  315. data/lib/capybara/spec/views/with_title.erb +0 -5
  316. data/spec/selenium_spec_marionette.rb +0 -127
@@ -1,228 +1,297 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'spec_helper'
3
4
 
4
5
  module TestSessions
5
6
  RackTest = Capybara::Session.new(:rack_test, TestApp)
6
7
  end
7
8
 
8
- Capybara::SpecHelper.run_specs TestSessions::RackTest, "RackTest", capybara_skip: [
9
- :js,
10
- :modals,
11
- :screenshot,
12
- :frames,
13
- :windows,
14
- :send_keys,
15
- :server,
16
- :hover,
17
- :about_scheme,
9
+ skipped_tests = %i[
10
+ js
11
+ modals
12
+ screenshot
13
+ frames
14
+ windows
15
+ send_keys
16
+ server
17
+ hover
18
+ about_scheme
19
+ download
20
+ css
21
+ scroll
22
+ spatial
23
+ html_validation
24
+ shadow_dom
25
+ active_element
18
26
  ]
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
19
37
 
20
- RSpec.describe Capybara::Session do
38
+ RSpec.describe Capybara::Session do # rubocop:disable RSpec/MultipleDescribes
39
+ include Capybara::RSpecMatchers
21
40
  context 'with rack test driver' do
22
- before do
23
- @session = TestSessions::RackTest
24
- end
41
+ let(:session) { TestSessions::RackTest }
25
42
 
26
43
  describe '#driver' do
27
- it "should be a rack test driver" do
28
- 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)
29
46
  end
30
47
  end
31
48
 
32
49
  describe '#mode' do
33
- it "should remember the mode" do
34
- expect(@session.mode).to eq(:rack_test)
50
+ it 'should remember the mode' do
51
+ expect(session.mode).to eq(:rack_test)
35
52
  end
36
53
  end
37
54
 
38
55
  describe '#click_link' do
39
- it "should use data-method if option is true" do
40
- @session.driver.options[:respect_data_method] = true
41
- @session.visit "/with_html"
42
- @session.click_link "A link with data-method"
43
- expect(@session.html).to include('The requested object was deleted')
56
+ after do
57
+ session.driver.options[:respect_data_method] = false
44
58
  end
45
59
 
46
- it "should not use data-method if option is false" do
47
- @session.driver.options[:respect_data_method] = false
48
- @session.visit "/with_html"
49
- @session.click_link "A link with data-method"
50
- 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')
51
65
  end
52
66
 
53
- it "should use data-method if available even if it's capitalized" do
54
- @session.driver.options[:respect_data_method] = true
55
- @session.visit "/with_html"
56
- @session.click_link "A link with capitalized data-method"
57
- 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')
58
72
  end
59
73
 
60
- after do
61
- @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')
62
79
  end
63
80
  end
64
81
 
65
- describe "#fill_in" do
66
- it "should warn that :fill_options are not supported" do
67
- expect_any_instance_of(Capybara::Node::Element).to receive(:warn)
68
- .with("Options passed to Capybara::Node#set but the driver doesn't support them")
69
- @session.visit "/with_html"
70
- @session.fill_in 'test_field', with: 'not_moneky', fill_options: { random: true }
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')
71
88
  end
72
89
  end
73
90
 
74
- describe "#attach_file" do
75
- context "with multipart form" do
76
- it "should submit an empty form-data section if no file is submitted" do
77
- @session.visit("/form")
78
- @session.click_button("Upload Empty")
79
- 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;')
80
103
  end
81
104
  end
82
105
 
83
- it "should not submit an obsolete mime type" do
84
- @test_jpg_file_path = File.expand_path('fixtures/capybara.csv', File.dirname(__FILE__))
85
- @session.visit("/form")
86
- @session.attach_file "form_document", @test_jpg_file_path
87
- @session.click_button('Upload Single')
88
- 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')
89
112
  end
90
113
  end
91
114
 
92
- describe "#click" do
93
- context "on a label" do
94
- it "should toggle the associated checkbox" do
95
- @session.visit("/form")
96
- expect(@session).to have_unchecked_field('form_pets_cat')
97
- @session.find(:label, 'Cat').click
98
- expect(@session).to have_checked_field('form_pets_cat')
99
- @session.find(:label, 'Cat').click
100
- expect(@session).to have_unchecked_field('form_pets_cat')
101
- @session.find(:label, 'McLaren').click
102
- 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')
135
+ end
136
+
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/)
103
141
  end
104
142
 
105
- it "should toggle the associated radio" do
106
- @session.visit("/form")
107
- expect(@session).to have_unchecked_field('gender_male')
108
- @session.find(:label, 'Male').click
109
- expect(@session).to have_checked_field('gender_male')
110
- @session.find(:label, 'Female').click
111
- expect(@session).to have_unchecked_field('gender_male')
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/)
112
147
  end
113
148
  end
114
149
  end
115
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
+
116
167
  describe '#text' do
117
- it "should return original text content for textareas" do
118
- @session.visit('/with_html')
119
- @session.find_field('normal', type: 'textarea', with: 'banana').set('hello')
120
- 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')
121
172
  expect(normal.value).to eq 'hello'
122
173
  expect(normal.text).to eq 'banana'
123
174
  end
124
175
  end
176
+
177
+ describe '#style' do
178
+ it 'should raise an error' do
179
+ session.visit('/with_html')
180
+ el = session.find(:css, '#first')
181
+ expect { el.style('display') }.to raise_error NotImplementedError, /not process CSS/
182
+ end
183
+ end
125
184
  end
126
185
  end
127
186
 
128
187
  RSpec.describe Capybara::RackTest::Driver do
129
- before do
130
- @driver = TestSessions::RackTest.driver
131
- end
188
+ let(:driver) { TestSessions::RackTest.driver }
132
189
 
133
190
  describe ':headers option' do
134
191
  it 'should always set headers' do
135
- @driver = Capybara::RackTest::Driver.new(TestApp, headers: {'HTTP_FOO' => 'foobar'})
136
- @driver.visit('/get_header')
137
- 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')
138
195
  end
139
196
 
140
197
  it 'should keep headers on link clicks' do
141
- @driver = Capybara::RackTest::Driver.new(TestApp, headers: {'HTTP_FOO' => 'foobar'})
142
- @driver.visit('/header_links')
143
- @driver.find_xpath('.//a').first.click
144
- 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')
145
202
  end
146
203
 
147
204
  it 'should keep headers on form submit' do
148
- @driver = Capybara::RackTest::Driver.new(TestApp, headers: {'HTTP_FOO' => 'foobar'})
149
- @driver.visit('/header_links')
150
- @driver.find_xpath('.//input').first.click
151
- 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')
152
209
  end
153
210
 
154
211
  it 'should keep headers on redirects' do
155
- @driver = Capybara::RackTest::Driver.new(TestApp, headers: {'HTTP_FOO' => 'foobar'})
156
- @driver.visit('/get_header_via_redirect')
157
- 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')
158
215
  end
159
216
  end
160
217
 
161
218
  describe ':follow_redirects option' do
162
- it "defaults to following redirects" do
163
- @driver = Capybara::RackTest::Driver.new(TestApp)
219
+ it 'defaults to following redirects' do
220
+ driver = described_class.new(TestApp)
164
221
 
165
- @driver.visit('/redirect')
166
- expect(@driver.response.header['Location']).to be_nil
167
- 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$}
168
225
  end
169
226
 
170
- it "is possible to not follow redirects" do
171
- @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
172
232
 
173
- @driver.visit('/redirect')
174
- expect(@driver.response.header['Location']).to match %r{/redirect_again$}
175
- expect(@driver.current_url).to match %r{/redirect$}
233
+ it 'is possible to not follow redirects' do
234
+ driver = described_class.new(TestApp, follow_redirects: false)
235
+
236
+ driver.visit('/redirect')
237
+ expect(driver.response.headers['Location']).to match %r{/redirect_again$}
238
+ expect(driver.current_url).to match %r{/redirect$}
176
239
  end
177
240
  end
178
241
 
179
242
  describe ':redirect_limit option' do
180
- context "with default redirect limit" do
181
- before do
182
- @driver = Capybara::RackTest::Driver.new(TestApp)
183
- end
243
+ context 'with default redirect limit' do
244
+ let(:driver) { described_class.new(TestApp) }
184
245
 
185
- it "should follow 5 redirects" do
186
- @driver.visit("/redirect/5/times")
187
- 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')
188
249
  end
189
250
 
190
- it "should not follow more than 6 redirects" do
251
+ it 'should not follow more than 6 redirects' do
191
252
  expect do
192
- @driver.visit("/redirect/6/times")
253
+ driver.visit('/redirect/6/times')
193
254
  end.to raise_error(Capybara::InfiniteRedirectError)
194
255
  end
195
256
  end
196
257
 
197
- context "with 21 redirect limit" do
198
- before do
199
- @driver = Capybara::RackTest::Driver.new(TestApp, redirect_limit: 21)
200
- end
258
+ context 'with 21 redirect limit' do
259
+ let(:driver) { described_class.new(TestApp, redirect_limit: 21) }
201
260
 
202
- it "should follow 21 redirects" do
203
- @driver.visit("/redirect/21/times")
204
- 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')
205
264
  end
206
265
 
207
- it "should not follow more than 21 redirects" do
266
+ it 'should not follow more than 21 redirects' do
208
267
  expect do
209
- @driver.visit("/redirect/22/times")
268
+ driver.visit('/redirect/22/times')
210
269
  end.to raise_error(Capybara::InfiniteRedirectError)
211
270
  end
212
271
  end
213
272
  end
214
273
  end
215
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
+
216
285
  module CSSHandlerIncludeTester
217
286
  def dont_extend_css_handler
218
287
  raise 'should never be called'
219
288
  end
220
289
  end
221
- include CSSHandlerIncludeTester
222
290
 
223
- RSpec.describe Capybara::RackTest::CSSHandlers do
224
- it "should not be extended by global includes" do
225
- expect(Capybara::RackTest::CSSHandlers.new).not_to respond_to(:dont_extend_css_handler)
291
+ RSpec.describe Capybara::RackTest::CSSHandlers do
292
+ include CSSHandlerIncludeTester
293
+
294
+ it 'should not be extended by global includes' do
295
+ expect(described_class.new).not_to respond_to(:dont_extend_css_handler)
226
296
  end
227
297
  end
228
-
@@ -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