mega-max-rb 0.0.1

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 (319) hide show
  1. checksums.yaml +7 -0
  2. data/capybara-3.40.0/History.md +2043 -0
  3. data/capybara-3.40.0/License.txt +22 -0
  4. data/capybara-3.40.0/README.md +1264 -0
  5. data/capybara-3.40.0/lib/capybara/config.rb +104 -0
  6. data/capybara-3.40.0/lib/capybara/cucumber.rb +27 -0
  7. data/capybara-3.40.0/lib/capybara/driver/base.rb +178 -0
  8. data/capybara-3.40.0/lib/capybara/driver/node.rb +143 -0
  9. data/capybara-3.40.0/lib/capybara/dsl.rb +59 -0
  10. data/capybara-3.40.0/lib/capybara/helpers.rb +127 -0
  11. data/capybara-3.40.0/lib/capybara/minitest/spec.rb +279 -0
  12. data/capybara-3.40.0/lib/capybara/minitest.rb +398 -0
  13. data/capybara-3.40.0/lib/capybara/node/actions.rb +420 -0
  14. data/capybara-3.40.0/lib/capybara/node/base.rb +144 -0
  15. data/capybara-3.40.0/lib/capybara/node/document.rb +48 -0
  16. data/capybara-3.40.0/lib/capybara/node/document_matchers.rb +67 -0
  17. data/capybara-3.40.0/lib/capybara/node/element.rb +613 -0
  18. data/capybara-3.40.0/lib/capybara/node/finders.rb +335 -0
  19. data/capybara-3.40.0/lib/capybara/node/matchers.rb +908 -0
  20. data/capybara-3.40.0/lib/capybara/node/simple.rb +216 -0
  21. data/capybara-3.40.0/lib/capybara/node/whitespace_normalizer.rb +81 -0
  22. data/capybara-3.40.0/lib/capybara/queries/active_element_query.rb +18 -0
  23. data/capybara-3.40.0/lib/capybara/queries/ancestor_query.rb +28 -0
  24. data/capybara-3.40.0/lib/capybara/queries/base_query.rb +106 -0
  25. data/capybara-3.40.0/lib/capybara/queries/current_path_query.rb +61 -0
  26. data/capybara-3.40.0/lib/capybara/queries/match_query.rb +26 -0
  27. data/capybara-3.40.0/lib/capybara/queries/selector_query.rb +761 -0
  28. data/capybara-3.40.0/lib/capybara/queries/sibling_query.rb +27 -0
  29. data/capybara-3.40.0/lib/capybara/queries/style_query.rb +45 -0
  30. data/capybara-3.40.0/lib/capybara/queries/text_query.rb +116 -0
  31. data/capybara-3.40.0/lib/capybara/queries/title_query.rb +39 -0
  32. data/capybara-3.40.0/lib/capybara/rack_test/browser.rb +200 -0
  33. data/capybara-3.40.0/lib/capybara/rack_test/css_handlers.rb +13 -0
  34. data/capybara-3.40.0/lib/capybara/rack_test/driver.rb +110 -0
  35. data/capybara-3.40.0/lib/capybara/rack_test/errors.rb +6 -0
  36. data/capybara-3.40.0/lib/capybara/rack_test/form.rb +149 -0
  37. data/capybara-3.40.0/lib/capybara/rack_test/node.rb +324 -0
  38. data/capybara-3.40.0/lib/capybara/rails.rb +16 -0
  39. data/capybara-3.40.0/lib/capybara/registration_container.rb +41 -0
  40. data/capybara-3.40.0/lib/capybara/registrations/drivers.rb +42 -0
  41. data/capybara-3.40.0/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  42. data/capybara-3.40.0/lib/capybara/registrations/servers.rb +66 -0
  43. data/capybara-3.40.0/lib/capybara/result.rb +186 -0
  44. data/capybara-3.40.0/lib/capybara/rspec/features.rb +23 -0
  45. data/capybara-3.40.0/lib/capybara/rspec/matcher_proxies.rb +82 -0
  46. data/capybara-3.40.0/lib/capybara/rspec/matchers/base.rb +113 -0
  47. data/capybara-3.40.0/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  48. data/capybara-3.40.0/lib/capybara/rspec/matchers/compound.rb +88 -0
  49. data/capybara-3.40.0/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  50. data/capybara-3.40.0/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  51. data/capybara-3.40.0/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  52. data/capybara-3.40.0/lib/capybara/rspec/matchers/have_selector.rb +69 -0
  53. data/capybara-3.40.0/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  54. data/capybara-3.40.0/lib/capybara/rspec/matchers/have_text.rb +33 -0
  55. data/capybara-3.40.0/lib/capybara/rspec/matchers/have_title.rb +29 -0
  56. data/capybara-3.40.0/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  57. data/capybara-3.40.0/lib/capybara/rspec/matchers/match_style.rb +43 -0
  58. data/capybara-3.40.0/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  59. data/capybara-3.40.0/lib/capybara/rspec/matchers.rb +207 -0
  60. data/capybara-3.40.0/lib/capybara/rspec.rb +31 -0
  61. data/capybara-3.40.0/lib/capybara/selector/builders/css_builder.rb +84 -0
  62. data/capybara-3.40.0/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  63. data/capybara-3.40.0/lib/capybara/selector/css.rb +102 -0
  64. data/capybara-3.40.0/lib/capybara/selector/definition/button.rb +68 -0
  65. data/capybara-3.40.0/lib/capybara/selector/definition/checkbox.rb +26 -0
  66. data/capybara-3.40.0/lib/capybara/selector/definition/css.rb +10 -0
  67. data/capybara-3.40.0/lib/capybara/selector/definition/datalist_input.rb +35 -0
  68. data/capybara-3.40.0/lib/capybara/selector/definition/datalist_option.rb +25 -0
  69. data/capybara-3.40.0/lib/capybara/selector/definition/element.rb +28 -0
  70. data/capybara-3.40.0/lib/capybara/selector/definition/field.rb +40 -0
  71. data/capybara-3.40.0/lib/capybara/selector/definition/fieldset.rb +14 -0
  72. data/capybara-3.40.0/lib/capybara/selector/definition/file_field.rb +13 -0
  73. data/capybara-3.40.0/lib/capybara/selector/definition/fillable_field.rb +33 -0
  74. data/capybara-3.40.0/lib/capybara/selector/definition/frame.rb +17 -0
  75. data/capybara-3.40.0/lib/capybara/selector/definition/id.rb +6 -0
  76. data/capybara-3.40.0/lib/capybara/selector/definition/label.rb +62 -0
  77. data/capybara-3.40.0/lib/capybara/selector/definition/link.rb +55 -0
  78. data/capybara-3.40.0/lib/capybara/selector/definition/link_or_button.rb +16 -0
  79. data/capybara-3.40.0/lib/capybara/selector/definition/option.rb +27 -0
  80. data/capybara-3.40.0/lib/capybara/selector/definition/radio_button.rb +27 -0
  81. data/capybara-3.40.0/lib/capybara/selector/definition/select.rb +81 -0
  82. data/capybara-3.40.0/lib/capybara/selector/definition/table.rb +109 -0
  83. data/capybara-3.40.0/lib/capybara/selector/definition/table_row.rb +21 -0
  84. data/capybara-3.40.0/lib/capybara/selector/definition/xpath.rb +5 -0
  85. data/capybara-3.40.0/lib/capybara/selector/definition.rb +280 -0
  86. data/capybara-3.40.0/lib/capybara/selector/filter.rb +5 -0
  87. data/capybara-3.40.0/lib/capybara/selector/filter_set.rb +121 -0
  88. data/capybara-3.40.0/lib/capybara/selector/filters/base.rb +77 -0
  89. data/capybara-3.40.0/lib/capybara/selector/filters/expression_filter.rb +22 -0
  90. data/capybara-3.40.0/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/capybara-3.40.0/lib/capybara/selector/filters/node_filter.rb +31 -0
  92. data/capybara-3.40.0/lib/capybara/selector/regexp_disassembler.rb +211 -0
  93. data/capybara-3.40.0/lib/capybara/selector/selector.rb +159 -0
  94. data/capybara-3.40.0/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/capybara-3.40.0/lib/capybara/selector.rb +494 -0
  96. data/capybara-3.40.0/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  97. data/capybara-3.40.0/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  98. data/capybara-3.40.0/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  99. data/capybara-3.40.0/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  100. data/capybara-3.40.0/lib/capybara/selenium/driver.rb +517 -0
  101. data/capybara-3.40.0/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  102. data/capybara-3.40.0/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  103. data/capybara-3.40.0/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
  104. data/capybara-3.40.0/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  105. data/capybara-3.40.0/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  106. data/capybara-3.40.0/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  107. data/capybara-3.40.0/lib/capybara/selenium/extensions/find.rb +110 -0
  108. data/capybara-3.40.0/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
  109. data/capybara-3.40.0/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  110. data/capybara-3.40.0/lib/capybara/selenium/extensions/scroll.rb +76 -0
  111. data/capybara-3.40.0/lib/capybara/selenium/node.rb +636 -0
  112. data/capybara-3.40.0/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
  113. data/capybara-3.40.0/lib/capybara/selenium/nodes/edge_node.rb +110 -0
  114. data/capybara-3.40.0/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  115. data/capybara-3.40.0/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  116. data/capybara-3.40.0/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  117. data/capybara-3.40.0/lib/capybara/selenium/patches/atoms.rb +18 -0
  118. data/capybara-3.40.0/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  119. data/capybara-3.40.0/lib/capybara/selenium/patches/logs.rb +45 -0
  120. data/capybara-3.40.0/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  121. data/capybara-3.40.0/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  122. data/capybara-3.40.0/lib/capybara/server/animation_disabler.rb +80 -0
  123. data/capybara-3.40.0/lib/capybara/server/checker.rb +44 -0
  124. data/capybara-3.40.0/lib/capybara/server/middleware.rb +71 -0
  125. data/capybara-3.40.0/lib/capybara/server.rb +126 -0
  126. data/capybara-3.40.0/lib/capybara/session/config.rb +128 -0
  127. data/capybara-3.40.0/lib/capybara/session/matchers.rb +87 -0
  128. data/capybara-3.40.0/lib/capybara/session.rb +951 -0
  129. data/capybara-3.40.0/lib/capybara/spec/fixtures/another_test_file.txt +1 -0
  130. data/capybara-3.40.0/lib/capybara/spec/fixtures/capybara.jpg +3 -0
  131. data/capybara-3.40.0/lib/capybara/spec/fixtures/no_extension +1 -0
  132. data/capybara-3.40.0/lib/capybara/spec/fixtures/test_file.txt +1 -0
  133. data/capybara-3.40.0/lib/capybara/spec/public/jquery-ui.js +13 -0
  134. data/capybara-3.40.0/lib/capybara/spec/public/jquery.js +5 -0
  135. data/capybara-3.40.0/lib/capybara/spec/public/offset.js +6 -0
  136. data/capybara-3.40.0/lib/capybara/spec/public/test.js +284 -0
  137. data/capybara-3.40.0/lib/capybara/spec/session/accept_alert_spec.rb +81 -0
  138. data/capybara-3.40.0/lib/capybara/spec/session/accept_confirm_spec.rb +32 -0
  139. data/capybara-3.40.0/lib/capybara/spec/session/accept_prompt_spec.rb +78 -0
  140. data/capybara-3.40.0/lib/capybara/spec/session/active_element_spec.rb +31 -0
  141. data/capybara-3.40.0/lib/capybara/spec/session/all_spec.rb +274 -0
  142. data/capybara-3.40.0/lib/capybara/spec/session/ancestor_spec.rb +88 -0
  143. data/capybara-3.40.0/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +140 -0
  144. data/capybara-3.40.0/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
  145. data/capybara-3.40.0/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  146. data/capybara-3.40.0/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  147. data/capybara-3.40.0/lib/capybara/spec/session/assert_text_spec.rb +258 -0
  148. data/capybara-3.40.0/lib/capybara/spec/session/assert_title_spec.rb +93 -0
  149. data/capybara-3.40.0/lib/capybara/spec/session/attach_file_spec.rb +222 -0
  150. data/capybara-3.40.0/lib/capybara/spec/session/body_spec.rb +23 -0
  151. data/capybara-3.40.0/lib/capybara/spec/session/check_spec.rb +251 -0
  152. data/capybara-3.40.0/lib/capybara/spec/session/choose_spec.rb +127 -0
  153. data/capybara-3.40.0/lib/capybara/spec/session/click_button_spec.rb +517 -0
  154. data/capybara-3.40.0/lib/capybara/spec/session/click_link_or_button_spec.rb +138 -0
  155. data/capybara-3.40.0/lib/capybara/spec/session/click_link_spec.rb +240 -0
  156. data/capybara-3.40.0/lib/capybara/spec/session/current_scope_spec.rb +31 -0
  157. data/capybara-3.40.0/lib/capybara/spec/session/current_url_spec.rb +125 -0
  158. data/capybara-3.40.0/lib/capybara/spec/session/dismiss_confirm_spec.rb +36 -0
  159. data/capybara-3.40.0/lib/capybara/spec/session/dismiss_prompt_spec.rb +21 -0
  160. data/capybara-3.40.0/lib/capybara/spec/session/element/assert_match_selector_spec.rb +38 -0
  161. data/capybara-3.40.0/lib/capybara/spec/session/element/match_css_spec.rb +31 -0
  162. data/capybara-3.40.0/lib/capybara/spec/session/element/match_xpath_spec.rb +25 -0
  163. data/capybara-3.40.0/lib/capybara/spec/session/element/matches_selector_spec.rb +120 -0
  164. data/capybara-3.40.0/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
  165. data/capybara-3.40.0/lib/capybara/spec/session/evaluate_script_spec.rb +49 -0
  166. data/capybara-3.40.0/lib/capybara/spec/session/execute_script_spec.rb +28 -0
  167. data/capybara-3.40.0/lib/capybara/spec/session/fill_in_spec.rb +292 -0
  168. data/capybara-3.40.0/lib/capybara/spec/session/find_button_spec.rb +74 -0
  169. data/capybara-3.40.0/lib/capybara/spec/session/find_by_id_spec.rb +33 -0
  170. data/capybara-3.40.0/lib/capybara/spec/session/find_field_spec.rb +113 -0
  171. data/capybara-3.40.0/lib/capybara/spec/session/find_link_spec.rb +80 -0
  172. data/capybara-3.40.0/lib/capybara/spec/session/find_spec.rb +545 -0
  173. data/capybara-3.40.0/lib/capybara/spec/session/first_spec.rb +156 -0
  174. data/capybara-3.40.0/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
  175. data/capybara-3.40.0/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  176. data/capybara-3.40.0/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +116 -0
  177. data/capybara-3.40.0/lib/capybara/spec/session/frame/within_frame_spec.rb +114 -0
  178. data/capybara-3.40.0/lib/capybara/spec/session/go_back_spec.rb +12 -0
  179. data/capybara-3.40.0/lib/capybara/spec/session/go_forward_spec.rb +14 -0
  180. data/capybara-3.40.0/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  181. data/capybara-3.40.0/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  182. data/capybara-3.40.0/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  183. data/capybara-3.40.0/lib/capybara/spec/session/has_button_spec.rb +150 -0
  184. data/capybara-3.40.0/lib/capybara/spec/session/has_css_spec.rb +375 -0
  185. data/capybara-3.40.0/lib/capybara/spec/session/has_current_path_spec.rb +151 -0
  186. data/capybara-3.40.0/lib/capybara/spec/session/has_element_spec.rb +47 -0
  187. data/capybara-3.40.0/lib/capybara/spec/session/has_field_spec.rb +389 -0
  188. data/capybara-3.40.0/lib/capybara/spec/session/has_link_spec.rb +79 -0
  189. data/capybara-3.40.0/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
  190. data/capybara-3.40.0/lib/capybara/spec/session/has_select_spec.rb +316 -0
  191. data/capybara-3.40.0/lib/capybara/spec/session/has_selector_spec.rb +217 -0
  192. data/capybara-3.40.0/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  193. data/capybara-3.40.0/lib/capybara/spec/session/has_table_spec.rb +209 -0
  194. data/capybara-3.40.0/lib/capybara/spec/session/has_text_spec.rb +375 -0
  195. data/capybara-3.40.0/lib/capybara/spec/session/has_title_spec.rb +71 -0
  196. data/capybara-3.40.0/lib/capybara/spec/session/has_xpath_spec.rb +149 -0
  197. data/capybara-3.40.0/lib/capybara/spec/session/headers_spec.rb +8 -0
  198. data/capybara-3.40.0/lib/capybara/spec/session/html_spec.rb +47 -0
  199. data/capybara-3.40.0/lib/capybara/spec/session/matches_style_spec.rb +37 -0
  200. data/capybara-3.40.0/lib/capybara/spec/session/node_spec.rb +1399 -0
  201. data/capybara-3.40.0/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
  202. data/capybara-3.40.0/lib/capybara/spec/session/refresh_spec.rb +34 -0
  203. data/capybara-3.40.0/lib/capybara/spec/session/reset_session_spec.rb +161 -0
  204. data/capybara-3.40.0/lib/capybara/spec/session/response_code_spec.rb +8 -0
  205. data/capybara-3.40.0/lib/capybara/spec/session/save_and_open_page_spec.rb +21 -0
  206. data/capybara-3.40.0/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +43 -0
  207. data/capybara-3.40.0/lib/capybara/spec/session/save_page_spec.rb +110 -0
  208. data/capybara-3.40.0/lib/capybara/spec/session/save_screenshot_spec.rb +55 -0
  209. data/capybara-3.40.0/lib/capybara/spec/session/screenshot_spec.rb +18 -0
  210. data/capybara-3.40.0/lib/capybara/spec/session/scroll_spec.rb +119 -0
  211. data/capybara-3.40.0/lib/capybara/spec/session/select_spec.rb +229 -0
  212. data/capybara-3.40.0/lib/capybara/spec/session/selectors_spec.rb +98 -0
  213. data/capybara-3.40.0/lib/capybara/spec/session/sibling_spec.rb +52 -0
  214. data/capybara-3.40.0/lib/capybara/spec/session/text_spec.rb +74 -0
  215. data/capybara-3.40.0/lib/capybara/spec/session/title_spec.rb +29 -0
  216. data/capybara-3.40.0/lib/capybara/spec/session/uncheck_spec.rb +100 -0
  217. data/capybara-3.40.0/lib/capybara/spec/session/unselect_spec.rb +116 -0
  218. data/capybara-3.40.0/lib/capybara/spec/session/visit_spec.rb +224 -0
  219. data/capybara-3.40.0/lib/capybara/spec/session/window/become_closed_spec.rb +89 -0
  220. data/capybara-3.40.0/lib/capybara/spec/session/window/current_window_spec.rb +28 -0
  221. data/capybara-3.40.0/lib/capybara/spec/session/window/open_new_window_spec.rb +31 -0
  222. data/capybara-3.40.0/lib/capybara/spec/session/window/switch_to_window_spec.rb +132 -0
  223. data/capybara-3.40.0/lib/capybara/spec/session/window/window_opened_by_spec.rb +99 -0
  224. data/capybara-3.40.0/lib/capybara/spec/session/window/window_spec.rb +203 -0
  225. data/capybara-3.40.0/lib/capybara/spec/session/window/windows_spec.rb +34 -0
  226. data/capybara-3.40.0/lib/capybara/spec/session/window/within_window_spec.rb +157 -0
  227. data/capybara-3.40.0/lib/capybara/spec/session/within_spec.rb +212 -0
  228. data/capybara-3.40.0/lib/capybara/spec/spec_helper.rb +141 -0
  229. data/capybara-3.40.0/lib/capybara/spec/test_app.rb +305 -0
  230. data/capybara-3.40.0/lib/capybara/spec/views/animated.erb +49 -0
  231. data/capybara-3.40.0/lib/capybara/spec/views/buttons.erb +5 -0
  232. data/capybara-3.40.0/lib/capybara/spec/views/fieldsets.erb +30 -0
  233. data/capybara-3.40.0/lib/capybara/spec/views/form.erb +738 -0
  234. data/capybara-3.40.0/lib/capybara/spec/views/frame_child.erb +18 -0
  235. data/capybara-3.40.0/lib/capybara/spec/views/frame_one.erb +10 -0
  236. data/capybara-3.40.0/lib/capybara/spec/views/frame_parent.erb +9 -0
  237. data/capybara-3.40.0/lib/capybara/spec/views/frame_two.erb +9 -0
  238. data/capybara-3.40.0/lib/capybara/spec/views/header_links.erb +8 -0
  239. data/capybara-3.40.0/lib/capybara/spec/views/host_links.erb +13 -0
  240. data/capybara-3.40.0/lib/capybara/spec/views/initial_alert.erb +11 -0
  241. data/capybara-3.40.0/lib/capybara/spec/views/layout.erb +10 -0
  242. data/capybara-3.40.0/lib/capybara/spec/views/obscured.erb +47 -0
  243. data/capybara-3.40.0/lib/capybara/spec/views/offset.erb +33 -0
  244. data/capybara-3.40.0/lib/capybara/spec/views/path.erb +13 -0
  245. data/capybara-3.40.0/lib/capybara/spec/views/popup_one.erb +9 -0
  246. data/capybara-3.40.0/lib/capybara/spec/views/popup_two.erb +9 -0
  247. data/capybara-3.40.0/lib/capybara/spec/views/postback.erb +14 -0
  248. data/capybara-3.40.0/lib/capybara/spec/views/react.erb +45 -0
  249. data/capybara-3.40.0/lib/capybara/spec/views/scroll.erb +21 -0
  250. data/capybara-3.40.0/lib/capybara/spec/views/spatial.erb +31 -0
  251. data/capybara-3.40.0/lib/capybara/spec/views/tables.erb +130 -0
  252. data/capybara-3.40.0/lib/capybara/spec/views/with_animation.erb +81 -0
  253. data/capybara-3.40.0/lib/capybara/spec/views/with_base_tag.erb +11 -0
  254. data/capybara-3.40.0/lib/capybara/spec/views/with_count.erb +8 -0
  255. data/capybara-3.40.0/lib/capybara/spec/views/with_dragula.erb +24 -0
  256. data/capybara-3.40.0/lib/capybara/spec/views/with_fixed_header_footer.erb +18 -0
  257. data/capybara-3.40.0/lib/capybara/spec/views/with_hover.erb +24 -0
  258. data/capybara-3.40.0/lib/capybara/spec/views/with_hover1.erb +10 -0
  259. data/capybara-3.40.0/lib/capybara/spec/views/with_html.erb +210 -0
  260. data/capybara-3.40.0/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  261. data/capybara-3.40.0/lib/capybara/spec/views/with_html_entities.erb +2 -0
  262. data/capybara-3.40.0/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  263. data/capybara-3.40.0/lib/capybara/spec/views/with_js.erb +162 -0
  264. data/capybara-3.40.0/lib/capybara/spec/views/with_jstree.erb +26 -0
  265. data/capybara-3.40.0/lib/capybara/spec/views/with_namespace.erb +21 -0
  266. data/capybara-3.40.0/lib/capybara/spec/views/with_scope.erb +42 -0
  267. data/capybara-3.40.0/lib/capybara/spec/views/with_scope_other.erb +6 -0
  268. data/capybara-3.40.0/lib/capybara/spec/views/with_shadow.erb +31 -0
  269. data/capybara-3.40.0/lib/capybara/spec/views/with_simple_html.erb +2 -0
  270. data/capybara-3.40.0/lib/capybara/spec/views/with_slow_unload.erb +18 -0
  271. data/capybara-3.40.0/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  272. data/capybara-3.40.0/lib/capybara/spec/views/with_unload_alert.erb +15 -0
  273. data/capybara-3.40.0/lib/capybara/spec/views/with_windows.erb +54 -0
  274. data/capybara-3.40.0/lib/capybara/spec/views/within_frames.erb +15 -0
  275. data/capybara-3.40.0/lib/capybara/version.rb +5 -0
  276. data/capybara-3.40.0/lib/capybara/window.rb +142 -0
  277. data/capybara-3.40.0/lib/capybara.rb +521 -0
  278. data/capybara-3.40.0/spec/basic_node_spec.rb +168 -0
  279. data/capybara-3.40.0/spec/capybara_spec.rb +124 -0
  280. data/capybara-3.40.0/spec/counter_spec.rb +35 -0
  281. data/capybara-3.40.0/spec/css_builder_spec.rb +101 -0
  282. data/capybara-3.40.0/spec/css_splitter_spec.rb +38 -0
  283. data/capybara-3.40.0/spec/dsl_spec.rb +291 -0
  284. data/capybara-3.40.0/spec/filter_set_spec.rb +46 -0
  285. data/capybara-3.40.0/spec/fixtures/capybara.csv +1 -0
  286. data/capybara-3.40.0/spec/fixtures/certificate.pem +25 -0
  287. data/capybara-3.40.0/spec/fixtures/key.pem +27 -0
  288. data/capybara-3.40.0/spec/fixtures/selenium_driver_rspec_failure.rb +13 -0
  289. data/capybara-3.40.0/spec/fixtures/selenium_driver_rspec_success.rb +13 -0
  290. data/capybara-3.40.0/spec/minitest_spec.rb +175 -0
  291. data/capybara-3.40.0/spec/minitest_spec_spec.rb +166 -0
  292. data/capybara-3.40.0/spec/per_session_config_spec.rb +68 -0
  293. data/capybara-3.40.0/spec/rack_test_spec.rb +297 -0
  294. data/capybara-3.40.0/spec/regexp_dissassembler_spec.rb +250 -0
  295. data/capybara-3.40.0/spec/result_spec.rb +202 -0
  296. data/capybara-3.40.0/spec/rspec/features_spec.rb +101 -0
  297. data/capybara-3.40.0/spec/rspec/scenarios_spec.rb +23 -0
  298. data/capybara-3.40.0/spec/rspec/shared_spec_matchers.rb +983 -0
  299. data/capybara-3.40.0/spec/rspec/views_spec.rb +14 -0
  300. data/capybara-3.40.0/spec/rspec_matchers_spec.rb +87 -0
  301. data/capybara-3.40.0/spec/rspec_spec.rb +149 -0
  302. data/capybara-3.40.0/spec/sauce_spec_chrome.rb +43 -0
  303. data/capybara-3.40.0/spec/selector_spec.rb +528 -0
  304. data/capybara-3.40.0/spec/selenium_spec_chrome.rb +209 -0
  305. data/capybara-3.40.0/spec/selenium_spec_chrome_remote.rb +96 -0
  306. data/capybara-3.40.0/spec/selenium_spec_edge.rb +60 -0
  307. data/capybara-3.40.0/spec/selenium_spec_firefox.rb +228 -0
  308. data/capybara-3.40.0/spec/selenium_spec_firefox_remote.rb +94 -0
  309. data/capybara-3.40.0/spec/selenium_spec_ie.rb +149 -0
  310. data/capybara-3.40.0/spec/selenium_spec_safari.rb +162 -0
  311. data/capybara-3.40.0/spec/server_spec.rb +315 -0
  312. data/capybara-3.40.0/spec/session_spec.rb +91 -0
  313. data/capybara-3.40.0/spec/shared_selenium_node.rb +79 -0
  314. data/capybara-3.40.0/spec/shared_selenium_session.rb +566 -0
  315. data/capybara-3.40.0/spec/spec_helper.rb +133 -0
  316. data/capybara-3.40.0/spec/whitespace_normalizer_spec.rb +54 -0
  317. data/capybara-3.40.0/spec/xpath_builder_spec.rb +93 -0
  318. data/mega-max-rb.gemspec +12 -0
  319. metadata +358 -0
@@ -0,0 +1,1399 @@
1
+ # frozen_string_literal: true
2
+
3
+ # NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
4
+ # because of the methods being tested. In tests using Capybara this type of behavior should be implemented
5
+ # using Capybara provided assertions with builtin waiting behavior.
6
+
7
+ Capybara::SpecHelper.spec 'node' do
8
+ before do
9
+ @session.visit('/with_html')
10
+ end
11
+
12
+ it 'should act like a session object' do
13
+ @session.visit('/form')
14
+ @form = @session.find(:css, '#get-form')
15
+ expect(@form).to have_field('Middle Name')
16
+ expect(@form).to have_no_field('Languages')
17
+ @form.fill_in('Middle Name', with: 'Monkey')
18
+ @form.click_button('med')
19
+ expect(extract_results(@session)['middle_name']).to eq('Monkey')
20
+ end
21
+
22
+ it 'should scope CSS selectors' do
23
+ expect(@session.find(:css, '#second')).to have_no_css('h1')
24
+ end
25
+
26
+ describe '#query_scope' do
27
+ it 'should have a reference to the element the query was evaluated on if there is one' do
28
+ node = @session.find(:css, '#first')
29
+ expect(node.query_scope).to eq(node.session.document)
30
+ expect(node.find(:css, '#foo').query_scope).to eq(node)
31
+ end
32
+ end
33
+
34
+ describe '#text' do
35
+ it 'should extract node texts' do
36
+ expect(@session.all('//a')[0].text).to eq('labore')
37
+ expect(@session.all('//a')[1].text).to eq('ullamco')
38
+ end
39
+
40
+ it 'should return document text on /html selector' do
41
+ @session.visit('/with_simple_html')
42
+ expect(@session.all('/html')[0].text).to eq('Bar')
43
+ end
44
+ end
45
+
46
+ describe '#[]' do
47
+ it 'should extract node attributes' do
48
+ expect(@session.all('//a')[0][:class]).to eq('simple')
49
+ expect(@session.all('//a')[1][:id]).to eq('foo')
50
+ expect(@session.all('//input')[0][:type]).to eq('text')
51
+ end
52
+
53
+ it 'should extract boolean node attributes' do
54
+ expect(@session.find('//input[@id="checked_field"]')[:checked]).to be_truthy
55
+ end
56
+ end
57
+
58
+ describe '#style', requires: [:css] do
59
+ it 'should return the computed style value' do
60
+ expect(@session.find(:css, '#first').style('display')).to eq('display' => 'block')
61
+ expect(@session.find(:css, '#second').style(:display)).to eq('display' => 'inline')
62
+ end
63
+
64
+ it 'should return multiple style values' do
65
+ expect(@session.find(:css, '#first').style('display', :'line-height')).to eq('display' => 'block', 'line-height' => '25px')
66
+ end
67
+ end
68
+
69
+ describe '#value' do
70
+ it 'should allow retrieval of the value' do
71
+ expect(@session.find('//textarea[@id="normal"]').value).to eq('banana')
72
+ end
73
+
74
+ it 'should not swallow extra newlines in textarea' do
75
+ expect(@session.find('//textarea[@id="additional_newline"]').value).to eq("\nbanana")
76
+ end
77
+
78
+ it 'should not swallow leading newlines for set content in textarea' do
79
+ @session.find('//textarea[@id="normal"]').set("\nbanana")
80
+ expect(@session.find('//textarea[@id="normal"]').value).to eq("\nbanana")
81
+ end
82
+
83
+ it 'return any HTML content in textarea' do
84
+ @session.find('//textarea[1]').set('some <em>html</em> here')
85
+ expect(@session.find('//textarea[1]').value).to eq('some <em>html</em> here')
86
+ end
87
+
88
+ it "defaults to 'on' for checkbox" do
89
+ @session.visit('/form')
90
+ expect(@session.find('//input[@id="valueless_checkbox"]').value).to eq('on')
91
+ end
92
+
93
+ it "defaults to 'on' for radio buttons" do
94
+ @session.visit('/form')
95
+ expect(@session.find('//input[@id="valueless_radio"]').value).to eq('on')
96
+ end
97
+ end
98
+
99
+ describe '#set' do
100
+ it 'should allow assignment of field value' do
101
+ expect(@session.first('//input').value).to eq('monkey')
102
+ @session.first('//input').set('gorilla')
103
+ expect(@session.first('//input').value).to eq('gorilla')
104
+ end
105
+
106
+ it 'should fill the field even if the caret was not at the end', requires: [:js] do
107
+ @session.execute_script("var el = document.getElementById('test_field'); el.focus(); el.setSelectionRange(0, 0);")
108
+ @session.first('//input').set('')
109
+ expect(@session.first('//input').value).to eq('')
110
+ end
111
+
112
+ if ENV['CAPYBARA_THOROUGH']
113
+ it 'should raise if the text field is readonly' do
114
+ expect { @session.first('//input[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
115
+ end
116
+
117
+ it 'should raise if the textarea is readonly' do
118
+ expect { @session.first('//textarea[@readonly]').set('changed') }.to raise_error(Capybara::ReadOnlyElementError)
119
+ end
120
+ else
121
+ it 'should not change if the text field is readonly' do
122
+ @session.first('//input[@readonly]').set('changed')
123
+ expect(@session.first('//input[@readonly]').value).to eq 'should not change'
124
+ end
125
+
126
+ it 'should not change if the textarea is readonly' do
127
+ @session.first('//textarea[@readonly]').set('changed')
128
+ expect(@session.first('//textarea[@readonly]').value).to eq 'textarea should not change'
129
+ end
130
+ end
131
+
132
+ it 'should use global default options' do
133
+ Capybara.default_set_options = { clear: :backspace }
134
+ element = @session.first(:fillable_field, type: 'text')
135
+ allow(element.base).to receive(:set)
136
+ element.set('gorilla')
137
+ expect(element.base).to have_received(:set).with('gorilla', clear: :backspace)
138
+ end
139
+
140
+ context 'with a contenteditable element', requires: [:js] do
141
+ it 'should allow me to change the contents' do
142
+ @session.visit('/with_js')
143
+ @session.find(:css, '#existing_content_editable').set('WYSIWYG')
144
+ expect(@session.find(:css, '#existing_content_editable').text).to eq('WYSIWYG')
145
+ end
146
+
147
+ it 'should allow me to set the contents' do
148
+ @session.visit('/with_js')
149
+ @session.find(:css, '#blank_content_editable').set('WYSIWYG')
150
+ expect(@session.find(:css, '#blank_content_editable').text).to eq('WYSIWYG')
151
+ end
152
+
153
+ it 'should allow me to change the contents of a child element' do
154
+ @session.visit('/with_js')
155
+ @session.find(:css, '#existing_content_editable_child').set('WYSIWYG')
156
+ expect(@session.find(:css, '#existing_content_editable_child').text).to eq('WYSIWYG')
157
+ expect(@session.find(:css, '#existing_content_editable_child_parent').text).to eq("Some content\nWYSIWYG")
158
+ end
159
+ end
160
+
161
+ it 'should submit single text input forms if ended with \n' do
162
+ @session.visit('/form')
163
+ @session.find(:css, '#single_input').set("my entry\n")
164
+ expect(extract_results(@session)['single_input']).to eq('my entry')
165
+ end
166
+
167
+ it 'should not submit single text input forms if ended with \n and has multiple values' do
168
+ @session.visit('/form')
169
+ @session.find(:css, '#two_input_1').set("my entry\n")
170
+ expect(@session.find(:css, '#two_input_1').value).to eq("my entry\n").or(eq 'my entry')
171
+ end
172
+ end
173
+
174
+ describe '#tag_name' do
175
+ it 'should extract node tag name' do
176
+ expect(@session.all('//a')[0].tag_name).to eq('a')
177
+ expect(@session.all('//a')[1].tag_name).to eq('a')
178
+ expect(@session.all('//p')[1].tag_name).to eq('p')
179
+ end
180
+ end
181
+
182
+ describe '#disabled?' do
183
+ it 'should extract disabled node' do
184
+ @session.visit('/form')
185
+ expect(@session.find('//input[@id="customer_name"]')).to be_disabled
186
+ expect(@session.find('//input[@id="customer_email"]')).not_to be_disabled
187
+ end
188
+
189
+ it 'should see disabled options as disabled' do
190
+ @session.visit('/form')
191
+ expect(@session.find('//select[@id="form_title"]/option[1]')).not_to be_disabled
192
+ expect(@session.find('//select[@id="form_title"]/option[@disabled]')).to be_disabled
193
+ end
194
+
195
+ it 'should see enabled options in disabled select as disabled' do
196
+ @session.visit('/form')
197
+ expect(@session.find('//select[@id="form_disabled_select"]/option')).to be_disabled
198
+ expect(@session.find('//select[@id="form_disabled_select"]/optgroup/option')).to be_disabled
199
+ expect(@session.find('//select[@id="form_title"]/option[1]')).not_to be_disabled
200
+ end
201
+
202
+ it 'should see enabled options in disabled optgroup as disabled' do
203
+ @session.visit('/form')
204
+ expect(@session.find('//option', text: 'A.B.1')).to be_disabled
205
+ expect(@session.find('//option', text: 'A.2')).not_to be_disabled
206
+ end
207
+
208
+ it 'should see a disabled fieldset as disabled' do
209
+ @session.visit('/form')
210
+ expect(@session.find(:xpath, './/fieldset[@id="form_disabled_fieldset"]')).to be_disabled
211
+ end
212
+
213
+ context 'in a disabled fieldset' do
214
+ # https://html.spec.whatwg.org/#the-fieldset-element
215
+ it 'should see elements not in first legend as disabled' do
216
+ @session.visit('/form')
217
+ expect(@session.find('//input[@id="form_disabled_fieldset_child"]')).to be_disabled
218
+ expect(@session.find('//input[@id="form_disabled_fieldset_second_legend_child"]')).to be_disabled
219
+ expect(@session.find('//input[@id="form_enabled_fieldset_child"]')).not_to be_disabled
220
+ end
221
+
222
+ it 'should see elements in first legend as enabled' do
223
+ @session.visit('/form')
224
+ expect(@session.find('//input[@id="form_disabled_fieldset_legend_child"]')).not_to be_disabled
225
+ end
226
+
227
+ it 'should sees options not in first legend as disabled' do
228
+ @session.visit('/form')
229
+ expect(@session.find('//option', text: 'Disabled Child Option')).to be_disabled
230
+ end
231
+ end
232
+
233
+ it 'should be boolean' do
234
+ @session.visit('/form')
235
+ expect(@session.find('//select[@id="form_disabled_select"]/option').disabled?).to be true
236
+ expect(@session.find('//select[@id="form_disabled_select2"]/option').disabled?).to be true
237
+ expect(@session.find('//select[@id="form_title"]/option[1]').disabled?).to be false
238
+ end
239
+
240
+ it 'should be disabled for all elements that are CSS :disabled' do
241
+ @session.visit('/form')
242
+ # sanity check
243
+ expect(@session.all(:css, ':disabled')).to all(be_disabled)
244
+ end
245
+ end
246
+
247
+ describe '#visible?' do
248
+ before { Capybara.ignore_hidden_elements = false }
249
+
250
+ it 'should extract node visibility' do
251
+ expect(@session.first('//a')).to be_visible
252
+
253
+ expect(@session.find('//div[@id="hidden"]')).not_to be_visible
254
+ expect(@session.find('//div[@id="hidden_via_ancestor"]')).not_to be_visible
255
+ expect(@session.find('//div[@id="hidden_attr"]')).not_to be_visible
256
+ expect(@session.find('//a[@id="hidden_attr_via_ancestor"]')).not_to be_visible
257
+ expect(@session.find('//input[@id="hidden_input"]')).not_to be_visible
258
+ end
259
+
260
+ it 'template elements should not be visible' do
261
+ expect(@session.find('//template')).not_to be_visible
262
+ end
263
+
264
+ it 'should be boolean' do
265
+ expect(@session.first('//a').visible?).to be true
266
+ expect(@session.find('//div[@id="hidden"]').visible?).to be false
267
+ end
268
+
269
+ it 'closed details > summary elements and descendants should be visible' do
270
+ expect(@session.find(:css, '#closed_details summary')).to be_visible
271
+ expect(@session.find(:css, '#closed_details summary h6')).to be_visible
272
+ end
273
+
274
+ it 'details non-summary descendants should be non-visible when closed' do
275
+ descendants = @session.all(:css, '#closed_details > *:not(summary), #closed_details > *:not(summary) *', minimum: 2)
276
+ expect(descendants).not_to include(be_visible)
277
+ end
278
+
279
+ it 'deatils descendants should be visible when open' do
280
+ descendants = @session.all(:css, '#open_details *')
281
+ expect(descendants).to all(be_visible)
282
+ end
283
+
284
+ it 'works when details is toggled open and closed' do
285
+ @session.find(:css, '#closed_details > summary').click
286
+ expect(@session).to have_css('#closed_details *', visible: :visible, count: 5)
287
+ .and(have_no_css('#closed_details *', visible: :hidden))
288
+
289
+ @session.find(:css, '#closed_details > summary').click
290
+ descendants_css = '#closed_details > *:not(summary), #closed_details > *:not(summary) *'
291
+ expect(@session).to have_no_css(descendants_css, visible: :visible)
292
+ .and(have_css(descendants_css, visible: :hidden, count: 3))
293
+ end
294
+ end
295
+
296
+ describe '#obscured?', requires: [:css] do
297
+ it 'should see non visible elements as obscured' do
298
+ Capybara.ignore_hidden_elements = false
299
+ expect(@session.find('//div[@id="hidden"]')).to be_obscured
300
+ expect(@session.find('//div[@id="hidden_via_ancestor"]')).to be_obscured
301
+ expect(@session.find('//div[@id="hidden_attr"]')).to be_obscured
302
+ expect(@session.find('//a[@id="hidden_attr_via_ancestor"]')).to be_obscured
303
+ expect(@session.find('//input[@id="hidden_input"]')).to be_obscured
304
+ end
305
+
306
+ it 'should see non-overlapped elements as not obscured' do
307
+ @session.visit('/obscured')
308
+ expect(@session.find(:css, '#cover')).not_to be_obscured
309
+ end
310
+
311
+ it 'should see elements only overlapped by descendants as not obscured' do
312
+ expect(@session.first(:css, 'p:not(.para)')).not_to be_obscured
313
+ end
314
+
315
+ it 'should see elements outside the viewport as obscured' do
316
+ @session.visit('/obscured')
317
+ off = @session.find(:css, '#offscreen')
318
+ off_wrapper = @session.find(:css, '#offscreen_wrapper')
319
+ expect(off).to be_obscured
320
+ expect(off_wrapper).to be_obscured
321
+ @session.scroll_to(off_wrapper)
322
+ expect(off_wrapper).not_to be_obscured
323
+ expect(off).to be_obscured
324
+ off_wrapper.scroll_to(off)
325
+ expect(off).not_to be_obscured
326
+ expect(off_wrapper).not_to be_obscured
327
+ end
328
+
329
+ it 'should see overlapped elements as obscured' do
330
+ @session.visit('/obscured')
331
+ expect(@session.find(:css, '#obscured')).to be_obscured
332
+ end
333
+
334
+ it 'should be boolean' do
335
+ Capybara.ignore_hidden_elements = false
336
+ expect(@session.first('//a').obscured?).to be false
337
+ expect(@session.find('//div[@id="hidden"]').obscured?).to be true
338
+ end
339
+
340
+ it 'should work in frames' do
341
+ @session.visit('/obscured')
342
+ frame = @session.find(:css, '#frameOne')
343
+ @session.within_frame(frame) do
344
+ div = @session.find(:css, '#divInFrameOne')
345
+ expect(div).to be_obscured
346
+ @session.scroll_to div
347
+ expect(div).not_to be_obscured
348
+ end
349
+ end
350
+
351
+ it 'should work in nested iframes' do
352
+ @session.visit('/obscured')
353
+ frame = @session.find(:css, '#nestedFrames')
354
+ @session.within_frame(frame) do
355
+ @session.within_frame(:css, '#childFrame') do
356
+ gcframe = @session.find(:css, '#grandchildFrame2')
357
+ @session.within_frame(gcframe) do
358
+ expect(@session.find(:css, '#divInFrameTwo')).to be_obscured
359
+ end
360
+ @session.scroll_to(gcframe)
361
+ @session.within_frame(gcframe) do
362
+ expect(@session.find(:css, '#divInFrameTwo')).not_to be_obscured
363
+ end
364
+ end
365
+ end
366
+ end
367
+ end
368
+
369
+ describe '#checked?' do
370
+ it 'should extract node checked state' do
371
+ @session.visit('/form')
372
+ expect(@session.find('//input[@id="gender_female"]')).to be_checked
373
+ expect(@session.find('//input[@id="gender_male"]')).not_to be_checked
374
+ expect(@session.first('//h1')).not_to be_checked
375
+ end
376
+
377
+ it 'should be boolean' do
378
+ @session.visit('/form')
379
+ expect(@session.find('//input[@id="gender_female"]').checked?).to be true
380
+ expect(@session.find('//input[@id="gender_male"]').checked?).to be false
381
+ expect(@session.find('//input[@id="no_attr_value_checked"]').checked?).to be true
382
+ end
383
+ end
384
+
385
+ describe '#selected?' do
386
+ it 'should extract node selected state' do
387
+ @session.visit('/form')
388
+ expect(@session.find('//option[@value="en"]')).to be_selected
389
+ expect(@session.find('//option[@value="sv"]')).not_to be_selected
390
+ expect(@session.first('//h1')).not_to be_selected
391
+ end
392
+
393
+ it 'should be boolean' do
394
+ @session.visit('/form')
395
+ expect(@session.find('//option[@value="en"]').selected?).to be true
396
+ expect(@session.find('//option[@value="sv"]').selected?).to be false
397
+ expect(@session.first('//h1').selected?).to be false
398
+ end
399
+ end
400
+
401
+ describe '#==' do
402
+ it 'preserve object identity' do
403
+ expect(@session.find('//h1') == @session.find('//h1')).to be true # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
404
+ expect(@session.find('//h1') === @session.find('//h1')).to be true # rubocop:disable Style/CaseEquality, Lint/BinaryOperatorWithIdenticalOperands
405
+ expect(@session.find('//h1').eql?(@session.find('//h1'))).to be false
406
+ end
407
+
408
+ it 'returns false for unrelated object' do
409
+ expect(@session.find('//h1') == 'Not Capybara::Node::Base').to be false
410
+ end
411
+ end
412
+
413
+ describe '#path' do
414
+ # Testing for specific XPaths here doesn't make sense since there
415
+ # are many that can refer to the same element
416
+ before do
417
+ @session.visit('/path')
418
+ end
419
+
420
+ it 'returns xpath which points to itself' do
421
+ element = @session.find(:link, 'Second Link')
422
+ expect(@session.find(:xpath, element.path)).to eq(element)
423
+ end
424
+
425
+ it 'reports when element in shadow dom', requires: [:shadow_dom] do
426
+ @session.visit('/with_js')
427
+ shadow = @session.find(:css, '#shadow')
428
+ element = @session.evaluate_script(<<~JS, shadow)
429
+ (function(root){
430
+ return root.shadowRoot.querySelector('span');
431
+ })(arguments[0])
432
+ JS
433
+ expect(element.path).to eq '(: Shadow DOM element - no XPath :)'
434
+ end
435
+ end
436
+
437
+ describe '#trigger', requires: %i[js trigger] do
438
+ it 'should allow triggering of custom JS events' do
439
+ @session.visit('/with_js')
440
+ @session.find(:css, '#with_focus_event').trigger(:focus)
441
+ expect(@session).to have_css('#focus_event_triggered')
442
+ end
443
+ end
444
+
445
+ describe '#drag_to', requires: %i[js drag] do
446
+ it 'should drag and drop an object' do
447
+ @session.visit('/with_js')
448
+ element = @session.find('//div[@id="drag"]')
449
+ target = @session.find('//div[@id="drop"]')
450
+ element.drag_to(target)
451
+ expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
452
+ end
453
+
454
+ it 'should drag and drop if scrolling is needed' do
455
+ @session.visit('/with_js')
456
+ element = @session.find('//div[@id="drag_scroll"]')
457
+ target = @session.find('//div[@id="drop_scroll"]')
458
+ element.drag_to(target)
459
+ expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
460
+ end
461
+
462
+ it 'should drag a link' do
463
+ @session.visit('/with_js')
464
+ link = @session.find_link('drag_link')
465
+ target = @session.find(:id, 'drop')
466
+ link.drag_to target
467
+ expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
468
+ end
469
+
470
+ it 'should work with Dragula' do
471
+ @session.visit('/with_dragula')
472
+ @session.within(:css, '#sortable.ready') do
473
+ src = @session.find('div', text: 'Item 1')
474
+ target = @session.find('div', text: 'Item 3')
475
+ src.drag_to target
476
+ expect(@session).to have_content(/Item 2.*Item 1/, normalize_ws: true)
477
+ end
478
+ end
479
+
480
+ it 'should work with jsTree' do
481
+ @session.visit('/with_jstree')
482
+ @session.within(:css, '#container') do
483
+ @session.assert_text(/A.*B.*C/m)
484
+ source = @session.find(:css, '#j1_1_anchor')
485
+ target = @session.find(:css, '#j1_2_anchor')
486
+
487
+ source.drag_to(target)
488
+
489
+ @session.assert_no_text(/A.*B.*C/m)
490
+ @session.assert_text(/B.*C/m)
491
+ end
492
+ end
493
+
494
+ it 'should simulate a single held down modifier key' do
495
+ %I[
496
+ alt
497
+ ctrl
498
+ meta
499
+ shift
500
+ ].each do |modifier_key|
501
+ @session.visit('/with_js')
502
+
503
+ element = @session.find('//div[@id="drag"]')
504
+ target = @session.find('//div[@id="drop"]')
505
+
506
+ element.drag_to(target, drop_modifiers: modifier_key)
507
+ expect(@session).to have_css('div.drag_start', exact_text: 'Dragged!')
508
+ expect(@session).to have_xpath("//div[contains(., 'Dropped!-#{modifier_key}')]")
509
+ end
510
+ end
511
+
512
+ it 'should simulate multiple held down modifier keys' do
513
+ @session.visit('/with_js')
514
+
515
+ element = @session.find('//div[@id="drag"]')
516
+ target = @session.find('//div[@id="drop"]')
517
+
518
+ modifier_keys = %I[alt ctrl meta shift]
519
+
520
+ element.drag_to(target, drop_modifiers: modifier_keys)
521
+ expect(@session).to have_xpath("//div[contains(., 'Dropped!-#{modifier_keys.join('-')}')]")
522
+ end
523
+
524
+ it 'should support key aliases' do
525
+ { control: :ctrl,
526
+ command: :meta,
527
+ cmd: :meta }.each do |(key_alias, key)|
528
+ @session.visit('/with_js')
529
+
530
+ element = @session.find('//div[@id="drag"]')
531
+ target = @session.find('//div[@id="drop"]')
532
+
533
+ element.drag_to(target, drop_modifiers: [key_alias])
534
+ expect(target).to have_text("Dropped!-#{key}", exact: true)
535
+ end
536
+ end
537
+
538
+ context 'HTML5', requires: %i[js html5_drag] do
539
+ it 'should HTML5 drag and drop an object' do
540
+ @session.visit('/with_js')
541
+ element = @session.find('//div[@id="drag_html5"]')
542
+ target = @session.find('//div[@id="drop_html5"]')
543
+ element.drag_to(target)
544
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5")]')
545
+ end
546
+
547
+ it 'should HTML5 drag and drop an object child' do
548
+ @session.visit('/with_js')
549
+ element = @session.find('//div[@id="drag_html5"]/p')
550
+ target = @session.find('//div[@id="drop_html5"]')
551
+ element.drag_to(target)
552
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5")]')
553
+ end
554
+
555
+ it 'should set clientX/Y in dragover events' do
556
+ @session.visit('/with_js')
557
+ element = @session.find('//div[@id="drag_html5"]')
558
+ target = @session.find('//div[@id="drop_html5"]')
559
+ element.drag_to(target)
560
+ expect(@session).to have_css('div.log', text: /DragOver with client position: [1-9]\d*,[1-9]\d*/, count: 2)
561
+ end
562
+
563
+ it 'should preserve clientX/Y from last dragover event' do
564
+ @session.visit('/with_js')
565
+ element = @session.find('//div[@id="drag_html5"]')
566
+ target = @session.find('//div[@id="drop_html5"]')
567
+ element.drag_to(target)
568
+
569
+ conditions = %w[DragLeave Drop DragEnd].map do |text|
570
+ have_css('div.log', text: text)
571
+ end
572
+ expect(@session).to(conditions.reduce { |memo, cond| memo.and(cond) })
573
+
574
+ # The first "DragOver" div is inserted by the last dragover event dispatched
575
+ drag_over_div = @session.first('//div[@class="log" and starts-with(text(), "DragOver")]')
576
+ position = drag_over_div.text.sub('DragOver ', '')
577
+
578
+ expect(@session).to have_css('div.log', text: /DragLeave #{position}/, count: 1)
579
+ expect(@session).to have_css('div.log', text: /Drop #{position}/, count: 1)
580
+ expect(@session).to have_css('div.log', text: /DragEnd #{position}/, count: 1)
581
+ end
582
+
583
+ it 'should not HTML5 drag and drop on a non HTML5 drop element' do
584
+ @session.visit('/with_js')
585
+ element = @session.find('//div[@id="drag_html5"]')
586
+ target = @session.find('//div[@id="drop_html5"]')
587
+ target.execute_script("$(this).removeClass('drop');")
588
+ element.drag_to(target)
589
+ sleep 1
590
+ expect(@session).not_to have_xpath('//div[contains(., "HTML5 Dropped")]')
591
+ end
592
+
593
+ it 'should HTML5 drag and drop when scrolling needed' do
594
+ @session.visit('/with_js')
595
+ element = @session.find('//div[@id="drag_html5_scroll"]')
596
+ target = @session.find('//div[@id="drop_html5_scroll"]')
597
+ element.drag_to(target)
598
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5_scroll")]')
599
+ end
600
+
601
+ it 'should drag HTML5 default draggable elements' do
602
+ @session.visit('/with_js')
603
+ link = @session.find_link('drag_link_html5')
604
+ target = @session.find(:id, 'drop_html5')
605
+ link.drag_to target
606
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
607
+ end
608
+
609
+ it 'should work with SortableJS' do
610
+ @session.visit('/with_sortable_js')
611
+ @session.within(:css, '#sortable') do
612
+ src = @session.find('div', text: 'Item 1')
613
+ target = @session.find('div', text: 'Item 3')
614
+ src.drag_to target
615
+ expect(@session).to have_content(/Item 3.*Item 1/, normalize_ws: true)
616
+ end
617
+ end
618
+
619
+ it 'should drag HTML5 default draggable element child' do
620
+ @session.visit('/with_js')
621
+ source = @session.find_link('drag_link_html5').find(:css, 'p')
622
+ target = @session.find(:id, 'drop_html5')
623
+ source.drag_to target
624
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
625
+ end
626
+
627
+ it 'should simulate a single held down modifier key' do
628
+ %I[alt ctrl meta shift].each do |modifier_key|
629
+ @session.visit('/with_js')
630
+
631
+ element = @session.find('//div[@id="drag_html5"]')
632
+ target = @session.find('//div[@id="drop_html5"]')
633
+
634
+ element.drag_to(target, drop_modifiers: modifier_key)
635
+
636
+ expect(@session).to have_css('div.drag_start', exact_text: 'HTML5 Dragged!')
637
+ expect(@session).to have_xpath("//div[contains(., 'HTML5 Dropped string: text/plain drag_html5-#{modifier_key}')]")
638
+ end
639
+ end
640
+
641
+ it 'should simulate multiple held down modifier keys' do
642
+ @session.visit('/with_js')
643
+
644
+ element = @session.find('//div[@id="drag_html5"]')
645
+ target = @session.find('//div[@id="drop_html5"]')
646
+
647
+ modifier_keys = %I[alt ctrl meta shift]
648
+
649
+ element.drag_to(target, drop_modifiers: modifier_keys)
650
+ expect(@session).to have_xpath("//div[contains(., 'HTML5 Dropped string: text/plain drag_html5-#{modifier_keys.join('-')}')]")
651
+ end
652
+
653
+ it 'should support key aliases' do
654
+ { control: :ctrl,
655
+ command: :meta,
656
+ cmd: :meta }.each do |(key_alias, key)|
657
+ @session.visit('/with_js')
658
+
659
+ element = @session.find('//div[@id="drag_html5"]')
660
+ target = @session.find('//div[@id="drop_html5"]')
661
+
662
+ element.drag_to(target, drop_modifiers: [key_alias])
663
+ expect(target).to have_text(%r{^HTML5 Dropped string: text/plain drag_html5-#{key}$}m, exact: true)
664
+ end
665
+ end
666
+
667
+ it 'should trigger a dragenter event, before the first dragover event' do
668
+ @session.visit('/with_js')
669
+ element = @session.find('//div[@id="drag_html5"]')
670
+ target = @session.find('//div[@id="drop_html5"]')
671
+ element.drag_to(target)
672
+
673
+ # Events are listed in reverse chronological order
674
+ expect(@session).to have_text(/DragOver.*DragEnter/m)
675
+ end
676
+ end
677
+ end
678
+
679
+ describe 'Element#drop', requires: %i[js html5_drag] do
680
+ it 'can drop a file' do
681
+ @session.visit('/with_js')
682
+ target = @session.find('//div[@id="drop_html5"]')
683
+ target.drop(
684
+ with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__)))
685
+ )
686
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
687
+ end
688
+
689
+ it 'can drop multiple files' do
690
+ @session.visit('/with_js')
691
+ target = @session.find('//div[@id="drop_html5"]')
692
+ target.drop(
693
+ with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))),
694
+ with_os_path_separators(File.expand_path('../fixtures/test_file.txt', File.dirname(__FILE__)))
695
+ )
696
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
697
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: test_file.txt")]')
698
+ end
699
+
700
+ it 'can drop strings' do
701
+ @session.visit('/with_js')
702
+ target = @session.find('//div[@id="drop_html5"]')
703
+ target.drop('text/plain' => 'Some dropped text')
704
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
705
+ end
706
+
707
+ it 'can drop a pathname' do
708
+ @session.visit('/with_js')
709
+ target = @session.find('//div[@id="drop_html5"]')
710
+ target.drop(
711
+ Pathname.new(with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))))
712
+ )
713
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
714
+ end
715
+
716
+ it 'can drop multiple strings' do
717
+ @session.visit('/with_js')
718
+ target = @session.find('//div[@id="drop_html5"]')
719
+ target.drop('text/plain' => 'Some dropped text', 'text/url' => 'http://www.google.com')
720
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
721
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/url http://www.google.com")]')
722
+ end
723
+ end
724
+
725
+ describe '#hover', requires: [:hover] do
726
+ it 'should allow hovering on an element' do
727
+ @session.visit('/with_hover')
728
+ expect(@session.find(:css, '.wrapper:not(.scroll_needed) .hidden_until_hover', visible: false)).not_to be_visible
729
+ @session.find(:css, '.wrapper:not(.scroll_needed)').hover
730
+ expect(@session.find(:css, '.wrapper:not(.scroll_needed) .hidden_until_hover', visible: false)).to be_visible
731
+ end
732
+
733
+ it 'should allow hovering on an element that needs to be scrolled into view' do
734
+ @session.visit('/with_hover')
735
+ expect(@session.find(:css, '.wrapper.scroll_needed .hidden_until_hover', visible: false)).not_to be_visible
736
+ @session.find(:css, '.wrapper.scroll_needed').hover
737
+ expect(@session.find(:css, '.wrapper.scroll_needed .hidden_until_hover', visible: false)).to be_visible
738
+ end
739
+
740
+ it 'should hover again after following a link and back' do
741
+ @session.visit('/with_hover')
742
+ @session.find(:css, '.wrapper:not(.scroll_needed)').hover
743
+ @session.click_link('Other hover page')
744
+ @session.click_link('Go back')
745
+ @session.find(:css, '.wrapper:not(.scroll_needed)').hover
746
+ expect(@session.find(:css, '.wrapper:not(.scroll_needed) .hidden_until_hover', visible: false)).to be_visible
747
+ end
748
+ end
749
+
750
+ describe '#click' do
751
+ it 'should not follow a link if no href' do
752
+ @session.find(:css, '#link_placeholder').click
753
+ expect(@session.current_url).to match(%r{/with_html$})
754
+ end
755
+
756
+ it 'should go to the same page if href is blank' do
757
+ @session.find(:css, '#link_blank_href').click
758
+ sleep 1
759
+ expect(@session).to have_current_path('/with_html')
760
+ end
761
+
762
+ it 'should be able to check a checkbox' do
763
+ @session.visit('form')
764
+ cbox = @session.find(:checkbox, 'form_terms_of_use')
765
+ expect(cbox).not_to be_checked
766
+ cbox.click
767
+ expect(cbox).to be_checked
768
+ end
769
+
770
+ it 'should be able to uncheck a checkbox' do
771
+ @session.visit('/form')
772
+ cbox = @session.find(:checkbox, 'form_pets_dog')
773
+ expect(cbox).to be_checked
774
+ cbox.click
775
+ expect(cbox).not_to be_checked
776
+ end
777
+
778
+ it 'should be able to select a radio button' do
779
+ @session.visit('/form')
780
+ radio = @session.find(:radio_button, 'gender_male')
781
+ expect(radio).not_to be_checked
782
+ radio.click
783
+ expect(radio).to be_checked
784
+ end
785
+
786
+ it 'should allow modifiers', requires: [:js] do
787
+ @session.visit('/with_js')
788
+ @session.find(:css, '#click-test').click(:shift)
789
+ expect(@session).to have_link('Has been shift clicked')
790
+ end
791
+
792
+ it 'should allow multiple modifiers', requires: [:js] do
793
+ @session.visit('with_js')
794
+ @session.find(:css, '#click-test').click(:control, :alt, :meta, :shift)
795
+ # Selenium with Chrome on OSX ctrl-click generates a right click so just verify all keys but not click type
796
+ expect(@session).to have_link('alt control meta shift')
797
+ end
798
+
799
+ it 'should allow to adjust the click offset', requires: [:js] do
800
+ Capybara.w3c_click_offset = false
801
+ @session.visit('with_js')
802
+ @session.find(:css, '#click-test').click(x: 5, y: 5)
803
+ link = @session.find(:link, 'has-been-clicked')
804
+ locations = link.text.match(/^Has been clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
805
+ # Resulting click location should be very close to 0, 0 relative to top left corner of the element, but may not be exact due to
806
+ # integer/float conversions and rounding.
807
+ expect(locations[:x].to_f).to be_within(1).of(5)
808
+ expect(locations[:y].to_f).to be_within(1).of(5)
809
+ end
810
+
811
+ it 'should raise error if both x and y values are not passed' do
812
+ @session.visit('with_js')
813
+ el = @session.find(:css, '#click-test')
814
+ expect { el.click(x: 5) }.to raise_error ArgumentError
815
+ expect { el.click(x: nil, y: 3) }.to raise_error ArgumentError
816
+ end
817
+
818
+ it 'should be able to click a table row', requires: [:js] do
819
+ @session.visit('/tables')
820
+ tr = @session.find(:css, '#agent_table tr:first-child').click
821
+ expect(tr).to have_css('label', text: 'Clicked')
822
+ end
823
+
824
+ it 'should retry clicking', requires: [:js] do
825
+ @session.visit('/animated')
826
+ obscured = @session.find(:css, '#obscured')
827
+ @session.execute_script <<~JS
828
+ setTimeout(function(){ $('#cover').hide(); }, 700)
829
+ JS
830
+ expect { obscured.click }.not_to raise_error
831
+ end
832
+
833
+ it 'should allow to retry longer', requires: [:js] do
834
+ @session.visit('/animated')
835
+ obscured = @session.find(:css, '#obscured')
836
+ @session.execute_script <<~JS
837
+ setTimeout(function(){ $('#cover').hide(); }, 3000)
838
+ JS
839
+ expect { obscured.click(wait: 4) }.not_to raise_error
840
+ end
841
+
842
+ it 'should not retry clicking when wait is disabled', requires: [:js] do
843
+ @session.visit('/animated')
844
+ obscured = @session.find(:css, '#obscured')
845
+ @session.execute_script <<~JS
846
+ setTimeout(function(){ $('#cover').hide(); }, 2000)
847
+ JS
848
+ expect { obscured.click(wait: 0) }.to(raise_error { |e| expect(e).to be_an_invalid_element_error(@session) })
849
+ end
850
+
851
+ context 'offset', requires: [:js] do
852
+ before do
853
+ @session.visit('/offset')
854
+ end
855
+
856
+ let :clicker do
857
+ @session.find(:id, 'clicker')
858
+ end
859
+
860
+ context 'when w3c_click_offset is false' do
861
+ before do
862
+ Capybara.w3c_click_offset = false
863
+ end
864
+
865
+ it 'should offset from top left of element' do
866
+ clicker.click(x: 10, y: 5)
867
+ expect(@session).to have_text(/clicked at 110,105/)
868
+ end
869
+
870
+ it 'should offset outside the element' do
871
+ clicker.click(x: -15, y: -10)
872
+ expect(@session).to have_text(/clicked at 85,90/)
873
+ end
874
+
875
+ it 'should default to click the middle' do
876
+ clicker.click
877
+ expect(@session).to have_text(/clicked at 150,150/)
878
+ end
879
+ end
880
+
881
+ context 'when w3c_click_offset is true' do
882
+ before do
883
+ Capybara.w3c_click_offset = true
884
+ end
885
+
886
+ it 'should offset from center of element' do
887
+ clicker.click(x: 10, y: 5)
888
+ expect(@session).to have_text(/clicked at 160,155/)
889
+ end
890
+
891
+ it 'should offset outside from center of element' do
892
+ clicker.click(x: -65, y: -60)
893
+ expect(@session).to have_text(/clicked at 85,90/)
894
+ end
895
+
896
+ it 'should default to click the middle' do
897
+ clicker.click
898
+ expect(@session).to have_text(/clicked at 150,150/)
899
+ end
900
+ end
901
+ end
902
+
903
+ context 'delay', requires: [:js] do
904
+ it 'should delay the mouse up' do
905
+ @session.visit('with_js')
906
+ @session.find(:css, '#click-test').click(delay: 2)
907
+ delay = @session.evaluate_script('window.click_delay')
908
+ expect(delay).to be >= 2
909
+ end
910
+ end
911
+ end
912
+
913
+ describe '#double_click', requires: [:js] do
914
+ it 'should double click an element' do
915
+ @session.visit('/with_js')
916
+ @session.find(:css, '#click-test').double_click
917
+ expect(@session.find(:css, '#has-been-double-clicked')).to be_truthy
918
+ end
919
+
920
+ it 'should allow modifiers', requires: [:js] do
921
+ @session.visit('/with_js')
922
+ @session.find(:css, '#click-test').double_click(:alt)
923
+ expect(@session).to have_link('Has been alt double clicked')
924
+ end
925
+
926
+ it 'should allow to adjust the offset', requires: [:js] do
927
+ Capybara.w3c_click_offset = false
928
+ @session.visit('with_js')
929
+ @session.find(:css, '#click-test').double_click(x: 10, y: 5)
930
+ link = @session.find(:link, 'has-been-double-clicked')
931
+ locations = link.text.match(/^Has been double clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
932
+ # Resulting click location should be very close to 10, 5 relative to top left corner of the element, but may not be exact due
933
+ # to integer/float conversions and rounding.
934
+ expect(locations[:x].to_f).to be_within(1).of(10)
935
+ expect(locations[:y].to_f).to be_within(1).of(5)
936
+ end
937
+
938
+ it 'should retry clicking', requires: [:js] do
939
+ @session.visit('/animated')
940
+ obscured = @session.find(:css, '#obscured')
941
+ @session.execute_script <<~JS
942
+ setTimeout(function(){ $('#cover').hide(); }, 700)
943
+ JS
944
+ expect { obscured.double_click }.not_to raise_error
945
+ end
946
+
947
+ context 'offset', requires: [:js] do
948
+ before do
949
+ @session.visit('/offset')
950
+ end
951
+
952
+ let :clicker do
953
+ @session.find(:id, 'clicker')
954
+ end
955
+
956
+ context 'when w3c_click_offset is false' do
957
+ before do
958
+ Capybara.w3c_click_offset = false
959
+ end
960
+
961
+ it 'should offset from top left of element' do
962
+ clicker.double_click(x: 10, y: 5)
963
+ expect(@session).to have_text(/clicked at 110,105/)
964
+ end
965
+
966
+ it 'should offset outside the element' do
967
+ clicker.double_click(x: -15, y: -10)
968
+ expect(@session).to have_text(/clicked at 85,90/)
969
+ end
970
+
971
+ it 'should default to click the middle' do
972
+ clicker.double_click
973
+ expect(@session).to have_text(/clicked at 150,150/)
974
+ end
975
+ end
976
+
977
+ context 'when w3c_click_offset is true' do
978
+ before do
979
+ Capybara.w3c_click_offset = true
980
+ end
981
+
982
+ it 'should offset from center of element' do
983
+ clicker.double_click(x: 10, y: 5)
984
+ expect(@session).to have_text(/clicked at 160,155/)
985
+ end
986
+
987
+ it 'should offset outside from center of element' do
988
+ clicker.double_click(x: -65, y: -60)
989
+ expect(@session).to have_text(/clicked at 85,90/)
990
+ end
991
+
992
+ it 'should default to click the middle' do
993
+ clicker.double_click
994
+ expect(@session).to have_text(/clicked at 150,150/)
995
+ end
996
+ end
997
+ end
998
+ end
999
+
1000
+ describe '#right_click', requires: [:js] do
1001
+ it 'should right click an element' do
1002
+ @session.visit('/with_js')
1003
+ @session.find(:css, '#click-test').right_click
1004
+ expect(@session.find(:css, '#has-been-right-clicked')).to be_truthy
1005
+ end
1006
+
1007
+ it 'should allow modifiers', requires: [:js] do
1008
+ @session.visit('/with_js')
1009
+ @session.find(:css, '#click-test').right_click(:meta)
1010
+ expect(@session).to have_link('Has been meta right clicked')
1011
+ end
1012
+
1013
+ it 'should allow to adjust the offset', requires: [:js] do
1014
+ Capybara.w3c_click_offset = false
1015
+ @session.visit('with_js')
1016
+ @session.find(:css, '#click-test').right_click(x: 10, y: 10)
1017
+ link = @session.find(:link, 'has-been-right-clicked')
1018
+ locations = link.text.match(/^Has been right clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
1019
+ # Resulting click location should be very close to 10, 10 relative to top left corner of the element, but may not be exact due
1020
+ # to integer/float conversions and rounding
1021
+ expect(locations[:x].to_f).to be_within(1).of(10)
1022
+ expect(locations[:y].to_f).to be_within(1).of(10)
1023
+ end
1024
+
1025
+ it 'should retry clicking', requires: [:js] do
1026
+ @session.visit('/animated')
1027
+ obscured = @session.find(:css, '#obscured')
1028
+ @session.execute_script <<~JS
1029
+ setTimeout(function(){ $('#cover').hide(); }, 700)
1030
+ JS
1031
+ expect { obscured.right_click }.not_to raise_error
1032
+ end
1033
+
1034
+ context 'offset', requires: [:js] do
1035
+ before do
1036
+ @session.visit('/offset')
1037
+ end
1038
+
1039
+ let :clicker do
1040
+ @session.find(:id, 'clicker')
1041
+ end
1042
+
1043
+ context 'when w3c_click_offset is false' do
1044
+ before do
1045
+ Capybara.w3c_click_offset = false
1046
+ end
1047
+
1048
+ it 'should offset from top left of element' do
1049
+ clicker.right_click(x: 10, y: 5)
1050
+ expect(@session).to have_text(/clicked at 110,105/)
1051
+ end
1052
+
1053
+ it 'should offset outside the element' do
1054
+ clicker.right_click(x: -15, y: -10)
1055
+ expect(@session).to have_text(/clicked at 85,90/)
1056
+ end
1057
+
1058
+ it 'should default to click the middle' do
1059
+ clicker.right_click
1060
+ expect(@session).to have_text(/clicked at 150,150/)
1061
+ end
1062
+ end
1063
+
1064
+ context 'when w3c_click_offset is true' do
1065
+ before do
1066
+ Capybara.w3c_click_offset = true
1067
+ end
1068
+
1069
+ it 'should offset from center of element' do
1070
+ clicker.right_click(x: 10, y: 5)
1071
+ expect(@session).to have_text(/clicked at 160,155/)
1072
+ end
1073
+
1074
+ it 'should offset outside from center of element' do
1075
+ clicker.right_click(x: -65, y: -60)
1076
+ expect(@session).to have_text(/clicked at 85,90/)
1077
+ end
1078
+
1079
+ it 'should default to click the middle' do
1080
+ clicker.right_click
1081
+ expect(@session).to have_text(/clicked at 150,150/)
1082
+ end
1083
+ end
1084
+ end
1085
+
1086
+ context 'delay', requires: [:js] do
1087
+ it 'should delay the mouse up' do
1088
+ @session.visit('with_js')
1089
+ @session.find(:css, '#click-test').right_click(delay: 2)
1090
+ delay = @session.evaluate_script('window.right_click_delay')
1091
+ expect(delay).to be >= 2
1092
+ end
1093
+ end
1094
+ end
1095
+
1096
+ describe '#send_keys', requires: [:send_keys] do
1097
+ it 'should send a string of keys to an element' do
1098
+ @session.visit('/form')
1099
+ @session.find(:css, '#address1_city').send_keys('Oceanside')
1100
+ expect(@session.find(:css, '#address1_city').value).to eq 'Oceanside'
1101
+ end
1102
+
1103
+ it 'should send special characters' do
1104
+ @session.visit('/form')
1105
+ @session.find(:css, '#address1_city').send_keys('Ocean', :space, 'sie', :left, 'd')
1106
+ expect(@session.find(:css, '#address1_city').value).to eq 'Ocean side'
1107
+ end
1108
+
1109
+ it 'should allow for multiple simultaneous keys' do
1110
+ @session.visit('/form')
1111
+ @session.find(:css, '#address1_city').send_keys([:shift, 'o'], 'ceanside')
1112
+ expect(@session.find(:css, '#address1_city').value).to eq 'Oceanside'
1113
+ end
1114
+
1115
+ it 'should hold modifiers at top level' do
1116
+ @session.visit('/form')
1117
+ @session.find(:css, '#address1_city').send_keys('ocean', :shift, 'side')
1118
+ expect(@session.find(:css, '#address1_city').value).to eq 'oceanSIDE'
1119
+ end
1120
+
1121
+ it 'should generate key events', requires: %i[send_keys js] do
1122
+ @session.visit('/with_js')
1123
+ @session.find(:css, '#with-key-events').send_keys([:shift, 't'], [:shift, 'w'])
1124
+ expect(@session.find(:css, '#key-events-output')).to have_text('keydown:16 keydown:84 keydown:16 keydown:87')
1125
+ end
1126
+ end
1127
+
1128
+ describe '#execute_script', requires: %i[js es_args] do
1129
+ it 'should execute the given script in the context of the element and return nothing' do
1130
+ @session.visit('/with_js')
1131
+ expect(@session.find(:css, '#change').execute_script("this.textContent = 'Funky Doodle'")).to be_nil
1132
+ expect(@session).to have_css('#change', text: 'Funky Doodle')
1133
+ end
1134
+
1135
+ it 'should pass arguments to the script' do
1136
+ @session.visit('/with_js')
1137
+ @session.find(:css, '#change').execute_script('this.textContent = arguments[0]', 'Doodle Funk')
1138
+ expect(@session).to have_css('#change', text: 'Doodle Funk')
1139
+ end
1140
+ end
1141
+
1142
+ describe '#evaluate_script', requires: %i[js es_args] do
1143
+ it 'should evaluate the given script in the context of the element and return whatever it produces' do
1144
+ @session.visit('/with_js')
1145
+ el = @session.find(:css, '#with_change_event')
1146
+ expect(el.evaluate_script('this.value')).to eq('default value')
1147
+ end
1148
+
1149
+ it 'should ignore leading whitespace' do
1150
+ @session.visit('/with_js')
1151
+ expect(@session.find(:css, '#change').evaluate_script('
1152
+ 2 + 3
1153
+ ')).to eq 5
1154
+ end
1155
+
1156
+ it 'should pass arguments to the script' do
1157
+ @session.visit('/with_js')
1158
+ @session.find(:css, '#change').evaluate_script('this.textContent = arguments[0]', 'Doodle Funk')
1159
+ expect(@session).to have_css('#change', text: 'Doodle Funk')
1160
+ end
1161
+
1162
+ it 'should pass multiple arguments' do
1163
+ @session.visit('/with_js')
1164
+ change = @session.find(:css, '#change')
1165
+ expect(change.evaluate_script('arguments[0] + arguments[1]', 2, 3)).to eq 5
1166
+ end
1167
+
1168
+ it 'should support returning elements' do
1169
+ @session.visit('/with_js')
1170
+ change = @session.find(:css, '#change') # ensure page has loaded and element is available
1171
+ el = change.evaluate_script('this')
1172
+ expect(el).to be_instance_of(Capybara::Node::Element)
1173
+ expect(el).to eq(change)
1174
+ end
1175
+
1176
+ it 'should support multiple statements via IIFE' do
1177
+ @session.visit('/with_js')
1178
+ change = @session.find(:css, '#change') # ensure page has loaded and element is available
1179
+ res = change.evaluate_script(<<~JS, 3)
1180
+ (function(n){
1181
+ var el = this;
1182
+ return [el, n];
1183
+ }).apply(this, arguments)
1184
+ JS
1185
+ expect(res).to eq [change, 3]
1186
+ end
1187
+ end
1188
+
1189
+ describe '#evaluate_async_script', requires: %i[js es_args] do
1190
+ it 'should evaluate the given script in the context of the element' do
1191
+ @session.visit('/with_js')
1192
+ el = @session.find(:css, '#with_change_event')
1193
+ expect(el.evaluate_async_script('arguments[0](this.value)')).to eq('default value')
1194
+ end
1195
+
1196
+ it 'should support returning elements after asynchronous operation' do
1197
+ @session.visit('/with_js')
1198
+ change = @session.find(:css, '#change') # ensure page has loaded and element is available
1199
+ el = change.evaluate_async_script('var cb = arguments[0]; setTimeout(function(el){ cb(el) }, 100, this)')
1200
+ expect(el).to eq(change)
1201
+ end
1202
+ end
1203
+
1204
+ describe '#shadow_root', requires: %i[js] do
1205
+ it 'should get the shadow root' do
1206
+ @session.visit('/with_shadow')
1207
+ expect do
1208
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1209
+ expect(shadow_root).to be_a(Capybara::Node::Element)
1210
+ end.not_to raise_error
1211
+ end
1212
+
1213
+ it 'should find elements inside the shadow dom using CSS' do
1214
+ @session.visit('/with_shadow')
1215
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1216
+ expect(shadow_root).to have_css('#shadow_content', text: 'some text')
1217
+ end
1218
+
1219
+ it 'should find nested shadow roots' do
1220
+ @session.visit('/with_shadow')
1221
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1222
+ nested_shadow_root = shadow_root.find(:css, '#nested_shadow_host').shadow_root
1223
+ expect(nested_shadow_root).to have_css('#nested_shadow_content', text: 'nested text')
1224
+ end
1225
+
1226
+ it 'should click on elements' do
1227
+ @session.visit('/with_shadow')
1228
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1229
+ checkbox = shadow_root.find(:css, 'input[type="checkbox"]')
1230
+ expect(checkbox).not_to be_checked
1231
+ checkbox.click
1232
+ expect(checkbox).to be_checked
1233
+ end
1234
+
1235
+ it 'should use convenience methods once moved to a descendant of the shadow root' do
1236
+ @session.visit('/with_shadow')
1237
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1238
+ descendant = shadow_root.find(:css, '#controls_wrapper')
1239
+ expect do
1240
+ descendant.check('shadow_checkbox')
1241
+ end.not_to raise_error
1242
+ expect(descendant).to have_checked_field('shadow_checkbox')
1243
+ end
1244
+
1245
+ it 'should produce error messages when failing' do
1246
+ @session.visit('/with_shadow')
1247
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1248
+ expect do
1249
+ expect(shadow_root).to have_css('#shadow_content', text: 'Not in the document')
1250
+ end.to raise_error(/tag="ShadowRoot"/)
1251
+ end
1252
+
1253
+ it 'should get visible text' do
1254
+ @session.visit('/with_shadow')
1255
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1256
+ expect(shadow_root).to have_text('some text scroll.html')
1257
+ end
1258
+
1259
+ it 'should get all text' do
1260
+ @session.visit('/with_shadow')
1261
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1262
+ expect(shadow_root).to have_text(:all, 'some text scroll.html')
1263
+ end
1264
+ end
1265
+
1266
+ describe '#reload', requires: [:js] do
1267
+ it 'should reload elements found via ancestor with CSS' do
1268
+ @session.visit('/with_js')
1269
+ node = @session.find(:css, '#reload-me em').ancestor(:css, 'div')
1270
+ node.reload
1271
+ expect(node[:id]).to eq 'reload-me'
1272
+ end
1273
+
1274
+ it 'should reload elements found via ancestor with XPath' do
1275
+ @session.visit('/with_js')
1276
+ node = @session.find(:css, '#reload-me em').ancestor(:xpath, './/div')
1277
+ node.reload
1278
+ expect(node[:id]).to eq 'reload-me'
1279
+ end
1280
+
1281
+ it 'should reload elements found via sibling' do
1282
+ @session.visit('/with_js')
1283
+ node = @session.find(:css, '#the-list li', text: 'Item 1').sibling(:css, 'li')
1284
+ expect(node.text).to eq 'Item 2'
1285
+ node.reload
1286
+ expect(node.text).to eq 'Item 2'
1287
+ end
1288
+
1289
+ context 'without automatic reload' do
1290
+ before { Capybara.automatic_reload = false }
1291
+
1292
+ after { Capybara.automatic_reload = true }
1293
+
1294
+ it 'should reload the current context of the node' do
1295
+ @session.visit('/with_js')
1296
+ node = @session.find(:css, '#reload-me')
1297
+ @session.click_link('Reload!')
1298
+ sleep(0.3)
1299
+ expect(node.reload.text).to eq('has been reloaded')
1300
+ expect(node.text).to eq('has been reloaded')
1301
+ end
1302
+
1303
+ it 'should reload a parent node' do
1304
+ @session.visit('/with_js')
1305
+ node = @session.find(:css, '#reload-me').find(:css, 'em')
1306
+ @session.click_link('Reload!')
1307
+ sleep(0.3)
1308
+ expect(node.reload.text).to eq('has been reloaded')
1309
+ expect(node.text).to eq('has been reloaded')
1310
+ end
1311
+
1312
+ it 'should not automatically reload' do
1313
+ @session.visit('/with_js')
1314
+ node = @session.find(:css, '#reload-me')
1315
+ @session.click_link('Reload!')
1316
+ sleep(0.3)
1317
+ expect do
1318
+ expect(node).to have_text('has been reloaded')
1319
+ end.to(raise_error do |error|
1320
+ expect(error).to be_an_invalid_element_error(@session)
1321
+ end)
1322
+ end
1323
+ end
1324
+
1325
+ context 'with automatic reload' do
1326
+ before do
1327
+ Capybara.default_max_wait_time = 4
1328
+ end
1329
+
1330
+ it 'should reload the current context of the node automatically' do
1331
+ @session.visit('/with_js')
1332
+ node = @session.find(:css, '#reload-me')
1333
+ @session.click_link('Reload!')
1334
+ sleep(1)
1335
+ expect(node.text).to eq('has been reloaded')
1336
+ end
1337
+
1338
+ it 'should reload a parent node automatically' do
1339
+ @session.visit('/with_js')
1340
+ node = @session.find(:css, '#reload-me').find(:css, 'em')
1341
+ @session.click_link('Reload!')
1342
+ sleep(1)
1343
+ expect(node.text).to eq('has been reloaded')
1344
+ end
1345
+
1346
+ it 'should reload a node automatically when using find' do
1347
+ @session.visit('/with_js')
1348
+ node = @session.find(:css, '#reload-me')
1349
+ @session.click_link('Reload!')
1350
+ sleep(1)
1351
+ expect(node.find(:css, 'a').text).to eq('has been reloaded')
1352
+ end
1353
+
1354
+ it "should not reload nodes which haven't been found with reevaluateable queries" do
1355
+ @session.visit('/with_js')
1356
+ node = @session.all(:css, '#the-list li')[1]
1357
+ @session.click_link('Fetch new list!')
1358
+ sleep(1)
1359
+
1360
+ expect do
1361
+ expect(node).to have_text('Foo')
1362
+ end.to(raise_error { |error| expect(error).to be_an_invalid_element_error(@session) })
1363
+ expect do
1364
+ expect(node).to have_text('Bar')
1365
+ end.to(raise_error { |error| expect(error).to be_an_invalid_element_error(@session) })
1366
+ end
1367
+
1368
+ it 'should reload nodes with options' do
1369
+ @session.visit('/with_js')
1370
+ node = @session.find(:css, 'em', text: 'reloaded')
1371
+ @session.click_link('Reload!')
1372
+ sleep(1)
1373
+ expect(node.text).to eq('has been reloaded')
1374
+ end
1375
+ end
1376
+ end
1377
+
1378
+ context 'when #synchronize raises server errors' do
1379
+ it 'sets an explanatory exception as the cause of server exceptions', requires: %i[server js] do
1380
+ quietly { @session.visit('/error') }
1381
+ expect do
1382
+ @session.find(:css, 'span')
1383
+ end.to(raise_error(TestApp::TestAppError) do |e|
1384
+ expect(e.cause).to be_a Capybara::CapybaraError
1385
+ expect(e.cause.message).to match(/Your application server raised an error/)
1386
+ end)
1387
+ end
1388
+
1389
+ it 'sets an explanatory exception as the cause of server exceptions with errors with initializers', requires: %i[server js] do
1390
+ quietly { @session.visit('/other_error') }
1391
+ expect do
1392
+ @session.find(:css, 'span')
1393
+ end.to(raise_error(TestApp::TestAppOtherError) do |e|
1394
+ expect(e.cause).to be_a Capybara::CapybaraError
1395
+ expect(e.cause.message).to match(/Your application server raised an error/)
1396
+ end)
1397
+ end
1398
+ end
1399
+ end