capybara 2.5.0 → 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. checksums.yaml +5 -5
  2. data/.yard/templates_custom/default/class/html/selectors.erb +38 -0
  3. data/.yard/templates_custom/default/class/html/setup.rb +17 -0
  4. data/.yard/yard_extensions.rb +78 -0
  5. data/.yardopts +1 -0
  6. data/History.md +413 -10
  7. data/License.txt +1 -1
  8. data/README.md +237 -130
  9. data/lib/capybara/config.rb +132 -0
  10. data/lib/capybara/cucumber.rb +3 -1
  11. data/lib/capybara/driver/base.rb +27 -6
  12. data/lib/capybara/driver/node.rb +14 -5
  13. data/lib/capybara/dsl.rb +2 -3
  14. data/lib/capybara/helpers.rb +13 -65
  15. data/lib/capybara/minitest/spec.rb +177 -0
  16. data/lib/capybara/minitest.rb +278 -0
  17. data/lib/capybara/node/actions.rb +180 -24
  18. data/lib/capybara/node/base.rb +17 -5
  19. data/lib/capybara/node/document.rb +5 -0
  20. data/lib/capybara/node/document_matchers.rb +15 -14
  21. data/lib/capybara/node/element.rb +55 -7
  22. data/lib/capybara/node/finders.rb +179 -67
  23. data/lib/capybara/node/matchers.rb +301 -105
  24. data/lib/capybara/node/simple.rb +15 -4
  25. data/lib/capybara/queries/ancestor_query.rb +25 -0
  26. data/lib/capybara/queries/base_query.rb +69 -3
  27. data/lib/capybara/queries/current_path_query.rb +17 -8
  28. data/lib/capybara/queries/match_query.rb +19 -0
  29. data/lib/capybara/queries/selector_query.rb +251 -0
  30. data/lib/capybara/queries/sibling_query.rb +25 -0
  31. data/lib/capybara/queries/text_query.rb +67 -16
  32. data/lib/capybara/queries/title_query.rb +4 -2
  33. data/lib/capybara/query.rb +3 -131
  34. data/lib/capybara/rack_test/browser.rb +14 -5
  35. data/lib/capybara/rack_test/css_handlers.rb +1 -0
  36. data/lib/capybara/rack_test/driver.rb +15 -8
  37. data/lib/capybara/rack_test/form.rb +34 -12
  38. data/lib/capybara/rack_test/node.rb +29 -12
  39. data/lib/capybara/rails.rb +3 -3
  40. data/lib/capybara/result.rb +104 -9
  41. data/lib/capybara/rspec/compound.rb +95 -0
  42. data/lib/capybara/rspec/features.rb +17 -6
  43. data/lib/capybara/rspec/matcher_proxies.rb +45 -0
  44. data/lib/capybara/rspec/matchers.rb +199 -80
  45. data/lib/capybara/rspec.rb +4 -2
  46. data/lib/capybara/selector/css.rb +30 -0
  47. data/lib/capybara/selector/filter.rb +20 -0
  48. data/lib/capybara/selector/filter_set.rb +74 -0
  49. data/lib/capybara/selector/filters/base.rb +33 -0
  50. data/lib/capybara/selector/filters/expression_filter.rb +40 -0
  51. data/lib/capybara/selector/filters/node_filter.rb +27 -0
  52. data/lib/capybara/selector/selector.rb +276 -0
  53. data/lib/capybara/selector.rb +452 -157
  54. data/lib/capybara/selenium/driver.rb +282 -81
  55. data/lib/capybara/selenium/node.rb +144 -46
  56. data/lib/capybara/server.rb +59 -16
  57. data/lib/capybara/session/config.rb +114 -0
  58. data/lib/capybara/session/matchers.rb +29 -19
  59. data/lib/capybara/session.rb +378 -143
  60. data/lib/capybara/spec/fixtures/no_extension +1 -0
  61. data/lib/capybara/spec/public/jquery-ui.js +13 -791
  62. data/lib/capybara/spec/public/jquery.js +4 -9045
  63. data/lib/capybara/spec/public/test.js +45 -11
  64. data/lib/capybara/spec/session/accept_alert_spec.rb +30 -7
  65. data/lib/capybara/spec/session/accept_confirm_spec.rb +14 -2
  66. data/lib/capybara/spec/session/accept_prompt_spec.rb +35 -6
  67. data/lib/capybara/spec/session/all_spec.rb +45 -32
  68. data/lib/capybara/spec/session/ancestor_spec.rb +85 -0
  69. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +110 -0
  70. data/lib/capybara/spec/session/assert_current_path.rb +15 -2
  71. data/lib/capybara/spec/session/assert_selector.rb +29 -28
  72. data/lib/capybara/spec/session/assert_text.rb +59 -20
  73. data/lib/capybara/spec/session/assert_title.rb +25 -11
  74. data/lib/capybara/spec/session/attach_file_spec.rb +42 -4
  75. data/lib/capybara/spec/session/body_spec.rb +1 -0
  76. data/lib/capybara/spec/session/check_spec.rb +90 -14
  77. data/lib/capybara/spec/session/choose_spec.rb +31 -5
  78. data/lib/capybara/spec/session/click_button_spec.rb +20 -9
  79. data/lib/capybara/spec/session/click_link_or_button_spec.rb +15 -9
  80. data/lib/capybara/spec/session/click_link_spec.rb +39 -15
  81. data/lib/capybara/spec/session/current_scope_spec.rb +2 -1
  82. data/lib/capybara/spec/session/current_url_spec.rb +12 -3
  83. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +6 -5
  84. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +4 -3
  85. data/lib/capybara/spec/session/element/assert_match_selector.rb +36 -0
  86. data/lib/capybara/spec/session/element/match_css_spec.rb +23 -0
  87. data/lib/capybara/spec/session/element/match_xpath_spec.rb +23 -0
  88. data/lib/capybara/spec/session/element/matches_selector_spec.rb +106 -0
  89. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +22 -0
  90. data/lib/capybara/spec/session/evaluate_script_spec.rb +23 -1
  91. data/lib/capybara/spec/session/execute_script_spec.rb +22 -3
  92. data/lib/capybara/spec/session/fill_in_spec.rb +50 -32
  93. data/lib/capybara/spec/session/find_button_spec.rb +43 -2
  94. data/lib/capybara/spec/session/find_by_id_spec.rb +3 -2
  95. data/lib/capybara/spec/session/find_field_spec.rb +42 -6
  96. data/lib/capybara/spec/session/find_link_spec.rb +22 -3
  97. data/lib/capybara/spec/session/find_spec.rb +103 -57
  98. data/lib/capybara/spec/session/first_spec.rb +34 -18
  99. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +103 -0
  100. data/lib/capybara/spec/session/{within_frame_spec.rb → frame/within_frame_spec.rb} +44 -2
  101. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  102. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  103. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  104. data/lib/capybara/spec/session/has_button_spec.rb +17 -8
  105. data/lib/capybara/spec/session/has_css_spec.rb +85 -73
  106. data/lib/capybara/spec/session/has_current_path_spec.rb +91 -7
  107. data/lib/capybara/spec/session/has_field_spec.rb +93 -58
  108. data/lib/capybara/spec/session/has_link_spec.rb +9 -8
  109. data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
  110. data/lib/capybara/spec/session/has_select_spec.rb +159 -59
  111. data/lib/capybara/spec/session/has_selector_spec.rb +64 -28
  112. data/lib/capybara/spec/session/has_table_spec.rb +1 -0
  113. data/lib/capybara/spec/session/has_text_spec.rb +27 -12
  114. data/lib/capybara/spec/session/has_title_spec.rb +22 -4
  115. data/lib/capybara/spec/session/has_xpath_spec.rb +32 -29
  116. data/lib/capybara/spec/session/headers.rb +2 -1
  117. data/lib/capybara/spec/session/html_spec.rb +4 -3
  118. data/lib/capybara/spec/session/node_spec.rb +198 -38
  119. data/lib/capybara/spec/session/refresh_spec.rb +28 -0
  120. data/lib/capybara/spec/session/reset_session_spec.rb +46 -5
  121. data/lib/capybara/spec/session/response_code.rb +2 -1
  122. data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
  123. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -5
  124. data/lib/capybara/spec/session/save_page_spec.rb +34 -2
  125. data/lib/capybara/spec/session/save_screenshot_spec.rb +31 -1
  126. data/lib/capybara/spec/session/screenshot_spec.rb +4 -2
  127. data/lib/capybara/spec/session/select_spec.rb +34 -32
  128. data/lib/capybara/spec/session/selectors_spec.rb +65 -0
  129. data/lib/capybara/spec/session/sibling_spec.rb +52 -0
  130. data/lib/capybara/spec/session/text_spec.rb +4 -4
  131. data/lib/capybara/spec/session/title_spec.rb +2 -1
  132. data/lib/capybara/spec/session/uncheck_spec.rb +42 -2
  133. data/lib/capybara/spec/session/unselect_spec.rb +17 -16
  134. data/lib/capybara/spec/session/visit_spec.rb +77 -2
  135. data/lib/capybara/spec/session/window/become_closed_spec.rb +12 -11
  136. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  137. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  138. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +16 -11
  139. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +7 -4
  140. data/lib/capybara/spec/session/window/window_spec.rb +36 -29
  141. data/lib/capybara/spec/session/window/windows_spec.rb +1 -0
  142. data/lib/capybara/spec/session/window/within_window_spec.rb +31 -7
  143. data/lib/capybara/spec/session/within_spec.rb +14 -6
  144. data/lib/capybara/spec/spec_helper.rb +37 -4
  145. data/lib/capybara/spec/test_app.rb +15 -3
  146. data/lib/capybara/spec/views/buttons.erb +1 -0
  147. data/lib/capybara/spec/views/fieldsets.erb +2 -1
  148. data/lib/capybara/spec/views/form.erb +169 -9
  149. data/lib/capybara/spec/views/frame_child.erb +10 -2
  150. data/lib/capybara/spec/views/frame_one.erb +2 -1
  151. data/lib/capybara/spec/views/frame_parent.erb +3 -2
  152. data/lib/capybara/spec/views/frame_two.erb +2 -1
  153. data/lib/capybara/spec/views/header_links.erb +1 -0
  154. data/lib/capybara/spec/views/host_links.erb +1 -0
  155. data/lib/capybara/spec/views/initial_alert.erb +10 -0
  156. data/lib/capybara/spec/views/path.erb +1 -0
  157. data/lib/capybara/spec/views/popup_one.erb +1 -0
  158. data/lib/capybara/spec/views/popup_two.erb +1 -0
  159. data/lib/capybara/spec/views/postback.erb +2 -1
  160. data/lib/capybara/spec/views/tables.erb +1 -0
  161. data/lib/capybara/spec/views/with_base_tag.erb +1 -0
  162. data/lib/capybara/spec/views/with_count.erb +2 -1
  163. data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
  164. data/lib/capybara/spec/views/with_hover.erb +7 -1
  165. data/lib/capybara/spec/views/with_html.erb +40 -2
  166. data/lib/capybara/spec/views/with_html_entities.erb +1 -0
  167. data/lib/capybara/spec/views/with_js.erb +32 -1
  168. data/lib/capybara/spec/views/with_scope.erb +1 -0
  169. data/lib/capybara/spec/views/with_simple_html.erb +2 -1
  170. data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
  171. data/lib/capybara/spec/views/with_title.erb +2 -1
  172. data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
  173. data/lib/capybara/spec/views/with_windows.erb +7 -0
  174. data/lib/capybara/spec/views/within_frames.erb +3 -2
  175. data/lib/capybara/version.rb +2 -1
  176. data/lib/capybara/window.rb +20 -3
  177. data/lib/capybara.rb +189 -93
  178. data/spec/basic_node_spec.rb +7 -6
  179. data/spec/capybara_spec.rb +90 -4
  180. data/spec/dsl_spec.rb +3 -1
  181. data/spec/filter_set_spec.rb +28 -0
  182. data/spec/fixtures/capybara.csv +1 -0
  183. data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -1
  184. data/spec/fixtures/selenium_driver_rspec_success.rb +5 -1
  185. data/spec/minitest_spec.rb +130 -0
  186. data/spec/minitest_spec_spec.rb +135 -0
  187. data/spec/per_session_config_spec.rb +67 -0
  188. data/spec/rack_test_spec.rb +50 -7
  189. data/spec/result_spec.rb +76 -0
  190. data/spec/rspec/features_spec.rb +21 -8
  191. data/spec/rspec/scenarios_spec.rb +21 -0
  192. data/spec/rspec/{matchers_spec.rb → shared_spec_matchers.rb} +160 -54
  193. data/spec/rspec/views_spec.rb +5 -0
  194. data/spec/rspec_matchers_spec.rb +46 -0
  195. data/spec/rspec_spec.rb +79 -1
  196. data/spec/selector_spec.rb +199 -0
  197. data/spec/selenium_spec_chrome.rb +54 -9
  198. data/spec/selenium_spec_firefox.rb +68 -0
  199. data/spec/selenium_spec_marionette.rb +127 -0
  200. data/spec/server_spec.rb +102 -14
  201. data/spec/session_spec.rb +54 -0
  202. data/spec/shared_selenium_session.rb +215 -0
  203. data/spec/spec_helper.rb +7 -0
  204. metadata +140 -15
  205. data/spec/selenium_spec.rb +0 -128
@@ -0,0 +1,278 @@
1
+ # frozen_string_literal: true
2
+ require 'minitest'
3
+ require 'capybara/dsl'
4
+
5
+ module Capybara
6
+ module Minitest
7
+ module Assertions
8
+ ## Assert text exists
9
+ #
10
+ # @!method assert_text
11
+ # see {Capybara::Node::Matchers#assert_text}
12
+
13
+ ## Assert text does not exist
14
+ #
15
+ # @!method assert_no_text
16
+ # see {Capybara::Node::Matchers#assert_no_text}
17
+
18
+ ##
19
+ # Assertion that page title does match
20
+ #
21
+ # @!method assert_title
22
+ # see {Capybara::Node::DocumentMatchers#assert_title}
23
+
24
+ ##
25
+ # Assertion that page title does not match
26
+ #
27
+ # @!method refute_title
28
+ # @!method assert_no_title
29
+ # see {Capybara::Node::DocumentMatchers#assert_no_title}
30
+
31
+ ##
32
+ # Assertion that current path matches
33
+ #
34
+ # @!method assert_current_path
35
+ # see {Capybara::SessionMatchers#assert_current_path}
36
+
37
+ ##
38
+ # Assertion that current page does not match
39
+ #
40
+ # @!method refute_current_path
41
+ # @!method assert_no_current_path
42
+ # see {Capybara::SessionMatchers#assert_no_current_path}
43
+
44
+
45
+ %w(assert_text assert_no_text assert_title assert_no_title assert_current_path assert_no_current_path).each do |assertion_name|
46
+ self.class_eval <<-EOM, __FILE__, __LINE__ + 1
47
+ def #{assertion_name} *args
48
+ self.assertions +=1
49
+ subject, *args = determine_subject(args)
50
+ subject.#{assertion_name}(*args)
51
+ rescue Capybara::ExpectationNotMet => e
52
+ raise ::Minitest::Assertion, e.message
53
+ end
54
+ EOM
55
+ end
56
+
57
+ alias_method :refute_title, :assert_no_title
58
+ alias_method :refute_text, :assert_no_text
59
+ alias_method :refute_content, :refute_text
60
+ alias_method :refute_current_path, :assert_no_current_path
61
+ alias_method :assert_content, :assert_text
62
+ alias_method :assert_no_content, :refute_text
63
+
64
+ ## Assert selector exists on page
65
+ #
66
+ # @!method assert_selector
67
+ # see {Capybara::Node::Matchers#assert_selector}
68
+
69
+ ## Assert selector does not exist on page
70
+ #
71
+ # @!method assert_no_selector
72
+ # see {Capybara::Node::Matchers#assert_no_selector}
73
+
74
+ ## Assert element matches selector
75
+ #
76
+ # @!method assert_matches_selector
77
+ # see {Capybara::Node::Matchers#assert_matches_selector}
78
+
79
+ ## Assert element does not match selector
80
+ #
81
+ # @!method assert_xpath
82
+ # see {Capybara::Node::Matchers#assert_not_matches_selector}
83
+
84
+ %w(assert_selector assert_no_selector
85
+ assert_all_of_selectors assert_none_of_selectors
86
+ assert_matches_selector assert_not_matches_selector).each do |assertion_name|
87
+ self.class_eval <<-EOM, __FILE__, __LINE__ + 1
88
+ def #{assertion_name} *args, &optional_filter_block
89
+ self.assertions +=1
90
+ subject, *args = determine_subject(args)
91
+ subject.#{assertion_name}(*args, &optional_filter_block)
92
+ rescue Capybara::ExpectationNotMet => e
93
+ raise ::Minitest::Assertion, e.message
94
+ end
95
+ EOM
96
+ end
97
+
98
+ alias_method :refute_selector, :assert_no_selector
99
+ alias_method :refute_matches_selector, :assert_not_matches_selector
100
+
101
+ %w(xpath css link button field select table).each do |selector_type|
102
+ define_method "assert_#{selector_type}" do |*args, &optional_filter_block|
103
+ subject, *args = determine_subject(args)
104
+ locator, options = extract_locator(args)
105
+ assert_selector(subject, selector_type.to_sym, locator, options, &optional_filter_block)
106
+ end
107
+
108
+ define_method "assert_no_#{selector_type}" do |*args, &optional_filter_block|
109
+ subject, *args = determine_subject(args)
110
+ locator, options = extract_locator(args)
111
+ assert_no_selector(subject, selector_type.to_sym, locator, options, &optional_filter_block)
112
+ end
113
+ alias_method "refute_#{selector_type}", "assert_no_#{selector_type}"
114
+ end
115
+
116
+ %w(checked unchecked).each do |field_type|
117
+ define_method "assert_#{field_type}_field" do |*args, &optional_filter_block|
118
+ subject, *args = determine_subject(args)
119
+ locator, options = extract_locator(args)
120
+ assert_selector(subject, :field, locator, options.merge(field_type.to_sym => true), &optional_filter_block)
121
+ end
122
+
123
+ define_method "assert_no_#{field_type}_field" do |*args, &optional_filter_block|
124
+ subject, *args = determine_subject(args)
125
+ locator, options = extract_locator(args)
126
+ assert_no_selector(subject, :field, locator, options.merge(field_type.to_sym => true), &optional_filter_block)
127
+ end
128
+ alias_method "refute_#{field_type}_field", "assert_no_#{field_type}_field"
129
+ end
130
+
131
+ %w(xpath css).each do |selector_type|
132
+ define_method "assert_matches_#{selector_type}" do |*args, &optional_filter_block|
133
+ subject, *args = determine_subject(args)
134
+ assert_matches_selector(subject, selector_type.to_sym, *args, &optional_filter_block)
135
+ end
136
+
137
+ define_method "assert_not_matches_#{selector_type}" do |*args, &optional_filter_block|
138
+ subject, *args = determine_subject(args)
139
+ assert_not_matches_selector(subject, selector_type.to_sym, *args, &optional_filter_block)
140
+ end
141
+ alias_method "refute_matches_#{selector_type}", "assert_not_matches_#{selector_type}"
142
+ end
143
+
144
+
145
+ ##
146
+ # Assertion that there is xpath
147
+ #
148
+ # @!method assert_xpath
149
+ # see Capybara::Node::Matchers#has_xpath?
150
+
151
+ ##
152
+ # Assertion that there is no xpath
153
+ #
154
+ # @!method refute_xpath
155
+ # @!method assert_no_xpath
156
+ # see Capybara::Node::Matchers#has_no_xpath?
157
+
158
+ ##
159
+ # Assertion that there is css
160
+ #
161
+ # @!method assert_css
162
+ # see Capybara::Node::Matchers#has_css?
163
+
164
+ ##
165
+ # Assertion that there is no css
166
+ #
167
+ # @!method refute_css
168
+ # @!method assert_no_css
169
+ # see Capybara::Node::Matchers#has_no_css?
170
+
171
+ ##
172
+ # Assertion that there is link
173
+ #
174
+ # @!method assert_link
175
+ # see {Capybara::Node::Matchers#has_link?}
176
+
177
+ ##
178
+ # Assertion that there is no link
179
+ #
180
+ # @!method assert_no_link
181
+ # @!method refute_link
182
+ # see {Capybara::Node::Matchers#has_no_link?}
183
+
184
+ ##
185
+ # Assertion that there is button
186
+ #
187
+ # @!method assert_button
188
+ # see {Capybara::Node::Matchers#has_button?}
189
+
190
+ ##
191
+ # Assertion that there is no button
192
+ #
193
+ # @!method refute_button
194
+ # @!method assert_no_button
195
+ # see {Capybara::Node::Matchers#has_no_button?}
196
+
197
+ ##
198
+ # Assertion that there is field
199
+ #
200
+ # @!method assert_field
201
+ # see {Capybara::Node::Matchers#has_field?}
202
+
203
+ ##
204
+ # Assertion that there is no field
205
+ #
206
+ # @!method refute_field
207
+ # @!method assert_no_field
208
+ # see {Capybara::Node::Matchers#has_no_field?}
209
+
210
+ ##
211
+ # Assertion that there is checked_field
212
+ #
213
+ # @!method assert_checked_field
214
+ # see {Capybara::Node::Matchers#has_checked_field?}
215
+
216
+ ##
217
+ # Assertion that there is no checked_field
218
+ #
219
+ # @!method assert_no_checked_field
220
+ # @!method refute_checked_field
221
+
222
+ ##
223
+ # Assertion that there is unchecked_field
224
+ #
225
+ # @!method assert_unchecked_field
226
+ # see {Capybara::Node::Matchers#has_unchecked_field?}
227
+
228
+ ##
229
+ # Assertion that there is no unchecked_field
230
+ #
231
+ # @!method assert_no_unchecked_field
232
+ # @!method refute_unchecked_field
233
+
234
+ ##
235
+ # Assertion that there is select
236
+ #
237
+ # @!method assert_select
238
+ # see {Capybara::Node::Matchers#has_select?}
239
+
240
+ ##
241
+ # Assertion that there is no select
242
+ #
243
+ # @!method refute_select
244
+ # @!method assert_no_select
245
+ # see {Capybara::Node::Matchers#has_no_select?}
246
+
247
+ ##
248
+ # Assertion that there is table
249
+ #
250
+ # @!method assert_table
251
+ # see {Capybara::Node::Matchers#has_table?}
252
+
253
+ ##
254
+ # Assertion that there is no table
255
+ #
256
+ # @!method refute_table
257
+ # @!method assert_no_table
258
+ # see {Capybara::Node::Matchers#has_no_table?}
259
+
260
+ private
261
+
262
+ def determine_subject(args)
263
+ case args.first
264
+ when Capybara::Session, Capybara::Node::Base, Capybara::Node::Simple
265
+ args
266
+ else
267
+ [page, *args]
268
+ end
269
+ end
270
+
271
+ def extract_locator(args)
272
+ locator, options = *args, {}
273
+ locator, options = nil, locator if locator.is_a? Hash
274
+ [locator, options]
275
+ end
276
+ end
277
+ end
278
+ end
@@ -1,15 +1,27 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
  module Actions
4
5
 
5
6
  ##
6
7
  #
7
- # Finds a button or link by id, text or value and clicks it. Also looks at image
8
- # alt text inside the link.
8
+ # Finds a button or link and clicks it. See {Capybara::Node::Actions#click_button} and
9
+ # {Capybara::Node::Actions#click_link} for what locator will match against for each type of element
10
+ # @!macro waiting_behavior
11
+ # If the driver is capable of executing JavaScript, +$0+ will wait for a set amount of time
12
+ # and continuously retry finding the element until either the element is found or the time
13
+ # expires. The length of time +find+ will wait is controlled through {Capybara.default_max_wait_time}
14
+ #
15
+ # @option options [false, Numeric] wait (Capybara.default_max_wait_time) Maximum time to wait for matching element to appear.
16
+ #
17
+ # @overload click_link_or_button([locator], options)
18
+ #
19
+ # @param [String] locator See {Capybara::Node::Actions#click_button} and {Capybara::Node::Actions#click_link}
9
20
  #
10
- # @param [String] locator Text, id or value of link or button
21
+ # @return [Capybara::Node::Element] The element clicked
11
22
  #
12
- def click_link_or_button(locator, options={})
23
+ def click_link_or_button(locator=nil, options={})
24
+ locator, options = nil, locator if locator.is_a? Hash
13
25
  find(:link_or_button, locator, options).click
14
26
  end
15
27
  alias_method :click_on, :click_link_or_button
@@ -19,10 +31,15 @@ module Capybara
19
31
  # Finds a link by id, text or title and clicks it. Also looks at image
20
32
  # alt text inside the link.
21
33
  #
22
- # @param [String] locator text, id, title or nested image's alt attribute
23
- # @param options See {Capybara::Node::Finders#find_link}
34
+ # @macro waiting_behavior
24
35
  #
25
- def click_link(locator, options={})
36
+ # @overload click_link([locator], options)
37
+ # @param [String] locator text, id, title or nested image's alt attribute
38
+ # @param options See {Capybara::Node::Finders#find_link}
39
+ #
40
+ # @return [Capybara::Node::Element] The element clicked
41
+ def click_link(locator=nil, options={})
42
+ locator, options = nil, locator if locator.is_a? Hash
26
43
  find(:link, locator, options).click
27
44
  end
28
45
 
@@ -33,9 +50,14 @@ module Capybara
33
50
  # \<button> element. All buttons can be found by their id, value, or title. \<button> elements can also be found
34
51
  # by their text content, and image \<input> elements by their alt attribute
35
52
  #
36
- # @param [String] locator Which button to find
37
- # @param options See {Capybara::Node::Finders#find_button}
38
- def click_button(locator, options={})
53
+ # @macro waiting_behavior
54
+ #
55
+ # @overload click_button([locator], options)
56
+ # @param [String] locator Which button to find
57
+ # @param options See {Capybara::Node::Finders#find_button}
58
+ # @return [Capybara::Node::Element] The element clicked
59
+ def click_button(locator=nil, options={})
60
+ locator, options = nil, locator if locator.is_a? Hash
39
61
  find(:button, locator, options).click
40
62
  end
41
63
 
@@ -44,20 +66,35 @@ module Capybara
44
66
  # Locate a text field or text area and fill it in with the given text
45
67
  # The field can be found via its name, id or label text.
46
68
  #
47
- # page.fill_in 'Name', :with => 'Bob'
69
+ # page.fill_in 'Name', with: 'Bob'
48
70
  #
49
- # @param [String] locator Which field to fill in
50
- # @param [Hash] options
51
- # @option options [String] :with The value to fill in - required
52
- # @option options [Hash] :fill_options Driver specific options regarding how to fill fields
53
71
  #
72
+ # @overload fill_in([locator], options={})
73
+ # @param [String] locator Which field to fill in
74
+ # @param [Hash] options
75
+ # @macro waiting_behavior
76
+ # @option options [String] :with The value to fill in - required
77
+ # @option options [Hash] :fill_options Driver specific options regarding how to fill fields
78
+ # @option options [String] :currently_with The current value property of the field to fill in
79
+ # @option options [Boolean] :multiple Match fields that can have multiple values?
80
+ # @option options [String] :id Match fields that match the id attribute
81
+ # @option options [String] :name Match fields that match the name attribute
82
+ # @option options [String] :placeholder Match fields that match the placeholder attribute
83
+ # @option options [String, Array<String>] :class Match fields that match the class(es) provided
84
+ #
85
+ # @return [Capybara::Node::Element] The element filled_in
54
86
  def fill_in(locator, options={})
87
+ locator, options = nil, locator if locator.is_a? Hash
55
88
  raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
56
89
  with = options.delete(:with)
57
90
  fill_options = options.delete(:fill_options)
91
+ options[:with] = options.delete(:currently_with) if options.has_key?(:currently_with)
58
92
  find(:fillable_field, locator, options).set(with, fill_options)
59
93
  end
60
94
 
95
+ # @!macro label_click
96
+ # @option options [Boolean] :allow_label_click (Capybara.automatic_label_click) Attempt to click the label to toggle state if element is non-visible.
97
+
61
98
  ##
62
99
  #
63
100
  # Find a radio button and mark it as checked. The radio button can be found
@@ -65,10 +102,19 @@ module Capybara
65
102
  #
66
103
  # page.choose('Male')
67
104
  #
68
- # @param [String] locator Which radio button to choose
105
+ # @overload choose([locator], options)
106
+ # @param [String] locator Which radio button to choose
69
107
  #
108
+ # @option options [String] :option Value of the radio_button to choose
109
+ # @option options [String] :id Match fields that match the id attribute
110
+ # @option options [String] :name Match fields that match the name attribute
111
+ # @option options [String, Array<String>] :class Match fields that match the class(es) provided
112
+ # @macro waiting_behavior
113
+ # @macro label_click
114
+ #
115
+ # @return [Capybara::Node::Element] The element chosen or the label clicked
70
116
  def choose(locator, options={})
71
- find(:radio_button, locator, options).set(true)
117
+ _check_with_label(:radio_button, true, locator, options)
72
118
  end
73
119
 
74
120
  ##
@@ -78,10 +124,20 @@ module Capybara
78
124
  #
79
125
  # page.check('German')
80
126
  #
81
- # @param [String] locator Which check box to check
82
127
  #
128
+ # @overload check([locator], options)
129
+ # @param [String] locator Which check box to check
130
+ #
131
+ # @option options [String] :option Value of the checkbox to select
132
+ # @option options [String] id Match fields that match the id attribute
133
+ # @option options [String] name Match fields that match the name attribute
134
+ # @option options [String, Array<String>] :class Match fields that match the class(es) provided
135
+ # @macro label_click
136
+ # @macro waiting_behavior
137
+ #
138
+ # @return [Capybara::Node::Element] The element checked or the label clicked
83
139
  def check(locator, options={})
84
- find(:checkbox, locator, options).set(true)
140
+ _check_with_label(:checkbox, true, locator, options)
85
141
  end
86
142
 
87
143
  ##
@@ -91,10 +147,20 @@ module Capybara
91
147
  #
92
148
  # page.uncheck('German')
93
149
  #
94
- # @param [String] locator Which check box to uncheck
95
150
  #
151
+ # @overload uncheck([locator], options)
152
+ # @param [String] locator Which check box to uncheck
153
+ #
154
+ # @option options [String] :option Value of the checkbox to deselect
155
+ # @option options [String] id Match fields that match the id attribute
156
+ # @option options [String] name Match fields that match the name attribute
157
+ # @option options [String, Array<String>] :class Match fields that match the class(es) provided
158
+ # @macro label_click
159
+ # @macro waiting_behavior
160
+ #
161
+ # @return [Capybara::Node::Element] The element unchecked or the label clicked
96
162
  def uncheck(locator, options={})
97
- find(:checkbox, locator, options).set(false)
163
+ _check_with_label(:checkbox, false, locator, options)
98
164
  end
99
165
 
100
166
  ##
@@ -106,11 +172,14 @@ module Capybara
106
172
  # one option.
107
173
  # The select box can be found via its name, id or label text. The option can be found by its text.
108
174
  #
109
- # page.select 'March', :from => 'Month'
175
+ # page.select 'March', from: 'Month'
176
+ #
177
+ # @macro waiting_behavior
110
178
  #
111
179
  # @param [String] value Which option to select
112
180
  # @option options [String] :from The id, name or label of the select box
113
181
  #
182
+ # @return [Capybara::Node::Element] The option element selected
114
183
  def select(value, options={})
115
184
  if options.has_key?(:from)
116
185
  from = options.delete(:from)
@@ -126,11 +195,14 @@ module Capybara
126
195
  # box is a multiple select, +unselect+ can be called multiple times to unselect more than
127
196
  # one option. The select box can be found via its name, id or label text.
128
197
  #
129
- # page.unselect 'March', :from => 'Month'
198
+ # page.unselect 'March', from: 'Month'
199
+ #
200
+ # @macro waiting_behavior
130
201
  #
131
202
  # @param [String] value Which option to unselect
132
203
  # @param [Hash{:from => String}] options The id, name or label of the select box
133
204
  #
205
+ # @return [Capybara::Node::Element] The option element unselected
134
206
  def unselect(value, options={})
135
207
  if options.has_key?(:from)
136
208
  from = options.delete(:from)
@@ -147,15 +219,99 @@ module Capybara
147
219
  #
148
220
  # page.attach_file(locator, '/path/to/file.png')
149
221
  #
222
+ # @macro waiting_behavior
223
+ #
150
224
  # @param [String] locator Which field to attach the file to
151
225
  # @param [String] path The path of the file that will be attached, or an array of paths
152
226
  #
227
+ # @option options [Symbol] match (Capybara.match) The matching strategy to use (:one, :first, :prefer_exact, :smart).
228
+ # @option options [Boolean] exact (Capybara.exact) Match the exact label name/contents or accept a partial match.
229
+ # @option options [Boolean] multiple Match field which allows multiple file selection
230
+ # @option options [String] id Match fields that match the id attribute
231
+ # @option options [String] name Match fields that match the name attribute
232
+ # @option options [String, Array<String>] :class Match fields that match the class(es) provided
233
+ # @option options [true, Hash] make_visible A Hash of CSS styles to change before attempting to attach the file, if `true` { opacity: 1, display: 'block', visibility: 'visible' } is used (may not be supported by all drivers)
234
+ #
235
+ # @return [Capybara::Node::Element] The file field element
153
236
  def attach_file(locator, path, options={})
237
+ locator, path, options = nil, locator, path if path.is_a? Hash
154
238
  Array(path).each do |p|
155
239
  raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
156
240
  end
157
- find(:file_field, locator, options).set(path)
241
+ # Allow user to update the CSS style of the file input since they are so often hidden on a page
242
+ if style = options.delete(:make_visible)
243
+ style = { opacity: 1, display: 'block', visibility: 'visible' } if style == true
244
+ ff = find(:file_field, locator, options.merge({visible: :all}))
245
+ _update_style(ff, style)
246
+ if ff.visible?
247
+ begin
248
+ ff.set(path)
249
+ ensure
250
+ _reset_style(ff)
251
+ end
252
+ else
253
+ raise ExpectationNotMet, "The style changes in :make_visible did not make the file input visible"
254
+ end
255
+ else
256
+ find(:file_field, locator, options).set(path)
257
+ end
258
+ end
259
+
260
+ private
261
+ def _update_style(element, style)
262
+ script = <<-JS
263
+ var el = arguments[0];
264
+ el.capybara_style_cache = el.style.cssText;
265
+ var css = arguments[1];
266
+ for (var prop in css){
267
+ if (css.hasOwnProperty(prop)) {
268
+ el.style[prop] = css[prop]
269
+ }
270
+ }
271
+ JS
272
+ begin
273
+ session.execute_script(script, element, style)
274
+ rescue Capybara::NotSupportedByDriverError
275
+ warn "The :make_visible option is not supported by the current driver - ignoring"
276
+ end
158
277
  end
278
+
279
+ def _reset_style(element)
280
+ script = <<-JS
281
+ var el = arguments[0];
282
+ if (el.hasOwnProperty('capybara_style_cache')) {
283
+ el.style.cssText = el.capybara_style_cache;
284
+ delete el.capybara_style_cache;
285
+ }
286
+ JS
287
+ begin
288
+ session.execute_script(script, element)
289
+ rescue
290
+ end
291
+ end
292
+
293
+
294
+ def _check_with_label(selector, checked, locator, options)
295
+ locator, options = nil, locator if locator.is_a? Hash
296
+ allow_label_click = options.delete(:allow_label_click) { session_options.automatic_label_click }
297
+
298
+ synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
299
+ begin
300
+ el = find(selector, locator, options)
301
+ el.set(checked)
302
+ rescue => e
303
+ raise unless allow_label_click && catch_error?(e)
304
+ begin
305
+ el ||= find(selector, locator, options.merge(visible: :all))
306
+ label = find(:label, for: el, visible: true)
307
+ label.click unless (el.checked? == checked)
308
+ rescue
309
+ raise e
310
+ end
311
+ end
312
+ end
313
+ end
314
+
159
315
  end
160
316
  end
161
317
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
 
@@ -16,13 +17,13 @@ module Capybara
16
17
  #
17
18
  # session = Capybara::Session.new(:rack_test, my_app)
18
19
  # session.visit('/')
19
- # session.fill_in('Foo', :with => 'Bar') # from Capybara::Node::Actions
20
+ # session.fill_in('Foo', with: 'Bar') # from Capybara::Node::Actions
20
21
  # bar = session.find('#bar') # from Capybara::Node::Finders
21
- # bar.select('Baz', :from => 'Quox') # from Capybara::Node::Actions
22
+ # bar.select('Baz', from: 'Quox') # from Capybara::Node::Actions
22
23
  # session.has_css?('#foobar') # from Capybara::Node::Matchers
23
24
  #
24
25
  class Base
25
- attr_reader :session, :base, :parent
26
+ attr_reader :session, :base, :query_scope
26
27
 
27
28
  include Capybara::Node::Finders
28
29
  include Capybara::Node::Actions
@@ -73,7 +74,7 @@ module Capybara
73
74
  # @return [Object] The result of the given block
74
75
  # @raise [Capybara::FrozenInTime] If the return value of `Time.now` appears stuck
75
76
  #
76
- def synchronize(seconds=Capybara.default_max_wait_time, options = {})
77
+ def synchronize(seconds=session_options.default_max_wait_time, options = {})
77
78
  start_time = Capybara::Helpers.monotonic_time
78
79
 
79
80
  if session.synchronized
@@ -89,7 +90,7 @@ module Capybara
89
90
  raise e if (Capybara::Helpers.monotonic_time - start_time) >= seconds
90
91
  sleep(0.05)
91
92
  raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if Capybara::Helpers.monotonic_time == start_time
92
- reload if Capybara.automatic_reload
93
+ reload if session_options.automatic_reload
93
94
  retry
94
95
  ensure
95
96
  session.synchronized = false
@@ -107,6 +108,17 @@ module Capybara
107
108
  base.find_xpath(xpath)
108
109
  end
109
110
 
111
+ # @deprecated Use query_scope instead
112
+ def parent
113
+ warn "DEPRECATED: #parent is deprecated in favor of #query_scope - Note: #parent was not the elements parent in the document so it's most likely not what you wanted anyway"
114
+ query_scope
115
+ end
116
+
117
+ # @api private
118
+ def session_options
119
+ session.config
120
+ end
121
+
110
122
  protected
111
123
 
112
124
  def catch_error?(error, errors = nil)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
 
@@ -23,6 +24,10 @@ module Capybara
23
24
  find(:xpath, '/html').text(type)
24
25
  end
25
26
 
27
+ ##
28
+ #
29
+ # @return [String] The title of the document
30
+ #
26
31
  def title
27
32
  session.driver.title
28
33
  end