capybara 2.15.1 → 3.36.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (311) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +1 -1
  3. data/History.md +902 -10
  4. data/License.txt +1 -1
  5. data/README.md +103 -75
  6. data/lib/capybara/config.rb +29 -56
  7. data/lib/capybara/cucumber.rb +2 -3
  8. data/lib/capybara/driver/base.rb +39 -18
  9. data/lib/capybara/driver/node.rb +36 -10
  10. data/lib/capybara/dsl.rb +15 -6
  11. data/lib/capybara/helpers.rb +65 -30
  12. data/lib/capybara/minitest/spec.rb +173 -81
  13. data/lib/capybara/minitest.rb +220 -111
  14. data/lib/capybara/node/actions.rb +274 -171
  15. data/lib/capybara/node/base.rb +41 -34
  16. data/lib/capybara/node/document.rb +15 -3
  17. data/lib/capybara/node/document_matchers.rb +19 -21
  18. data/lib/capybara/node/element.rb +353 -137
  19. data/lib/capybara/node/finders.rb +144 -138
  20. data/lib/capybara/node/matchers.rb +369 -209
  21. data/lib/capybara/node/simple.rb +59 -26
  22. data/lib/capybara/queries/active_element_query.rb +18 -0
  23. data/lib/capybara/queries/ancestor_query.rb +13 -10
  24. data/lib/capybara/queries/base_query.rb +39 -28
  25. data/lib/capybara/queries/current_path_query.rb +22 -25
  26. data/lib/capybara/queries/match_query.rb +14 -7
  27. data/lib/capybara/queries/selector_query.rb +646 -145
  28. data/lib/capybara/queries/sibling_query.rb +12 -10
  29. data/lib/capybara/queries/style_query.rb +45 -0
  30. data/lib/capybara/queries/text_query.rb +56 -38
  31. data/lib/capybara/queries/title_query.rb +8 -11
  32. data/lib/capybara/rack_test/browser.rb +57 -41
  33. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  34. data/lib/capybara/rack_test/driver.rb +18 -13
  35. data/lib/capybara/rack_test/errors.rb +6 -0
  36. data/lib/capybara/rack_test/form.rb +73 -58
  37. data/lib/capybara/rack_test/node.rb +188 -81
  38. data/lib/capybara/rails.rb +3 -7
  39. data/lib/capybara/registration_container.rb +44 -0
  40. data/lib/capybara/registrations/drivers.rb +42 -0
  41. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  42. data/lib/capybara/registrations/servers.rb +45 -0
  43. data/lib/capybara/result.rb +96 -62
  44. data/lib/capybara/rspec/features.rb +17 -50
  45. data/lib/capybara/rspec/matcher_proxies.rb +52 -15
  46. data/lib/capybara/rspec/matchers/base.rb +111 -0
  47. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  48. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  49. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  50. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  51. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  52. data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
  53. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  54. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  55. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  56. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  57. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  58. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  59. data/lib/capybara/rspec/matchers.rb +144 -264
  60. data/lib/capybara/rspec.rb +7 -11
  61. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  62. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  63. data/lib/capybara/selector/css.rb +89 -17
  64. data/lib/capybara/selector/definition/button.rb +68 -0
  65. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  66. data/lib/capybara/selector/definition/css.rb +10 -0
  67. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  68. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  69. data/lib/capybara/selector/definition/element.rb +28 -0
  70. data/lib/capybara/selector/definition/field.rb +40 -0
  71. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  72. data/lib/capybara/selector/definition/file_field.rb +13 -0
  73. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  74. data/lib/capybara/selector/definition/frame.rb +17 -0
  75. data/lib/capybara/selector/definition/id.rb +6 -0
  76. data/lib/capybara/selector/definition/label.rb +62 -0
  77. data/lib/capybara/selector/definition/link.rb +54 -0
  78. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  79. data/lib/capybara/selector/definition/option.rb +27 -0
  80. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  81. data/lib/capybara/selector/definition/select.rb +81 -0
  82. data/lib/capybara/selector/definition/table.rb +109 -0
  83. data/lib/capybara/selector/definition/table_row.rb +21 -0
  84. data/lib/capybara/selector/definition/xpath.rb +5 -0
  85. data/lib/capybara/selector/definition.rb +279 -0
  86. data/lib/capybara/selector/filter.rb +2 -17
  87. data/lib/capybara/selector/filter_set.rb +81 -33
  88. data/lib/capybara/selector/filters/base.rb +50 -6
  89. data/lib/capybara/selector/filters/expression_filter.rb +8 -26
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +16 -12
  92. data/lib/capybara/selector/regexp_disassembler.rb +214 -0
  93. data/lib/capybara/selector/selector.rb +89 -210
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/lib/capybara/selector.rb +227 -526
  96. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  97. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  98. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  99. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  100. data/lib/capybara/selenium/driver.rb +343 -276
  101. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  102. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
  103. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
  104. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  105. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  106. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  107. data/lib/capybara/selenium/extensions/find.rb +110 -0
  108. data/lib/capybara/selenium/extensions/html5_drag.rb +228 -0
  109. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  110. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  111. data/lib/capybara/selenium/logger_suppressor.rb +40 -0
  112. data/lib/capybara/selenium/node.rb +508 -124
  113. data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
  114. data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
  115. data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  116. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  117. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  118. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  119. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  120. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  121. data/lib/capybara/selenium/patches/logs.rb +45 -0
  122. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  123. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  124. data/lib/capybara/server/animation_disabler.rb +69 -0
  125. data/lib/capybara/server/checker.rb +44 -0
  126. data/lib/capybara/server/middleware.rb +71 -0
  127. data/lib/capybara/server.rb +59 -67
  128. data/lib/capybara/session/config.rb +79 -59
  129. data/lib/capybara/session/matchers.rb +41 -25
  130. data/lib/capybara/session.rb +371 -357
  131. data/lib/capybara/spec/public/jquery.js +5 -5
  132. data/lib/capybara/spec/public/offset.js +6 -0
  133. data/lib/capybara/spec/public/test.js +159 -13
  134. data/lib/capybara/spec/session/accept_alert_spec.rb +12 -11
  135. data/lib/capybara/spec/session/accept_confirm_spec.rb +6 -5
  136. data/lib/capybara/spec/session/accept_prompt_spec.rb +34 -6
  137. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  138. data/lib/capybara/spec/session/all_spec.rb +161 -55
  139. data/lib/capybara/spec/session/ancestor_spec.rb +27 -24
  140. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +68 -38
  141. data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
  142. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  143. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  144. data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +91 -59
  145. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +22 -12
  146. data/lib/capybara/spec/session/attach_file_spec.rb +138 -69
  147. data/lib/capybara/spec/session/body_spec.rb +12 -13
  148. data/lib/capybara/spec/session/check_spec.rb +116 -55
  149. data/lib/capybara/spec/session/choose_spec.rb +64 -31
  150. data/lib/capybara/spec/session/click_button_spec.rb +231 -173
  151. data/lib/capybara/spec/session/click_link_or_button_spec.rb +55 -35
  152. data/lib/capybara/spec/session/click_link_spec.rb +82 -58
  153. data/lib/capybara/spec/session/current_scope_spec.rb +11 -10
  154. data/lib/capybara/spec/session/current_url_spec.rb +57 -39
  155. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +4 -4
  156. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +3 -2
  157. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
  158. data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
  159. data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
  160. data/lib/capybara/spec/session/element/matches_selector_spec.rb +71 -57
  161. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
  162. data/lib/capybara/spec/session/evaluate_script_spec.rb +30 -9
  163. data/lib/capybara/spec/session/execute_script_spec.rb +10 -8
  164. data/lib/capybara/spec/session/fill_in_spec.rb +128 -43
  165. data/lib/capybara/spec/session/find_button_spec.rb +25 -24
  166. data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
  167. data/lib/capybara/spec/session/find_field_spec.rb +37 -41
  168. data/lib/capybara/spec/session/find_link_spec.rb +36 -17
  169. data/lib/capybara/spec/session/find_spec.rb +245 -144
  170. data/lib/capybara/spec/session/first_spec.rb +79 -51
  171. data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
  172. data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  173. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +33 -20
  174. data/lib/capybara/spec/session/frame/within_frame_spec.rb +50 -32
  175. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  176. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  177. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  178. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  179. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  180. data/lib/capybara/spec/session/has_button_spec.rb +94 -13
  181. data/lib/capybara/spec/session/has_css_spec.rb +272 -137
  182. data/lib/capybara/spec/session/has_current_path_spec.rb +87 -45
  183. data/lib/capybara/spec/session/has_field_spec.rb +139 -59
  184. data/lib/capybara/spec/session/has_link_spec.rb +34 -9
  185. data/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
  186. data/lib/capybara/spec/session/has_select_spec.rb +103 -74
  187. data/lib/capybara/spec/session/has_selector_spec.rb +105 -71
  188. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  189. data/lib/capybara/spec/session/has_table_spec.rb +172 -5
  190. data/lib/capybara/spec/session/has_text_spec.rb +113 -61
  191. data/lib/capybara/spec/session/has_title_spec.rb +20 -14
  192. data/lib/capybara/spec/session/has_xpath_spec.rb +57 -38
  193. data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
  194. data/lib/capybara/spec/session/html_spec.rb +14 -6
  195. data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
  196. data/lib/capybara/spec/session/node_spec.rb +950 -152
  197. data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
  198. data/lib/capybara/spec/session/refresh_spec.rb +12 -6
  199. data/lib/capybara/spec/session/reset_session_spec.rb +69 -35
  200. data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
  201. data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
  202. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +8 -12
  203. data/lib/capybara/spec/session/save_page_spec.rb +42 -55
  204. data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
  205. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  206. data/lib/capybara/spec/session/scroll_spec.rb +117 -0
  207. data/lib/capybara/spec/session/select_spec.rb +107 -80
  208. data/lib/capybara/spec/session/selectors_spec.rb +52 -19
  209. data/lib/capybara/spec/session/sibling_spec.rb +10 -10
  210. data/lib/capybara/spec/session/text_spec.rb +37 -21
  211. data/lib/capybara/spec/session/title_spec.rb +17 -5
  212. data/lib/capybara/spec/session/uncheck_spec.rb +42 -22
  213. data/lib/capybara/spec/session/unselect_spec.rb +39 -38
  214. data/lib/capybara/spec/session/visit_spec.rb +99 -32
  215. data/lib/capybara/spec/session/window/become_closed_spec.rb +24 -20
  216. data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
  217. data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
  218. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +27 -22
  219. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +12 -6
  220. data/lib/capybara/spec/session/window/window_spec.rb +97 -63
  221. data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
  222. data/lib/capybara/spec/session/window/within_window_spec.rb +31 -86
  223. data/lib/capybara/spec/session/within_spec.rb +70 -44
  224. data/lib/capybara/spec/spec_helper.rb +49 -43
  225. data/lib/capybara/spec/test_app.rb +89 -42
  226. data/lib/capybara/spec/views/animated.erb +49 -0
  227. data/lib/capybara/spec/views/form.erb +141 -42
  228. data/lib/capybara/spec/views/frame_child.erb +4 -3
  229. data/lib/capybara/spec/views/frame_one.erb +2 -1
  230. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  231. data/lib/capybara/spec/views/frame_two.erb +1 -1
  232. data/lib/capybara/spec/views/initial_alert.erb +11 -0
  233. data/lib/capybara/spec/views/layout.erb +10 -0
  234. data/lib/capybara/spec/views/obscured.erb +47 -0
  235. data/lib/capybara/spec/views/offset.erb +33 -0
  236. data/lib/capybara/spec/views/path.erb +2 -2
  237. data/lib/capybara/spec/views/popup_one.erb +1 -1
  238. data/lib/capybara/spec/views/popup_two.erb +1 -1
  239. data/lib/capybara/spec/views/react.erb +45 -0
  240. data/lib/capybara/spec/views/scroll.erb +21 -0
  241. data/lib/capybara/spec/views/spatial.erb +31 -0
  242. data/lib/capybara/spec/views/tables.erb +68 -1
  243. data/lib/capybara/spec/views/with_animation.erb +81 -0
  244. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  245. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  246. data/lib/capybara/spec/views/with_fixed_header_footer.erb +18 -0
  247. data/lib/capybara/spec/views/with_hover.erb +8 -2
  248. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  249. data/lib/capybara/spec/views/with_html.erb +70 -11
  250. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  251. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  252. data/lib/capybara/spec/views/with_js.erb +39 -3
  253. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  254. data/lib/capybara/spec/views/with_namespace.erb +21 -0
  255. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  256. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  257. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  258. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  259. data/lib/capybara/spec/views/with_windows.erb +1 -1
  260. data/lib/capybara/spec/views/within_frames.erb +5 -2
  261. data/lib/capybara/version.rb +2 -1
  262. data/lib/capybara/window.rb +35 -33
  263. data/lib/capybara.rb +126 -103
  264. data/spec/basic_node_spec.rb +60 -34
  265. data/spec/capybara_spec.rb +53 -104
  266. data/spec/css_builder_spec.rb +101 -0
  267. data/spec/css_splitter_spec.rb +38 -0
  268. data/spec/dsl_spec.rb +81 -62
  269. data/spec/filter_set_spec.rb +27 -9
  270. data/spec/fixtures/certificate.pem +25 -0
  271. data/spec/fixtures/key.pem +27 -0
  272. data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -4
  273. data/spec/fixtures/selenium_driver_rspec_success.rb +5 -4
  274. data/spec/minitest_spec.rb +49 -7
  275. data/spec/minitest_spec_spec.rb +94 -59
  276. data/spec/per_session_config_spec.rb +14 -13
  277. data/spec/rack_test_spec.rb +180 -125
  278. data/spec/regexp_dissassembler_spec.rb +250 -0
  279. data/spec/result_spec.rb +99 -45
  280. data/spec/rspec/features_spec.rb +37 -31
  281. data/spec/rspec/scenarios_spec.rb +9 -7
  282. data/spec/rspec/shared_spec_matchers.rb +448 -421
  283. data/spec/rspec/views_spec.rb +5 -3
  284. data/spec/rspec_matchers_spec.rb +27 -11
  285. data/spec/rspec_spec.rb +109 -89
  286. data/spec/sauce_spec_chrome.rb +43 -0
  287. data/spec/selector_spec.rb +396 -67
  288. data/spec/selenium_spec_chrome.rb +183 -35
  289. data/spec/selenium_spec_chrome_remote.rb +101 -0
  290. data/spec/selenium_spec_edge.rb +47 -0
  291. data/spec/selenium_spec_firefox.rb +184 -41
  292. data/spec/selenium_spec_firefox_remote.rb +80 -0
  293. data/spec/selenium_spec_ie.rb +147 -0
  294. data/spec/selenium_spec_safari.rb +156 -0
  295. data/spec/server_spec.rb +198 -99
  296. data/spec/session_spec.rb +53 -16
  297. data/spec/shared_selenium_node.rb +79 -0
  298. data/spec/shared_selenium_session.rb +489 -97
  299. data/spec/spec_helper.rb +93 -7
  300. data/spec/xpath_builder_spec.rb +93 -0
  301. metadata +365 -70
  302. data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
  303. data/.yard/templates_custom/default/class/html/setup.rb +0 -17
  304. data/.yard/yard_extensions.rb +0 -78
  305. data/lib/capybara/query.rb +0 -7
  306. data/lib/capybara/rspec/compound.rb +0 -95
  307. data/lib/capybara/spec/session/assert_current_path.rb +0 -72
  308. data/lib/capybara/spec/session/assert_selector.rb +0 -148
  309. data/lib/capybara/spec/session/source_spec.rb +0 -0
  310. data/lib/capybara/spec/views/with_title.erb +0 -5
  311. data/spec/selenium_spec_marionette.rb +0 -117
@@ -1,542 +1,243 @@
1
1
  # frozen_string_literal: true
2
- require 'capybara/selector/selector'
3
- Capybara::Selector::FilterSet.add(:_field) do
4
- filter(:checked, :boolean) { |node, value| not(value ^ node.checked?) }
5
- filter(:unchecked, :boolean) { |node, value| (value ^ node.checked?) }
6
- filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
7
- filter(:multiple, :boolean) { |node, value| !(value ^ node.multiple?) }
8
-
9
- expression_filter(:name) { |xpath, val| xpath[XPath.attr(:name).equals(val)] }
10
- expression_filter(:placeholder) { |xpath, val| xpath[XPath.attr(:placeholder).equals(val)] }
11
-
12
- describe do |options|
13
- desc, states = String.new, []
14
- states << 'checked' if options[:checked] || (options[:unchecked] == false)
15
- states << 'not checked' if options[:unchecked] || (options[:checked] == false)
16
- states << 'disabled' if options[:disabled] == true
17
- states << 'not disabled' if options[:disabled] == false
18
- desc << " that is #{states.join(' and ')}" unless states.empty?
19
- desc << " with the multiple attribute" if options[:multiple] == true
20
- desc << " without the multiple attribute" if options[:multiple] == false
21
- desc
22
- end
23
- end
24
-
25
- ##
26
- #
27
- # Select elements by XPath expression
28
- #
29
- # @locator An XPath expression
30
- #
31
- Capybara.add_selector(:xpath) do
32
- xpath { |xpath| xpath }
33
- end
34
-
35
- ##
36
- #
37
- # Select elements by CSS selector
38
- #
39
- # @locator A CSS selector
40
- #
41
- Capybara.add_selector(:css) do
42
- css { |css| css }
43
- end
44
-
45
- ##
46
- #
47
- # Select element by id
48
- #
49
- # @locator The id of the element to match
50
- #
51
- Capybara.add_selector(:id) do
52
- xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
53
- end
54
-
55
- ##
56
- #
57
- # Select field elements (input [not of type submit, image, or hidden], textarea, select)
58
- #
59
- # @locator Matches against the id, name, or placeholder
60
- # @filter [String] :id Matches the id attribute
61
- # @filter [String] :name Matches the name attribute
62
- # @filter [String] :placeholder Matches the placeholder attribute
63
- # @filter [String] :type Matches the type attribute of the field or element type for 'textarea' and 'select'
64
- # @filter [Boolean] :readonly
65
- # @filter [String] :with Matches the current value of the field
66
- # @filter [String, Array<String>] :class Matches the class(es) provided
67
- # @filter [Boolean] :checked Match checked fields?
68
- # @filter [Boolean] :unchecked Match unchecked fields?
69
- # @filter [Boolean] :disabled Match disabled field?
70
- # @filter [Boolean] :multiple Match fields that accept multiple values
71
- Capybara.add_selector(:field) do
72
- xpath do |locator, options|
73
- xpath = XPath.descendant(:input, :textarea, :select)[~XPath.attr(:type).one_of('submit', 'image', 'hidden')]
74
- locate_field(xpath, locator, options)
75
- end
76
-
77
- expression_filter(:type) do |expr, type|
78
- type = type.to_s
79
- if ['textarea', 'select'].include?(type)
80
- expr.axis(:self, type.to_sym)
81
- else
82
- expr[XPath.attr(:type).equals(type)]
83
- end
84
- end
85
-
86
- filter_set(:_field) # checked/unchecked/disabled/multiple/name/placeholder
87
-
88
- filter(:readonly, :boolean) { |node, value| not(value ^ node.readonly?) }
89
- filter(:with) do |node, with|
90
- with.is_a?(Regexp) ? node.value =~ with : node.value == with.to_s
91
- end
92
- describe do |options|
93
- desc = String.new
94
- (expression_filters.keys - [:type]).each { |ef| desc << " with #{ef} #{options[ef]}" if options.has_key?(ef) }
95
- desc << " of type #{options[:type].inspect}" if options[:type]
96
- desc << " with value #{options[:with].to_s.inspect}" if options.has_key?(:with)
97
- desc
98
- end
99
- end
100
-
101
- ##
102
- #
103
- # Select fieldset elements
104
- #
105
- # @locator Matches id or contents of wrapped legend
106
- #
107
- # @filter [String] :id Matches id attribute
108
- # @filter [String] :legend Matches contents of wrapped legend
109
- # @filter [String, Array<String>] :class Matches the class(es) provided
110
- #
111
- Capybara.add_selector(:fieldset) do
112
- xpath(:legend) do |locator, options|
113
- xpath = XPath.descendant(:fieldset)
114
- xpath = xpath[XPath.attr(:id).equals(locator.to_s).or XPath.child(:legend)[XPath.string.n.is(locator.to_s)]] unless locator.nil?
115
- xpath = xpath[XPath.child(:legend)[XPath.string.n.is(options[:legend])]] if options[:legend]
116
- xpath
117
- end
118
- end
119
-
120
- ##
121
- #
122
- # Find links ( <a> elements with an href attribute )
123
- #
124
- # @locator Matches the id or title attributes, or the string content of the link, or the alt attribute of a contained img element
125
- #
126
- # @filter [String] :id Matches the id attribute
127
- # @filter [String] :title Matches the title attribute
128
- # @filter [String] :alt Matches the alt attribute of a contained img element
129
- # @filter [String] :class Matches the class(es) provided
130
- # @filter [String, Regexp,nil] :href Matches the normalized href of the link, if nil will find <a> elements with no href attribute
131
- #
132
- Capybara.add_selector(:link) do
133
- xpath(:title, :alt) do |locator, options={}|
134
- xpath = XPath.descendant(:a)
135
- xpath = if options.fetch(:href, true).nil?
136
- xpath[~XPath.attr(:href)]
137
- else
138
- xpath[XPath.attr(:href)]
139
- end
140
- unless locator.nil?
141
- locator = locator.to_s
142
- matchers = XPath.attr(:id).equals(locator).or(
143
- XPath.string.n.is(locator)).or(
144
- XPath.attr(:title).is(locator)).or(
145
- XPath.descendant(:img)[XPath.attr(:alt).is(locator)])
146
- matchers = matchers.or XPath.attr(:'aria-label').is(locator) if options[:enable_aria_label]
147
- xpath = xpath[matchers]
148
- end
149
- xpath = [:title].inject(xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
150
- xpath = xpath[XPath.descendant(:img)[XPath.attr(:alt).equals(options[:alt])]] if options[:alt]
151
- xpath
152
- end
153
-
154
- filter(:href) do |node, href|
155
- case href
156
- when nil
157
- true
158
- when Regexp
159
- node[:href].match href
160
- else
161
- node.first(:xpath, XPath.axis(:self)[XPath.attr(:href).equals(href.to_s)], minimum: 0)
162
- end
163
- end
164
-
165
- describe do |options|
166
- desc = String.new()
167
- desc << " with href #{options[:href].inspect}" if options[:href]
168
- desc << " with no href attribute" if options.fetch(:href, true).nil?
169
- end
170
- end
171
-
172
- ##
173
- #
174
- # Find buttons ( input [of type submit, reset, image, button] or button elements )
175
- #
176
- # @locator Matches the id, value, or title attributes, string content of a button, or the alt attribute of an image type button or of a descendant image of a button
177
- #
178
- # @filter [String] :id Matches the id attribute
179
- # @filter [String] :title Matches the title attribute
180
- # @filter [String] :class Matches the class(es) provided
181
- # @filter [String] :value Matches the value of an input button
182
- #
183
- Capybara.add_selector(:button) do
184
- xpath(:value, :title) do |locator, options={}|
185
- input_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).one_of('submit', 'reset', 'image', 'button')]
186
- btn_xpath = XPath.descendant(:button)
187
- image_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).equals('image')]
188
-
189
- unless locator.nil?
190
- locator = locator.to_s
191
- locator_matches = XPath.attr(:id).equals(locator).or XPath.attr(:value).is(locator).or XPath.attr(:title).is(locator)
192
- locator_matches = locator_matches.or XPath.attr(:'aria-label').is(locator) if options[:enable_aria_label]
193
-
194
- input_btn_xpath = input_btn_xpath[locator_matches]
195
-
196
- btn_xpath = btn_xpath[locator_matches.or XPath.string.n.is(locator).or XPath.descendant(:img)[XPath.attr(:alt).is(locator)]]
197
-
198
- alt_matches = XPath.attr(:alt).is(locator)
199
- alt_matches = alt_matches.or XPath.attr(:'aria-label').is(locator) if options[:enable_aria_label]
200
- image_btn_xpath = image_btn_xpath[alt_matches]
201
- end
202
-
203
- res_xpath = input_btn_xpath.union(btn_xpath).union(image_btn_xpath)
204
2
 
205
- res_xpath = expression_filters.keys.inject(res_xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
206
-
207
- res_xpath
208
- end
209
-
210
- filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
211
-
212
- describe do |options|
213
- desc = String.new
214
- desc << " that is disabled" if options[:disabled] == true
215
- desc << describe_all_expression_filters(options)
216
- desc
217
- end
218
- end
219
-
220
- ##
221
- #
222
- # Find links or buttons
223
- #
224
- Capybara.add_selector(:link_or_button) do
225
- label "link or button"
226
- xpath do |locator, options|
227
- self.class.all.values_at(:link, :button).map {|selector| selector.xpath.call(locator, options)}.reduce(:union)
228
- end
229
-
230
- filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| node.tag_name == "a" or not(value ^ node.disabled?) }
231
-
232
- describe { |options| " that is disabled" if options[:disabled] }
233
- end
234
-
235
- ##
236
- #
237
- # Find text fillable fields ( textarea, input [not of type submit, image, radio, checkbox, hidden, file] )
238
- #
239
- # @locator Matches against the id, name, or placeholder
240
- # @filter [String] :id Matches the id attribute
241
- # @filter [String] :name Matches the name attribute
242
- # @filter [String] :placeholder Matches the placeholder attribute
243
- # @filter [String] :with Matches the current value of the field
244
- # @filter [String] :type Matches the type attribute of the field or element type for 'textarea'
245
- # @filter [String, Array<String>] :class Matches the class(es) provided
246
- # @filter [Boolean] :disabled Match disabled field?
247
- # @filter [Boolean] :multiple Match fields that accept multiple values
248
- #
249
- Capybara.add_selector(:fillable_field) do
250
- label "field"
251
- xpath do |locator, options|
252
- xpath = XPath.descendant(:input, :textarea)[~XPath.attr(:type).one_of('submit', 'image', 'radio', 'checkbox', 'hidden', 'file')]
253
- locate_field(xpath, locator, options)
254
- end
255
-
256
- expression_filter(:type) do |expr, type|
257
- type = type.to_s
258
- if ['textarea'].include?(type)
259
- expr.axis(:self, type.to_sym)
260
- else
261
- expr[XPath.attr(:type).equals(type)]
262
- end
263
- end
264
-
265
- filter_set(:_field, [:disabled, :multiple, :name, :placeholder])
266
-
267
- filter(:with) do |node, with|
268
- with.is_a?(Regexp) ? node.value =~ with : node.value == with.to_s
269
- end
270
-
271
- describe do |options|
272
- desc = String.new
273
- desc << describe_all_expression_filters(options)
274
- desc << " with value #{options[:with].to_s.inspect}" if options.has_key?(:with)
275
- desc
276
- end
277
- end
278
-
279
- ##
280
- #
281
- # Find radio buttons
282
- #
283
- # @locator Match id, name, or associated label text
284
- # @filter [String] :id Matches the id attribute
285
- # @filter [String] :name Matches the name attribute
286
- # @filter [String, Array<String>] :class Matches the class(es) provided
287
- # @filter [Boolean] :checked Match checked fields?
288
- # @filter [Boolean] :unchecked Match unchecked fields?
289
- # @filter [Boolean] :disabled Match disabled field?
290
- # @filter [String] :option Match the value
291
- #
292
- Capybara.add_selector(:radio_button) do
293
- label "radio button"
294
- xpath do |locator, options|
295
- xpath = XPath.descendant(:input)[XPath.attr(:type).equals('radio')]
296
- locate_field(xpath, locator, options)
297
- end
298
-
299
- filter_set(:_field, [:checked, :unchecked, :disabled, :name])
300
-
301
- filter(:option) { |node, value| node.value == value.to_s }
302
-
303
- describe do |options|
304
- desc = String.new
305
- desc << " with value #{options[:option].inspect}" if options[:option]
306
- desc << describe_all_expression_filters(options)
307
- desc
308
- end
309
- end
310
-
311
- ##
312
- #
313
- # Find checkboxes
314
- #
315
- # @locator Match id, name, or associated label text
316
- # @filter [String] :id Matches the id attribute
317
- # @filter [String] :name Matches the name attribute
318
- # @filter [String, Array<String>] :class Matches the class(es) provided
319
- # @filter [Boolean] :checked Match checked fields?
320
- # @filter [Boolean] :unchecked Match unchecked fields?
321
- # @filter [Boolean] :disabled Match disabled field?
322
- # @filter [String] :option Match the value
323
- #
324
- Capybara.add_selector(:checkbox) do
325
- xpath do |locator, options|
326
- xpath = XPath.descendant(:input)[XPath.attr(:type).equals('checkbox')]
327
- locate_field(xpath, locator, options)
328
- end
329
-
330
- filter_set(:_field, [:checked, :unchecked, :disabled, :name])
331
-
332
- filter(:option) { |node, value| node.value == value.to_s }
333
-
334
- describe do |options|
335
- desc = String.new
336
- desc << " with value #{options[:option].inspect}" if options[:option]
337
- desc << describe_all_expression_filters(options)
338
- desc
339
- end
340
- end
341
-
342
- ##
343
- #
344
- # Find select elements
345
- #
346
- # @locator Match id, name, placeholder, or associated label text
347
- # @filter [String] :id Matches the id attribute
348
- # @filter [String] :name Matches the name attribute
349
- # @filter [String] :placeholder Matches the placeholder attribute
350
- # @filter [String, Array<String>] :class Matches the class(es) provided
351
- # @filter [Boolean] :disabled Match disabled field?
352
- # @filter [Boolean] :multiple Match fields that accept multiple values
353
- # @filter [Array<String>] :options Exact match options
354
- # @filter [Array<String>] :with_options Partial match options
355
- # @filter [String, Array<String>] :selected Match the selection(s)
356
- # @filter [String, Array<String>] :with_selected Partial match the selection(s)
357
- #
358
- Capybara.add_selector(:select) do
359
- label "select box"
360
- xpath do |locator, options|
361
- xpath = XPath.descendant(:select)
362
- locate_field(xpath, locator, options)
363
- end
364
-
365
- filter_set(:_field, [:disabled, :multiple, :name, :placeholder])
3
+ require 'capybara/selector/xpath_extensions'
4
+ require 'capybara/selector/selector'
5
+ require 'capybara/selector/definition'
6
+
7
+ #
8
+ # All Selectors below support the listed selector specific filters in addition to the following system-wide filters
9
+ # * :id (String, Regexp, XPath::Expression) - Matches the id attribute
10
+ # * :class (String, Array<String | Regexp>, Regexp, XPath::Expression) - Matches the class(es) provided
11
+ # * :style (String, Regexp, Hash<String, String>) - Match on elements style
12
+ # * :above (Element) - Match elements above the passed element on the page
13
+ # * :below (Element) - Match elements below the passed element on the page
14
+ # * :left_of (Element) - Match elements left of the passed element on the page
15
+ # * :right_of (Element) - Match elements right of the passed element on the page
16
+ # * :near (Element) - Match elements near (within 50px) the passed element on the page
17
+ # * :focused (Boolean) - Match elements with focus (requires driver support)
18
+ #
19
+ # ### Built-in Selectors
20
+ #
21
+ # * **:xpath** - Select elements by XPath expression
22
+ # * Locator: An XPath expression
23
+ #
24
+ # * **:css** - Select elements by CSS selector
25
+ # * Locator: A CSS selector
26
+ #
27
+ # * **:id** - Select element by id
28
+ # * Locator: (String, Regexp, XPath::Expression) The id of the element to match
29
+ #
30
+ # * **:field** - Select field elements (input [not of type submit, image, or hidden], textarea, select)
31
+ # * Locator: Matches against the id, {Capybara.configure test_id} attribute, name, placeholder, or
32
+ # associated label text
33
+ # * Filters:
34
+ # * :name (String, Regexp) - Matches the name attribute
35
+ # * :placeholder (String, Regexp) - Matches the placeholder attribute
36
+ # * :type (String) - Matches the type attribute of the field or element type for 'textarea' and 'select'
37
+ # * :readonly (Boolean) - Match on the element being readonly
38
+ # * :with (String, Regexp) - Matches the current value of the field
39
+ # * :checked (Boolean) - Match checked fields?
40
+ # * :unchecked (Boolean) - Match unchecked fields?
41
+ # * :disabled (Boolean, :all) - Match disabled field? (Default: false)
42
+ # * :multiple (Boolean) - Match fields that accept multiple values
43
+ # * :valid (Boolean) - Match fields that are valid/invalid according to HTML5 form validation
44
+ # * :validation_message (String, Regexp) - Matches the elements current validationMessage
45
+ #
46
+ # * **:fieldset** - Select fieldset elements
47
+ # * Locator: Matches id, {Capybara.configure test_id}, or contents of wrapped legend
48
+ # * Filters:
49
+ # * :legend (String) - Matches contents of wrapped legend
50
+ # * :disabled (Boolean) - Match disabled fieldset?
51
+ #
52
+ # * **:link** - Find links (`<a>` elements with an href attribute)
53
+ # * Locator: Matches the id, {Capybara.configure test_id}, or title attributes, or the string content of the link,
54
+ # or the alt attribute of a contained img element. By default this selector requires a link to have an href attribute.
55
+ # * Filters:
56
+ # * :title (String) - Matches the title attribute
57
+ # * :alt (String) - Matches the alt attribute of a contained img element
58
+ # * :href (String, Regexp, nil, false) - Matches the normalized href of the link, if nil will find `<a>` elements with no href attribute, if false ignores href presence
59
+ #
60
+ # * **:button** - Find buttons ( input [of type submit, reset, image, button] or button elements )
61
+ # * Locator: Matches the id, {Capybara.configure test_id} attribute, name, value, or title attributes, string content of a button, or the alt attribute of an image type button or of a descendant image of a button
62
+ # * Filters:
63
+ # * :name (String, Regexp) - Matches the name attribute
64
+ # * :title (String) - Matches the title attribute
65
+ # * :value (String) - Matches the value of an input button
66
+ # * :type (String) - Matches the type attribute
67
+ # * :disabled (Boolean, :all) - Match disabled buttons (Default: false)
68
+ #
69
+ # * **:link_or_button** - Find links or buttons
70
+ # * Locator: See :link and :button selectors
71
+ # * Filters:
72
+ # * :disabled (Boolean, :all) - Match disabled buttons? (Default: false)
73
+ #
74
+ # * **:fillable_field** - Find text fillable fields ( textarea, input [not of type submit, image, radio, checkbox, hidden, file] )
75
+ # * Locator: Matches against the id, {Capybara.configure test_id} attribute, name, placeholder, or associated label text
76
+ # * Filters:
77
+ # * :name (String, Regexp) - Matches the name attribute
78
+ # * :placeholder (String, Regexp) - Matches the placeholder attribute
79
+ # * :with (String, Regexp) - Matches the current value of the field
80
+ # * :type (String) - Matches the type attribute of the field or element type for 'textarea'
81
+ # * :disabled (Boolean, :all) - Match disabled field? (Default: false)
82
+ # * :multiple (Boolean) - Match fields that accept multiple values
83
+ # * :valid (Boolean) - Match fields that are valid/invalid according to HTML5 form validation
84
+ # * :validation_message (String, Regexp) - Matches the elements current validationMessage
85
+ #
86
+ # * **:radio_button** - Find radio buttons
87
+ # * Locator: Match id, {Capybara.configure test_id} attribute, name, or associated label text
88
+ # * Filters:
89
+ # * :name (String, Regexp) - Matches the name attribute
90
+ # * :checked (Boolean) - Match checked fields?
91
+ # * :unchecked (Boolean) - Match unchecked fields?
92
+ # * :disabled (Boolean, :all) - Match disabled field? (Default: false)
93
+ # * :option (String, Regexp) - Match the current value
94
+ # * :with - Alias of :option
95
+ #
96
+ # * **:checkbox** - Find checkboxes
97
+ # * Locator: Match id, {Capybara.configure test_id} attribute, name, or associated label text
98
+ # * Filters:
99
+ # * :name (String, Regexp) - Matches the name attribute
100
+ # * :checked (Boolean) - Match checked fields?
101
+ # * :unchecked (Boolean) - Match unchecked fields?
102
+ # * :disabled (Boolean, :all) - Match disabled field? (Default: false)
103
+ # * :with (String, Regexp) - Match the current value
104
+ # * :option - Alias of :with
105
+ #
106
+ # * **:select** - Find select elements
107
+ # * Locator: Match id, {Capybara.configure test_id} attribute, name, placeholder, or associated label text
108
+ # * Filters:
109
+ # * :name (String, Regexp) - Matches the name attribute
110
+ # * :placeholder (String, Placeholder) - Matches the placeholder attribute
111
+ # * :disabled (Boolean, :all) - Match disabled field? (Default: false)
112
+ # * :multiple (Boolean) - Match fields that accept multiple values
113
+ # * :options (Array<String>) - Exact match options
114
+ # * :enabled_options (Array<String>) - Exact match enabled options
115
+ # * :disabled_options (Array<String>) - Exact match disabled options
116
+ # * :with_options (Array<String>) - Partial match options
117
+ # * :selected (String, Array<String>) - Match the selection(s)
118
+ # * :with_selected (String, Array<String>) - Partial match the selection(s)
119
+ #
120
+ # * **:option** - Find option elements
121
+ # * Locator: Match text of option
122
+ # * Filters:
123
+ # * :disabled (Boolean) - Match disabled option
124
+ # * :selected (Boolean) - Match selected option
125
+ #
126
+ # * **:datalist_input** - Find input field with datalist completion
127
+ # * Locator: Matches against the id, {Capybara.configure test_id} attribute, name,
128
+ # placeholder, or associated label text
129
+ # * Filters:
130
+ # * :name (String, Regexp) - Matches the name attribute
131
+ # * :placeholder (String, Regexp) - Matches the placeholder attribute
132
+ # * :disabled (Boolean, :all) - Match disabled field? (Default: false)
133
+ # * :options (Array<String>) - Exact match options
134
+ # * :with_options (Array<String>) - Partial match options
135
+ #
136
+ # * **:datalist_option** - Find datalist option
137
+ # * Locator: Match text or value of option
138
+ # * Filters:
139
+ # * :disabled (Boolean) - Match disabled option
140
+ #
141
+ # * **:file_field** - Find file input elements
142
+ # * Locator: Match id, {Capybara.configure test_id} attribute, name, or associated label text
143
+ # * Filters:
144
+ # * :name (String, Regexp) - Matches the name attribute
145
+ # * :disabled (Boolean, :all) - Match disabled field? (Default: false)
146
+ # * :multiple (Boolean) - Match field that accepts multiple values
147
+ #
148
+ # * **:label** - Find label elements
149
+ # * Locator: Match id, {Capybara.configure test_id}, or text contents
150
+ # * Filters:
151
+ # * :for (Element, String, Regexp) - The element or id of the element associated with the label
152
+ #
153
+ # * **:table** - Find table elements
154
+ # * Locator: id, {Capybara.configure test_id}, or caption text of table
155
+ # * Filters:
156
+ # * :caption (String) - Match text of associated caption
157
+ # * :with_rows (Array<Array<String>>, Array<Hash<String, String>>) - Partial match `<td>` data - visibility of `<td>` elements is not considered
158
+ # * :rows (Array<Array<String>>) - Match all `<td>`s - visibility of `<td>` elements is not considered
159
+ # * :with_cols (Array<Array<String>>, Array<Hash<String, String>>) - Partial match `<td>` data - visibility of `<td>` elements is not considered
160
+ # * :cols (Array<Array<String>>) - Match all `<td>`s - visibility of `<td>` elements is not considered
161
+ #
162
+ # * **:table_row** - Find table row
163
+ # * Locator: Array<String>, Hash<String, String> table row `<td>` contents - visibility of `<td>` elements is not considered
164
+ #
165
+ # * **:frame** - Find frame/iframe elements
166
+ # * Locator: Match id, {Capybara.configure test_id} attribute, or name
167
+ # * Filters:
168
+ # * :name (String) - Match name attribute
169
+ #
170
+ # * **:element**
171
+ # * Locator: Type of element ('div', 'a', etc) - if not specified defaults to '*'
172
+ # * Filters:
173
+ # * :\<any> (String, Regexp) - Match on any specified element attribute
174
+ #
175
+ class Capybara::Selector; end # rubocop:disable Lint/EmptyClass
366
176
 
367
- filter(:options) do |node, options|
368
- if node.visible?
369
- actual = node.all(:xpath, './/option').map { |option| option.text }
370
- else
371
- actual = node.all(:xpath, './/option', visible: false).map { |option| option.text(:all) }
177
+ Capybara::Selector::FilterSet.add(:_field) do
178
+ node_filter(:checked, :boolean) { |node, value| !(value ^ node.checked?) }
179
+ node_filter(:unchecked, :boolean) { |node, value| (value ^ node.checked?) }
180
+ node_filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| !(value ^ node.disabled?) }
181
+ node_filter(:valid, :boolean) { |node, value| node.evaluate_script('this.validity.valid') == value }
182
+ node_filter(:name) { |node, value| !value.is_a?(Regexp) || value.match?(node[:name]) }
183
+ node_filter(:placeholder) { |node, value| !value.is_a?(Regexp) || value.match?(node[:placeholder]) }
184
+ node_filter(:validation_message) do |node, msg|
185
+ vm = node[:validationMessage]
186
+ (msg.is_a?(Regexp) ? msg.match?(vm) : vm == msg.to_s).tap do |res|
187
+ add_error("Expected validation message to be #{msg.inspect} but was #{vm}") unless res
372
188
  end
373
- options.sort == actual.sort
374
189
  end
375
190
 
376
- filter(:with_options) do |node, options|
377
- finder_settings = { minimum: 0 }
378
- if !node.visible?
379
- finder_settings[:visible] = false
380
- end
381
- options.all? { |option| node.first(:option, option, finder_settings) }
191
+ expression_filter(:name) do |xpath, val|
192
+ builder(xpath).add_attribute_conditions(name: val)
382
193
  end
383
-
384
- filter(:selected) do |node, selected|
385
- actual = node.all(:xpath, './/option', visible: false).select(&:selected?).map { |option| option.text(:all) }
386
- Array(selected).sort == actual.sort
194
+ expression_filter(:placeholder) do |xpath, val|
195
+ builder(xpath).add_attribute_conditions(placeholder: val)
387
196
  end
197
+ expression_filter(:disabled) { |xpath, val| val ? xpath : xpath[~XPath.attr(:disabled)] }
198
+ expression_filter(:multiple) { |xpath, val| xpath[val ? XPath.attr(:multiple) : ~XPath.attr(:multiple)] }
388
199
 
389
- filter(:with_selected) do |node, selected|
390
- actual = node.all(:xpath, './/option', visible: false).select(&:selected?).map { |option| option.text(:all) }
391
- (Array(selected) - actual).empty?
392
- end
393
-
394
- describe do |options|
395
- desc = String.new
396
- desc << " with options #{options[:options].inspect}" if options[:options]
397
- desc << " with at least options #{options[:with_options].inspect}" if options[:with_options]
398
- desc << " with #{options[:selected].inspect} selected" if options[:selected]
399
- desc << " with at least #{options[:with_selected].inspect} selected" if options[:with_selected]
400
- desc << describe_all_expression_filters(options)
200
+ describe(:expression_filters) do |name: nil, placeholder: nil, disabled: nil, multiple: nil, **|
201
+ desc = +''
202
+ desc << ' that is not disabled' if disabled == false
203
+ desc << " with name #{name}" if name
204
+ desc << " with placeholder #{placeholder}" if placeholder
205
+ desc << ' with the multiple attribute' if multiple == true
206
+ desc << ' without the multiple attribute' if multiple == false
401
207
  desc
402
208
  end
403
- end
404
209
 
405
- ##
406
- #
407
- # Find option elements
408
- #
409
- # @locator Match text of option
410
- # @filter [Boolean] :disabled Match disabled option
411
- # @filter [Boolean] :selected Match selected option
412
- #
413
- Capybara.add_selector(:option) do
414
- xpath do |locator|
415
- xpath = XPath.descendant(:option)
416
- xpath = xpath[XPath.string.n.is(locator.to_s)] unless locator.nil?
417
- xpath
418
- end
419
-
420
- filter(:disabled, :boolean) { |node, value| not(value ^ node.disabled?) }
421
- filter(:selected, :boolean) { |node, value| not(value ^ node.selected?) }
422
-
423
- describe do |options|
424
- desc = String.new
425
- desc << " that is#{' not' unless options[:disabled]} disabled" if options.has_key?(:disabled)
426
- desc << " that is#{' not' unless options[:selected]} selected" if options.has_key?(:selected)
427
- desc
428
- end
429
- end
430
-
431
- ##
432
- #
433
- # Find file input elements
434
- #
435
- # @locator Match id, name, or associated label text
436
- # @filter [String] :id Matches the id attribute
437
- # @filter [String] :name Matches the name attribute
438
- # @filter [String, Array<String>] :class Matches the class(es) provided
439
- # @filter [Boolean] :disabled Match disabled field?
440
- # @filter [Boolean] :multiple Match field that accepts multiple values
441
- #
442
- Capybara.add_selector(:file_field) do
443
- label "file field"
444
- xpath do |locator, options|
445
- xpath = XPath.descendant(:input)[XPath.attr(:type).equals('file')]
446
- locate_field(xpath, locator, options)
447
- end
448
-
449
- filter_set(:_field, [:disabled, :multiple, :name])
450
-
451
- describe do |options|
452
- desc = String.new
453
- desc << describe_all_expression_filters(options)
454
- desc
455
- end
456
- end
457
-
458
- ##
459
- #
460
- # Find label elements
461
- #
462
- # @locator Match id or text contents
463
- # @filter [Element, String] :for The element or id of the element associated with the label
464
- #
465
- Capybara.add_selector(:label) do
466
- label "label"
467
- xpath(:for) do |locator, options|
468
- xpath = XPath.descendant(:label)
469
- xpath = xpath[XPath.string.n.is(locator.to_s).or XPath.attr(:id).equals(locator.to_s)] unless locator.nil?
470
- if options.has_key?(:for) && !options[:for].is_a?(Capybara::Node::Element)
471
- xpath = xpath[XPath.attr(:for).equals(options[:for].to_s).or((~XPath.attr(:for)).and(XPath.descendant()[XPath.attr(:id).equals(options[:for].to_s)]))]
472
- end
473
- xpath
474
- end
475
-
476
- filter(:for) do |node, field_or_value|
477
- if field_or_value.is_a? Capybara::Node::Element
478
- if node[:for]
479
- field_or_value[:id] == node[:for]
480
- else
481
- field_or_value.find_xpath('./ancestor::label[1]').include? node.base
482
- end
483
- else
484
- #Non element values were handled through the expression filter
485
- true
486
- end
487
- end
488
-
489
- describe do |options|
490
- desc = String.new
491
- desc << " for #{options[:for]}" if options[:for]
492
- desc
493
- end
494
- end
495
-
496
- ##
497
- #
498
- # Find table elements
499
- #
500
- # @locator id or caption text of table
501
- # @filter [String] :id Match id attribute of table
502
- # @filter [String] :caption Match text of associated caption
503
- # @filter [String, Array<String>] :class Matches the class(es) provided
504
- #
505
- Capybara.add_selector(:table) do
506
- xpath(:caption) do |locator, options|
507
- xpath = XPath.descendant(:table)
508
- xpath = xpath[XPath.attr(:id).equals(locator.to_s).or XPath.descendant(:caption).is(locator.to_s)] unless locator.nil?
509
- xpath = xpath[XPath.descendant(:caption).equals(options[:caption])] if options[:caption]
510
- xpath
511
- end
512
-
513
- describe do |options|
514
- desc = String.new
515
- desc << " with caption #{options[:caption]}" if options[:caption]
210
+ describe(:node_filters) do |checked: nil, unchecked: nil, disabled: nil, valid: nil, validation_message: nil, **|
211
+ desc, states = +'', []
212
+ states << 'checked' if checked || (unchecked == false)
213
+ states << 'not checked' if unchecked || (checked == false)
214
+ states << 'disabled' if disabled == true
215
+ desc << " that is #{states.join(' and ')}" unless states.empty?
216
+ desc << ' that is valid' if valid == true
217
+ desc << ' that is invalid' if valid == false
218
+ desc << " with validation message #{validation_message.to_s.inspect}" if validation_message
516
219
  desc
517
220
  end
518
221
  end
519
222
 
520
- ##
521
- #
522
- # Find frame/iframe elements
523
- #
524
- # @locator Match id or name
525
- # @filter [String] :id Match id attribute
526
- # @filter [String] :name Match name attribute
527
- # @filter [String, Array<String>] :class Matches the class(es) provided
528
- #
529
- Capybara.add_selector(:frame) do
530
- xpath(:name) do |locator, options|
531
- xpath = XPath.descendant(:iframe).union(XPath.descendant(:frame))
532
- xpath = xpath[XPath.attr(:id).equals(locator.to_s).or XPath.attr(:name).equals(locator)] unless locator.nil?
533
- xpath = expression_filters.keys.inject(xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
534
- xpath
535
- end
536
-
537
- describe do |options|
538
- desc = String.new
539
- desc << " with name #{options[:name]}" if options[:name]
540
- desc
541
- end
542
- end
223
+ require 'capybara/selector/definition/xpath'
224
+ require 'capybara/selector/definition/css'
225
+ require 'capybara/selector/definition/id'
226
+ require 'capybara/selector/definition/field'
227
+ require 'capybara/selector/definition/fieldset'
228
+ require 'capybara/selector/definition/link'
229
+ require 'capybara/selector/definition/button'
230
+ require 'capybara/selector/definition/link_or_button'
231
+ require 'capybara/selector/definition/fillable_field'
232
+ require 'capybara/selector/definition/radio_button'
233
+ require 'capybara/selector/definition/checkbox'
234
+ require 'capybara/selector/definition/select'
235
+ require 'capybara/selector/definition/datalist_input'
236
+ require 'capybara/selector/definition/option'
237
+ require 'capybara/selector/definition/datalist_option'
238
+ require 'capybara/selector/definition/file_field'
239
+ require 'capybara/selector/definition/label'
240
+ require 'capybara/selector/definition/table'
241
+ require 'capybara/selector/definition/table_row'
242
+ require 'capybara/selector/definition/frame'
243
+ require 'capybara/selector/definition/element'