capybara 3.32.2

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 (313) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/History.md +1813 -0
  4. data/License.txt +22 -0
  5. data/README.md +1099 -0
  6. data/lib/capybara.rb +511 -0
  7. data/lib/capybara/config.rb +94 -0
  8. data/lib/capybara/cucumber.rb +27 -0
  9. data/lib/capybara/driver/base.rb +170 -0
  10. data/lib/capybara/driver/node.rb +139 -0
  11. data/lib/capybara/dsl.rb +65 -0
  12. data/lib/capybara/helpers.rb +108 -0
  13. data/lib/capybara/minitest.rb +386 -0
  14. data/lib/capybara/minitest/spec.rb +264 -0
  15. data/lib/capybara/node/actions.rb +420 -0
  16. data/lib/capybara/node/base.rb +143 -0
  17. data/lib/capybara/node/document.rb +48 -0
  18. data/lib/capybara/node/document_matchers.rb +67 -0
  19. data/lib/capybara/node/element.rb +606 -0
  20. data/lib/capybara/node/finders.rb +325 -0
  21. data/lib/capybara/node/matchers.rb +883 -0
  22. data/lib/capybara/node/simple.rb +208 -0
  23. data/lib/capybara/queries/ancestor_query.rb +27 -0
  24. data/lib/capybara/queries/base_query.rb +106 -0
  25. data/lib/capybara/queries/current_path_query.rb +51 -0
  26. data/lib/capybara/queries/match_query.rb +26 -0
  27. data/lib/capybara/queries/selector_query.rb +710 -0
  28. data/lib/capybara/queries/sibling_query.rb +26 -0
  29. data/lib/capybara/queries/style_query.rb +45 -0
  30. data/lib/capybara/queries/text_query.rb +110 -0
  31. data/lib/capybara/queries/title_query.rb +39 -0
  32. data/lib/capybara/rack_test/browser.rb +140 -0
  33. data/lib/capybara/rack_test/css_handlers.rb +13 -0
  34. data/lib/capybara/rack_test/driver.rb +109 -0
  35. data/lib/capybara/rack_test/errors.rb +6 -0
  36. data/lib/capybara/rack_test/form.rb +127 -0
  37. data/lib/capybara/rack_test/node.rb +325 -0
  38. data/lib/capybara/rails.rb +16 -0
  39. data/lib/capybara/registrations/drivers.rb +36 -0
  40. data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
  41. data/lib/capybara/registrations/servers.rb +44 -0
  42. data/lib/capybara/result.rb +190 -0
  43. data/lib/capybara/rspec.rb +29 -0
  44. data/lib/capybara/rspec/features.rb +23 -0
  45. data/lib/capybara/rspec/matcher_proxies.rb +82 -0
  46. data/lib/capybara/rspec/matchers.rb +201 -0
  47. data/lib/capybara/rspec/matchers/base.rb +111 -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 +77 -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 +38 -0
  59. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  60. data/lib/capybara/selector.rb +233 -0
  61. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  62. data/lib/capybara/selector/builders/xpath_builder.rb +69 -0
  63. data/lib/capybara/selector/css.rb +102 -0
  64. data/lib/capybara/selector/definition.rb +276 -0
  65. data/lib/capybara/selector/definition/button.rb +51 -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 +27 -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 +46 -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/filter.rb +5 -0
  87. data/lib/capybara/selector/filter_set.rb +124 -0
  88. data/lib/capybara/selector/filters/base.rb +77 -0
  89. data/lib/capybara/selector/filters/expression_filter.rb +22 -0
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +31 -0
  92. data/lib/capybara/selector/regexp_disassembler.rb +214 -0
  93. data/lib/capybara/selector/selector.rb +147 -0
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  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 +496 -0
  100. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +119 -0
  101. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +126 -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 +78 -0
  110. data/lib/capybara/selenium/logger_suppressor.rb +34 -0
  111. data/lib/capybara/selenium/node.rb +610 -0
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +119 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
  114. data/lib/capybara/selenium/nodes/firefox_node.rb +131 -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 +47 -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.rb +126 -0
  124. data/lib/capybara/server/animation_disabler.rb +58 -0
  125. data/lib/capybara/server/checker.rb +44 -0
  126. data/lib/capybara/server/middleware.rb +69 -0
  127. data/lib/capybara/session.rb +942 -0
  128. data/lib/capybara/session/config.rb +124 -0
  129. data/lib/capybara/session/matchers.rb +87 -0
  130. data/lib/capybara/spec/fixtures/another_test_file.txt +1 -0
  131. data/lib/capybara/spec/fixtures/capybara.jpg +3 -0
  132. data/lib/capybara/spec/fixtures/no_extension +1 -0
  133. data/lib/capybara/spec/fixtures/test_file.txt +1 -0
  134. data/lib/capybara/spec/public/jquery-ui.js +13 -0
  135. data/lib/capybara/spec/public/jquery.js +5 -0
  136. data/lib/capybara/spec/public/offset.js +6 -0
  137. data/lib/capybara/spec/public/test.js +268 -0
  138. data/lib/capybara/spec/session/accept_alert_spec.rb +81 -0
  139. data/lib/capybara/spec/session/accept_confirm_spec.rb +32 -0
  140. data/lib/capybara/spec/session/accept_prompt_spec.rb +78 -0
  141. data/lib/capybara/spec/session/all_spec.rb +278 -0
  142. data/lib/capybara/spec/session/ancestor_spec.rb +88 -0
  143. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +140 -0
  144. data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
  145. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  146. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  147. data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
  148. data/lib/capybara/spec/session/assert_title_spec.rb +93 -0
  149. data/lib/capybara/spec/session/attach_file_spec.rb +216 -0
  150. data/lib/capybara/spec/session/body_spec.rb +23 -0
  151. data/lib/capybara/spec/session/check_spec.rb +235 -0
  152. data/lib/capybara/spec/session/choose_spec.rb +121 -0
  153. data/lib/capybara/spec/session/click_button_spec.rb +506 -0
  154. data/lib/capybara/spec/session/click_link_or_button_spec.rb +129 -0
  155. data/lib/capybara/spec/session/click_link_spec.rb +229 -0
  156. data/lib/capybara/spec/session/current_scope_spec.rb +31 -0
  157. data/lib/capybara/spec/session/current_url_spec.rb +115 -0
  158. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +36 -0
  159. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +21 -0
  160. data/lib/capybara/spec/session/element/assert_match_selector_spec.rb +38 -0
  161. data/lib/capybara/spec/session/element/match_css_spec.rb +31 -0
  162. data/lib/capybara/spec/session/element/match_xpath_spec.rb +25 -0
  163. data/lib/capybara/spec/session/element/matches_selector_spec.rb +120 -0
  164. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
  165. data/lib/capybara/spec/session/evaluate_script_spec.rb +49 -0
  166. data/lib/capybara/spec/session/execute_script_spec.rb +28 -0
  167. data/lib/capybara/spec/session/fill_in_spec.rb +286 -0
  168. data/lib/capybara/spec/session/find_button_spec.rb +74 -0
  169. data/lib/capybara/spec/session/find_by_id_spec.rb +33 -0
  170. data/lib/capybara/spec/session/find_field_spec.rb +113 -0
  171. data/lib/capybara/spec/session/find_link_spec.rb +70 -0
  172. data/lib/capybara/spec/session/find_spec.rb +531 -0
  173. data/lib/capybara/spec/session/first_spec.rb +156 -0
  174. data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
  175. data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  176. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +116 -0
  177. data/lib/capybara/spec/session/frame/within_frame_spec.rb +112 -0
  178. data/lib/capybara/spec/session/go_back_spec.rb +12 -0
  179. data/lib/capybara/spec/session/go_forward_spec.rb +14 -0
  180. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  181. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  182. data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
  183. data/lib/capybara/spec/session/has_button_spec.rb +69 -0
  184. data/lib/capybara/spec/session/has_css_spec.rb +374 -0
  185. data/lib/capybara/spec/session/has_current_path_spec.rb +138 -0
  186. data/lib/capybara/spec/session/has_field_spec.rb +349 -0
  187. data/lib/capybara/spec/session/has_link_spec.rb +39 -0
  188. data/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
  189. data/lib/capybara/spec/session/has_select_spec.rb +310 -0
  190. data/lib/capybara/spec/session/has_selector_spec.rb +202 -0
  191. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  192. data/lib/capybara/spec/session/has_table_spec.rb +198 -0
  193. data/lib/capybara/spec/session/has_text_spec.rb +394 -0
  194. data/lib/capybara/spec/session/has_title_spec.rb +71 -0
  195. data/lib/capybara/spec/session/has_xpath_spec.rb +149 -0
  196. data/lib/capybara/spec/session/headers_spec.rb +8 -0
  197. data/lib/capybara/spec/session/html_spec.rb +47 -0
  198. data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
  199. data/lib/capybara/spec/session/node_spec.rb +1292 -0
  200. data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
  201. data/lib/capybara/spec/session/refresh_spec.rb +33 -0
  202. data/lib/capybara/spec/session/reset_session_spec.rb +148 -0
  203. data/lib/capybara/spec/session/response_code_spec.rb +8 -0
  204. data/lib/capybara/spec/session/save_and_open_page_spec.rb +21 -0
  205. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +43 -0
  206. data/lib/capybara/spec/session/save_page_spec.rb +110 -0
  207. data/lib/capybara/spec/session/save_screenshot_spec.rb +55 -0
  208. data/lib/capybara/spec/session/screenshot_spec.rb +18 -0
  209. data/lib/capybara/spec/session/scroll_spec.rb +117 -0
  210. data/lib/capybara/spec/session/select_spec.rb +229 -0
  211. data/lib/capybara/spec/session/selectors_spec.rb +98 -0
  212. data/lib/capybara/spec/session/sibling_spec.rb +52 -0
  213. data/lib/capybara/spec/session/source_spec.rb +0 -0
  214. data/lib/capybara/spec/session/text_spec.rb +74 -0
  215. data/lib/capybara/spec/session/title_spec.rb +29 -0
  216. data/lib/capybara/spec/session/uncheck_spec.rb +100 -0
  217. data/lib/capybara/spec/session/unselect_spec.rb +116 -0
  218. data/lib/capybara/spec/session/visit_spec.rb +204 -0
  219. data/lib/capybara/spec/session/window/become_closed_spec.rb +89 -0
  220. data/lib/capybara/spec/session/window/current_window_spec.rb +28 -0
  221. data/lib/capybara/spec/session/window/open_new_window_spec.rb +31 -0
  222. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +132 -0
  223. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +99 -0
  224. data/lib/capybara/spec/session/window/window_spec.rb +203 -0
  225. data/lib/capybara/spec/session/window/windows_spec.rb +34 -0
  226. data/lib/capybara/spec/session/window/within_window_spec.rb +157 -0
  227. data/lib/capybara/spec/session/within_spec.rb +199 -0
  228. data/lib/capybara/spec/spec_helper.rb +134 -0
  229. data/lib/capybara/spec/test_app.rb +226 -0
  230. data/lib/capybara/spec/views/animated.erb +49 -0
  231. data/lib/capybara/spec/views/buttons.erb +5 -0
  232. data/lib/capybara/spec/views/fieldsets.erb +30 -0
  233. data/lib/capybara/spec/views/form.erb +685 -0
  234. data/lib/capybara/spec/views/frame_child.erb +18 -0
  235. data/lib/capybara/spec/views/frame_one.erb +10 -0
  236. data/lib/capybara/spec/views/frame_parent.erb +9 -0
  237. data/lib/capybara/spec/views/frame_two.erb +9 -0
  238. data/lib/capybara/spec/views/header_links.erb +8 -0
  239. data/lib/capybara/spec/views/host_links.erb +13 -0
  240. data/lib/capybara/spec/views/initial_alert.erb +10 -0
  241. data/lib/capybara/spec/views/obscured.erb +47 -0
  242. data/lib/capybara/spec/views/offset.erb +32 -0
  243. data/lib/capybara/spec/views/path.erb +13 -0
  244. data/lib/capybara/spec/views/popup_one.erb +9 -0
  245. data/lib/capybara/spec/views/popup_two.erb +9 -0
  246. data/lib/capybara/spec/views/postback.erb +14 -0
  247. data/lib/capybara/spec/views/react.erb +45 -0
  248. data/lib/capybara/spec/views/scroll.erb +20 -0
  249. data/lib/capybara/spec/views/spatial.erb +31 -0
  250. data/lib/capybara/spec/views/tables.erb +130 -0
  251. data/lib/capybara/spec/views/with_animation.erb +74 -0
  252. data/lib/capybara/spec/views/with_base_tag.erb +11 -0
  253. data/lib/capybara/spec/views/with_count.erb +8 -0
  254. data/lib/capybara/spec/views/with_dragula.erb +22 -0
  255. data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
  256. data/lib/capybara/spec/views/with_hover.erb +24 -0
  257. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  258. data/lib/capybara/spec/views/with_html.erb +208 -0
  259. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  260. data/lib/capybara/spec/views/with_html_entities.erb +2 -0
  261. data/lib/capybara/spec/views/with_js.erb +160 -0
  262. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  263. data/lib/capybara/spec/views/with_namespace.erb +20 -0
  264. data/lib/capybara/spec/views/with_scope.erb +42 -0
  265. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  266. data/lib/capybara/spec/views/with_simple_html.erb +2 -0
  267. data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
  268. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  269. data/lib/capybara/spec/views/with_title.erb +5 -0
  270. data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
  271. data/lib/capybara/spec/views/with_windows.erb +54 -0
  272. data/lib/capybara/spec/views/within_frames.erb +15 -0
  273. data/lib/capybara/version.rb +5 -0
  274. data/lib/capybara/window.rb +146 -0
  275. data/spec/basic_node_spec.rb +154 -0
  276. data/spec/capybara_spec.rb +112 -0
  277. data/spec/css_builder_spec.rb +101 -0
  278. data/spec/css_splitter_spec.rb +38 -0
  279. data/spec/dsl_spec.rb +276 -0
  280. data/spec/filter_set_spec.rb +46 -0
  281. data/spec/fixtures/capybara.csv +1 -0
  282. data/spec/fixtures/certificate.pem +25 -0
  283. data/spec/fixtures/key.pem +27 -0
  284. data/spec/fixtures/selenium_driver_rspec_failure.rb +13 -0
  285. data/spec/fixtures/selenium_driver_rspec_success.rb +13 -0
  286. data/spec/minitest_spec.rb +163 -0
  287. data/spec/minitest_spec_spec.rb +162 -0
  288. data/spec/per_session_config_spec.rb +68 -0
  289. data/spec/rack_test_spec.rb +268 -0
  290. data/spec/regexp_dissassembler_spec.rb +250 -0
  291. data/spec/result_spec.rb +196 -0
  292. data/spec/rspec/features_spec.rb +99 -0
  293. data/spec/rspec/scenarios_spec.rb +19 -0
  294. data/spec/rspec/shared_spec_matchers.rb +947 -0
  295. data/spec/rspec/views_spec.rb +14 -0
  296. data/spec/rspec_matchers_spec.rb +62 -0
  297. data/spec/rspec_spec.rb +145 -0
  298. data/spec/sauce_spec_chrome.rb +43 -0
  299. data/spec/selector_spec.rb +513 -0
  300. data/spec/selenium_spec_chrome.rb +188 -0
  301. data/spec/selenium_spec_chrome_remote.rb +96 -0
  302. data/spec/selenium_spec_edge.rb +47 -0
  303. data/spec/selenium_spec_firefox.rb +208 -0
  304. data/spec/selenium_spec_firefox_remote.rb +80 -0
  305. data/spec/selenium_spec_ie.rb +150 -0
  306. data/spec/selenium_spec_safari.rb +148 -0
  307. data/spec/server_spec.rb +292 -0
  308. data/spec/session_spec.rb +91 -0
  309. data/spec/shared_selenium_node.rb +83 -0
  310. data/spec/shared_selenium_session.rb +476 -0
  311. data/spec/spec_helper.rb +100 -0
  312. data/spec/xpath_builder_spec.rb +93 -0
  313. metadata +753 -0
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara
4
+ module Queries
5
+ class SiblingQuery < SelectorQuery
6
+ # @api private
7
+ def resolve_for(node, exact = nil)
8
+ @sibling_node = node
9
+ node.synchronize do
10
+ match_results = super(node.session.current_scope, exact)
11
+ siblings = node.find_xpath((XPath.preceding_sibling + XPath.following_sibling).to_s)
12
+ .map(&method(:to_element))
13
+ .select { |el| match_results.include?(el) }
14
+ Capybara::Result.new(ordered_results(siblings), self)
15
+ end
16
+ end
17
+
18
+ def description(applied = false)
19
+ desc = super
20
+ sibling_query = @sibling_node&.instance_variable_get(:@query)
21
+ desc += " that is a sibling of #{sibling_query.description}" if sibling_query
22
+ desc
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara
4
+ # @api private
5
+ module Queries
6
+ class StyleQuery < BaseQuery
7
+ def initialize(expected_styles, session_options:, **options)
8
+ @expected_styles = stringify_keys(expected_styles)
9
+ @options = options
10
+ @actual_styles = {}
11
+ super(@options)
12
+ self.session_options = session_options
13
+
14
+ assert_valid_keys
15
+ end
16
+
17
+ def resolves_for?(node)
18
+ @node = node
19
+ @actual_styles = node.style(*@expected_styles.keys)
20
+ @expected_styles.all? do |style, value|
21
+ if value.is_a? Regexp
22
+ value.match? @actual_styles[style]
23
+ else
24
+ @actual_styles[style] == value
25
+ end
26
+ end
27
+ end
28
+
29
+ def failure_message
30
+ +"Expected node to have styles #{@expected_styles.inspect}. " \
31
+ "Actual styles were #{@actual_styles.inspect}"
32
+ end
33
+
34
+ private
35
+
36
+ def stringify_keys(hsh)
37
+ hsh.each_with_object({}) { |(k, v), str_keys| str_keys[k.to_s] = v }
38
+ end
39
+
40
+ def valid_keys
41
+ %i[wait]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara
4
+ # @api private
5
+ module Queries
6
+ class TextQuery < BaseQuery
7
+ def initialize(type = nil, expected_text, session_options:, **options) # rubocop:disable Style/OptionalArguments
8
+ @type = type.nil? ? default_type : type
9
+ @options = options
10
+ super(@options)
11
+ self.session_options = session_options
12
+
13
+ if expected_text.nil? && !exact?
14
+ warn 'Checking for expected text of nil is confusing and/or pointless since it will always match. '\
15
+ 'Please specify a string or regexp instead.'
16
+ end
17
+
18
+ @expected_text = expected_text.is_a?(Regexp) ? expected_text : expected_text.to_s
19
+
20
+ @search_regexp = Capybara::Helpers.to_regexp(@expected_text, exact: exact?)
21
+
22
+ assert_valid_keys
23
+ end
24
+
25
+ def resolve_for(node)
26
+ @node = node
27
+ @actual_text = text
28
+ @count = @actual_text.scan(@search_regexp).size
29
+ end
30
+
31
+ def failure_message
32
+ super << build_message(true)
33
+ end
34
+
35
+ def negative_failure_message
36
+ super << build_message(false)
37
+ end
38
+
39
+ def description
40
+ if @expected_text.is_a?(Regexp)
41
+ "text matching #{@expected_text.inspect}"
42
+ else
43
+ "#{'exact ' if exact?}text #{@expected_text.inspect}"
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def exact?
50
+ options.fetch(:exact, session_options.exact_text)
51
+ end
52
+
53
+ def build_message(report_on_invisible)
54
+ message = +''
55
+ unless (COUNT_KEYS & @options.keys).empty?
56
+ message << " but found #{@count} #{Capybara::Helpers.declension('time', 'times', @count)}"
57
+ end
58
+ message << " in #{@actual_text.inspect}"
59
+
60
+ details_message = []
61
+ details_message << case_insensitive_message if @node && check_case_insensitive?
62
+ details_message << invisible_message if @node && check_visible_text? && report_on_invisible
63
+ details_message.compact!
64
+
65
+ message << ". (However, #{details_message.join(' and ')}.)" unless details_message.empty?
66
+ message
67
+ end
68
+
69
+ def case_insensitive_message
70
+ insensitive_regexp = Capybara::Helpers.to_regexp(@expected_text, options: Regexp::IGNORECASE)
71
+ insensitive_count = @actual_text.scan(insensitive_regexp).size
72
+ return if insensitive_count == @count
73
+
74
+ "it was found #{occurrences insensitive_count} using a case insensitive search"
75
+ end
76
+
77
+ def invisible_message
78
+ invisible_text = text(query_type: :all)
79
+ invisible_count = invisible_text.scan(@search_regexp).size
80
+ return if invisible_count == @count
81
+
82
+ "it was found #{occurrences invisible_count} including non-visible text"
83
+ rescue StandardError
84
+ # An error getting the non-visible text (if element goes out of scope) should not affect the response
85
+ nil
86
+ end
87
+
88
+ def valid_keys
89
+ COUNT_KEYS + %i[wait exact normalize_ws]
90
+ end
91
+
92
+ def check_visible_text?
93
+ @type == :visible
94
+ end
95
+
96
+ def check_case_insensitive?
97
+ !@expected_text.is_a?(Regexp)
98
+ end
99
+
100
+ def text(node: @node, query_type: @type)
101
+ normalize_ws = options.fetch(:normalize_ws, session_options.default_normalize_ws)
102
+ node.text(query_type, normalize_ws: normalize_ws)
103
+ end
104
+
105
+ def default_type
106
+ Capybara.ignore_hidden_elements || Capybara.visible_text_only ? :visible : :all
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara
4
+ # @api private
5
+ module Queries
6
+ class TitleQuery < BaseQuery
7
+ def initialize(expected_title, **options)
8
+ @expected_title = expected_title.is_a?(Regexp) ? expected_title : expected_title.to_s
9
+ @options = options
10
+ super(@options)
11
+ @search_regexp = Helpers.to_regexp(@expected_title, all_whitespace: true, exact: options.fetch(:exact, false))
12
+ assert_valid_keys
13
+ end
14
+
15
+ def resolves_for?(node)
16
+ (@actual_title = node.title).match?(@search_regexp)
17
+ end
18
+
19
+ def failure_message
20
+ failure_message_helper
21
+ end
22
+
23
+ def negative_failure_message
24
+ failure_message_helper(' not')
25
+ end
26
+
27
+ private
28
+
29
+ def failure_message_helper(negated = '')
30
+ verb = @expected_title.is_a?(Regexp) ? 'match' : 'include'
31
+ "expected #{@actual_title.inspect}#{negated} to #{verb} #{@expected_title.inspect}"
32
+ end
33
+
34
+ def valid_keys
35
+ %i[wait exact]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Capybara::RackTest::Browser
4
+ include ::Rack::Test::Methods
5
+
6
+ attr_reader :driver
7
+ attr_accessor :current_host
8
+
9
+ def initialize(driver)
10
+ @driver = driver
11
+ end
12
+
13
+ def app
14
+ driver.app
15
+ end
16
+
17
+ def options
18
+ driver.options
19
+ end
20
+
21
+ def visit(path, **attributes)
22
+ reset_host!
23
+ process_and_follow_redirects(:get, path, attributes)
24
+ end
25
+
26
+ def refresh
27
+ reset_cache!
28
+ request(last_request.fullpath, last_request.env)
29
+ end
30
+
31
+ def submit(method, path, attributes)
32
+ path = request_path if path.nil? || path.empty?
33
+ uri = build_uri(path)
34
+ uri.query = '' if method&.to_s&.downcase == 'get'
35
+ process_and_follow_redirects(method, uri.to_s, attributes, 'HTTP_REFERER' => current_url)
36
+ end
37
+
38
+ def follow(method, path, **attributes)
39
+ return if fragment_or_script?(path)
40
+
41
+ process_and_follow_redirects(method, path, attributes, 'HTTP_REFERER' => current_url)
42
+ end
43
+
44
+ def process_and_follow_redirects(method, path, attributes = {}, env = {})
45
+ process(method, path, attributes, env)
46
+
47
+ return unless driver.follow_redirects?
48
+
49
+ driver.redirect_limit.times do
50
+ if last_response.redirect?
51
+ if [307, 308].include? last_response.status
52
+ process(last_request.request_method, last_response['Location'], last_request.params, env)
53
+ else
54
+ process(:get, last_response['Location'], {}, env)
55
+ end
56
+ end
57
+ end
58
+
59
+ if last_response.redirect? # rubocop:disable Style/GuardClause
60
+ raise Capybara::InfiniteRedirectError, "redirected more than #{driver.redirect_limit} times, check for infinite redirects."
61
+ end
62
+ end
63
+
64
+ def process(method, path, attributes = {}, env = {})
65
+ method = method.downcase
66
+ new_uri = build_uri(path)
67
+ @current_scheme, @current_host, @current_port = new_uri.select(:scheme, :host, :port)
68
+
69
+ reset_cache!
70
+ send(method, new_uri.to_s, attributes, env.merge(options[:headers] || {}))
71
+ end
72
+
73
+ def build_uri(path)
74
+ URI.parse(path).tap do |uri|
75
+ uri.path = request_path if path.empty? || path.start_with?('?')
76
+ uri.path = '/' if uri.path.empty?
77
+ uri.path = request_path.sub(%r{/[^/]*$}, '/') + uri.path unless uri.path.start_with?('/')
78
+
79
+ uri.scheme ||= @current_scheme
80
+ uri.host ||= @current_host
81
+ uri.port ||= @current_port unless uri.default_port == @current_port
82
+ end
83
+ end
84
+
85
+ def current_url
86
+ last_request.url
87
+ rescue Rack::Test::Error
88
+ ''
89
+ end
90
+
91
+ def reset_host!
92
+ uri = URI.parse(driver.session_options.app_host || driver.session_options.default_host)
93
+ @current_scheme, @current_host, @current_port = uri.select(:scheme, :host, :port)
94
+ end
95
+
96
+ def reset_cache!
97
+ @dom = nil
98
+ end
99
+
100
+ def dom
101
+ @dom ||= Capybara::HTML(html)
102
+ end
103
+
104
+ def find(format, selector)
105
+ if format == :css
106
+ dom.css(selector, Capybara::RackTest::CSSHandlers.new)
107
+ else
108
+ dom.xpath(selector)
109
+ end.map { |node| Capybara::RackTest::Node.new(self, node) }
110
+ end
111
+
112
+ def html
113
+ last_response.body
114
+ rescue Rack::Test::Error
115
+ ''
116
+ end
117
+
118
+ def title
119
+ dom.title
120
+ end
121
+
122
+ protected
123
+
124
+ def build_rack_mock_session
125
+ reset_host! unless current_host
126
+ Rack::MockSession.new(app, current_host)
127
+ end
128
+
129
+ def request_path
130
+ last_request.path
131
+ rescue Rack::Test::Error
132
+ '/'
133
+ end
134
+
135
+ private
136
+
137
+ def fragment_or_script?(path)
138
+ path.gsub(/^#{Regexp.escape(request_path)}/, '').start_with?('#') || path.downcase.start_with?('javascript:')
139
+ end
140
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Capybara::RackTest::CSSHandlers < BasicObject
4
+ include ::Kernel
5
+
6
+ def disabled(list)
7
+ list.find_all { |node| node.has_attribute? 'disabled' }
8
+ end
9
+
10
+ def enabled(list)
11
+ list.find_all { |node| !node.has_attribute? 'disabled' }
12
+ end
13
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack/test'
4
+ require 'rack/utils'
5
+ require 'mini_mime'
6
+ require 'nokogiri'
7
+ require 'cgi'
8
+
9
+ class Capybara::RackTest::Driver < Capybara::Driver::Base
10
+ DEFAULT_OPTIONS = {
11
+ respect_data_method: false,
12
+ follow_redirects: true,
13
+ redirect_limit: 5
14
+ }.freeze
15
+ attr_reader :app, :options
16
+
17
+ def initialize(app, **options)
18
+ raise ArgumentError, 'rack-test requires a rack application, but none was given' unless app
19
+
20
+ @app = app
21
+ @options = DEFAULT_OPTIONS.merge(options)
22
+ end
23
+
24
+ def browser
25
+ @browser ||= Capybara::RackTest::Browser.new(self)
26
+ end
27
+
28
+ def follow_redirects?
29
+ @options[:follow_redirects]
30
+ end
31
+
32
+ def redirect_limit
33
+ @options[:redirect_limit]
34
+ end
35
+
36
+ def response
37
+ browser.last_response
38
+ end
39
+
40
+ def request
41
+ browser.last_request
42
+ end
43
+
44
+ def visit(path, **attributes)
45
+ browser.visit(path, **attributes)
46
+ end
47
+
48
+ def refresh
49
+ browser.refresh
50
+ end
51
+
52
+ def submit(method, path, attributes)
53
+ browser.submit(method, path, attributes)
54
+ end
55
+
56
+ def follow(method, path, **attributes)
57
+ browser.follow(method, path, attributes)
58
+ end
59
+
60
+ def current_url
61
+ browser.current_url
62
+ end
63
+
64
+ def response_headers
65
+ response.headers
66
+ end
67
+
68
+ def status_code
69
+ response.status
70
+ end
71
+
72
+ def find_xpath(selector)
73
+ browser.find(:xpath, selector)
74
+ end
75
+
76
+ def find_css(selector)
77
+ browser.find(:css, selector)
78
+ rescue Nokogiri::CSS::SyntaxError
79
+ raise unless selector.include?(' i]')
80
+
81
+ raise ArgumentError, "This driver doesn't support case insensitive attribute matching when using CSS base selectors"
82
+ end
83
+
84
+ def html
85
+ browser.html
86
+ end
87
+
88
+ def dom
89
+ browser.dom
90
+ end
91
+
92
+ def title
93
+ browser.title
94
+ end
95
+
96
+ def reset!
97
+ @browser = nil
98
+ end
99
+
100
+ def get(*args, &block); browser.get(*args, &block); end
101
+ def post(*args, &block); browser.post(*args, &block); end
102
+ def put(*args, &block); browser.put(*args, &block); end
103
+ def delete(*args, &block); browser.delete(*args, &block); end
104
+ def header(key, value); browser.header(key, value); end
105
+
106
+ def invalid_element_errors
107
+ [Capybara::RackTest::Errors::StaleElementReferenceError]
108
+ end
109
+ end