capybara 3.13.2 → 3.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +587 -16
  4. data/README.md +240 -90
  5. data/lib/capybara/config.rb +24 -11
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/driver/base.rb +8 -0
  8. data/lib/capybara/driver/node.rb +20 -4
  9. data/lib/capybara/dsl.rb +5 -3
  10. data/lib/capybara/helpers.rb +25 -4
  11. data/lib/capybara/minitest/spec.rb +174 -90
  12. data/lib/capybara/minitest.rb +256 -142
  13. data/lib/capybara/node/actions.rb +123 -77
  14. data/lib/capybara/node/base.rb +20 -12
  15. data/lib/capybara/node/document.rb +2 -2
  16. data/lib/capybara/node/document_matchers.rb +3 -3
  17. data/lib/capybara/node/element.rb +223 -117
  18. data/lib/capybara/node/finders.rb +81 -71
  19. data/lib/capybara/node/matchers.rb +271 -134
  20. data/lib/capybara/node/simple.rb +18 -5
  21. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  22. data/lib/capybara/queries/active_element_query.rb +18 -0
  23. data/lib/capybara/queries/ancestor_query.rb +8 -9
  24. data/lib/capybara/queries/base_query.rb +3 -2
  25. data/lib/capybara/queries/current_path_query.rb +15 -5
  26. data/lib/capybara/queries/selector_query.rb +364 -54
  27. data/lib/capybara/queries/sibling_query.rb +8 -6
  28. data/lib/capybara/queries/style_query.rb +2 -2
  29. data/lib/capybara/queries/text_query.rb +13 -1
  30. data/lib/capybara/queries/title_query.rb +1 -1
  31. data/lib/capybara/rack_test/browser.rb +76 -11
  32. data/lib/capybara/rack_test/driver.rb +10 -5
  33. data/lib/capybara/rack_test/errors.rb +6 -0
  34. data/lib/capybara/rack_test/form.rb +31 -9
  35. data/lib/capybara/rack_test/node.rb +74 -23
  36. data/lib/capybara/registration_container.rb +41 -0
  37. data/lib/capybara/registrations/drivers.rb +42 -0
  38. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  39. data/lib/capybara/registrations/servers.rb +66 -0
  40. data/lib/capybara/result.rb +44 -20
  41. data/lib/capybara/rspec/matcher_proxies.rb +13 -11
  42. data/lib/capybara/rspec/matchers/base.rb +31 -16
  43. data/lib/capybara/rspec/matchers/compound.rb +1 -1
  44. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  45. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  46. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  47. data/lib/capybara/rspec/matchers/have_selector.rb +21 -21
  48. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  49. data/lib/capybara/rspec/matchers/have_text.rb +4 -4
  50. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  51. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  52. data/lib/capybara/rspec/matchers/match_style.rb +7 -2
  53. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  54. data/lib/capybara/rspec/matchers.rb +111 -68
  55. data/lib/capybara/rspec.rb +2 -0
  56. data/lib/capybara/selector/builders/css_builder.rb +11 -7
  57. data/lib/capybara/selector/builders/xpath_builder.rb +5 -3
  58. data/lib/capybara/selector/css.rb +11 -9
  59. data/lib/capybara/selector/definition/button.rb +68 -0
  60. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  61. data/lib/capybara/selector/definition/css.rb +10 -0
  62. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  63. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  64. data/lib/capybara/selector/definition/element.rb +28 -0
  65. data/lib/capybara/selector/definition/field.rb +40 -0
  66. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  67. data/lib/capybara/selector/definition/file_field.rb +13 -0
  68. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  69. data/lib/capybara/selector/definition/frame.rb +17 -0
  70. data/lib/capybara/selector/definition/id.rb +6 -0
  71. data/lib/capybara/selector/definition/label.rb +62 -0
  72. data/lib/capybara/selector/definition/link.rb +55 -0
  73. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  74. data/lib/capybara/selector/definition/option.rb +27 -0
  75. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  76. data/lib/capybara/selector/definition/select.rb +81 -0
  77. data/lib/capybara/selector/definition/table.rb +109 -0
  78. data/lib/capybara/selector/definition/table_row.rb +21 -0
  79. data/lib/capybara/selector/definition/xpath.rb +5 -0
  80. data/lib/capybara/selector/definition.rb +280 -0
  81. data/lib/capybara/selector/filter_set.rb +19 -18
  82. data/lib/capybara/selector/filters/base.rb +11 -2
  83. data/lib/capybara/selector/filters/locator_filter.rb +13 -3
  84. data/lib/capybara/selector/regexp_disassembler.rb +11 -7
  85. data/lib/capybara/selector/selector.rb +50 -440
  86. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  87. data/lib/capybara/selector.rb +473 -482
  88. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  89. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  90. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  91. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  92. data/lib/capybara/selenium/driver.rb +174 -62
  93. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +74 -18
  94. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  95. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +37 -3
  96. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +14 -1
  97. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  98. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  99. data/lib/capybara/selenium/extensions/find.rb +68 -45
  100. data/lib/capybara/selenium/extensions/html5_drag.rb +192 -22
  101. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  102. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  103. data/lib/capybara/selenium/node.rb +268 -72
  104. data/lib/capybara/selenium/nodes/chrome_node.rb +105 -9
  105. data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
  106. data/lib/capybara/selenium/nodes/firefox_node.rb +51 -61
  107. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  108. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  109. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  110. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  111. data/lib/capybara/selenium/patches/logs.rb +45 -0
  112. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -1
  113. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  114. data/lib/capybara/server/animation_disabler.rb +43 -21
  115. data/lib/capybara/server/checker.rb +6 -2
  116. data/lib/capybara/server/middleware.rb +25 -13
  117. data/lib/capybara/server.rb +20 -4
  118. data/lib/capybara/session/config.rb +15 -11
  119. data/lib/capybara/session/matchers.rb +11 -11
  120. data/lib/capybara/session.rb +162 -131
  121. data/lib/capybara/spec/public/offset.js +6 -0
  122. data/lib/capybara/spec/public/test.js +105 -6
  123. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  124. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  125. data/lib/capybara/spec/session/all_spec.rb +89 -15
  126. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  127. data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
  128. data/lib/capybara/spec/session/assert_text_spec.rb +26 -22
  129. data/lib/capybara/spec/session/attach_file_spec.rb +64 -31
  130. data/lib/capybara/spec/session/check_spec.rb +26 -4
  131. data/lib/capybara/spec/session/choose_spec.rb +14 -2
  132. data/lib/capybara/spec/session/click_button_spec.rb +109 -61
  133. data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
  134. data/lib/capybara/spec/session/click_link_spec.rb +23 -1
  135. data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
  136. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  137. data/lib/capybara/spec/session/element/matches_selector_spec.rb +40 -39
  138. data/lib/capybara/spec/session/evaluate_script_spec.rb +12 -0
  139. data/lib/capybara/spec/session/fill_in_spec.rb +46 -5
  140. data/lib/capybara/spec/session/find_link_spec.rb +10 -0
  141. data/lib/capybara/spec/session/find_spec.rb +80 -7
  142. data/lib/capybara/spec/session/first_spec.rb +2 -2
  143. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +14 -1
  144. data/lib/capybara/spec/session/frame/within_frame_spec.rb +14 -1
  145. data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
  146. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  147. data/lib/capybara/spec/session/has_any_selectors_spec.rb +6 -2
  148. data/lib/capybara/spec/session/has_button_spec.rb +81 -0
  149. data/lib/capybara/spec/session/has_css_spec.rb +45 -8
  150. data/lib/capybara/spec/session/has_current_path_spec.rb +22 -7
  151. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  152. data/lib/capybara/spec/session/has_field_spec.rb +59 -1
  153. data/lib/capybara/spec/session/has_link_spec.rb +40 -0
  154. data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
  155. data/lib/capybara/spec/session/has_select_spec.rb +42 -8
  156. data/lib/capybara/spec/session/has_selector_spec.rb +19 -4
  157. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  158. data/lib/capybara/spec/session/has_table_spec.rb +177 -0
  159. data/lib/capybara/spec/session/has_text_spec.rb +31 -3
  160. data/lib/capybara/spec/session/html_spec.rb +1 -1
  161. data/lib/capybara/spec/session/matches_style_spec.rb +6 -4
  162. data/lib/capybara/spec/session/node_spec.rb +697 -23
  163. data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
  164. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  165. data/lib/capybara/spec/session/reset_session_spec.rb +21 -7
  166. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  167. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  168. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  169. data/lib/capybara/spec/session/scroll_spec.rb +9 -7
  170. data/lib/capybara/spec/session/select_spec.rb +5 -10
  171. data/lib/capybara/spec/session/selectors_spec.rb +24 -3
  172. data/lib/capybara/spec/session/uncheck_spec.rb +3 -3
  173. data/lib/capybara/spec/session/unselect_spec.rb +1 -1
  174. data/lib/capybara/spec/session/visit_spec.rb +20 -0
  175. data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
  176. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  177. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  178. data/lib/capybara/spec/session/window/window_spec.rb +54 -57
  179. data/lib/capybara/spec/session/window/windows_spec.rb +2 -2
  180. data/lib/capybara/spec/session/within_spec.rb +36 -0
  181. data/lib/capybara/spec/spec_helper.rb +30 -19
  182. data/lib/capybara/spec/test_app.rb +122 -34
  183. data/lib/capybara/spec/views/animated.erb +49 -0
  184. data/lib/capybara/spec/views/form.erb +86 -8
  185. data/lib/capybara/spec/views/frame_child.erb +3 -2
  186. data/lib/capybara/spec/views/frame_one.erb +2 -1
  187. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  188. data/lib/capybara/spec/views/frame_two.erb +1 -1
  189. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  190. data/lib/capybara/spec/views/layout.erb +10 -0
  191. data/lib/capybara/spec/views/obscured.erb +10 -10
  192. data/lib/capybara/spec/views/offset.erb +33 -0
  193. data/lib/capybara/spec/views/path.erb +2 -2
  194. data/lib/capybara/spec/views/popup_one.erb +1 -1
  195. data/lib/capybara/spec/views/popup_two.erb +1 -1
  196. data/lib/capybara/spec/views/react.erb +45 -0
  197. data/lib/capybara/spec/views/scroll.erb +2 -1
  198. data/lib/capybara/spec/views/spatial.erb +31 -0
  199. data/lib/capybara/spec/views/tables.erb +67 -0
  200. data/lib/capybara/spec/views/with_animation.erb +39 -4
  201. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  202. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  203. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  204. data/lib/capybara/spec/views/with_hover.erb +3 -2
  205. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  206. data/lib/capybara/spec/views/with_html.erb +34 -6
  207. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  208. data/lib/capybara/spec/views/with_js.erb +7 -4
  209. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  210. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  211. data/lib/capybara/spec/views/with_scope.erb +2 -2
  212. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  213. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  214. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  215. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  216. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  217. data/lib/capybara/spec/views/with_windows.erb +1 -1
  218. data/lib/capybara/spec/views/within_frames.erb +1 -1
  219. data/lib/capybara/version.rb +1 -1
  220. data/lib/capybara/window.rb +14 -18
  221. data/lib/capybara.rb +91 -126
  222. data/spec/basic_node_spec.rb +30 -16
  223. data/spec/capybara_spec.rb +40 -28
  224. data/spec/counter_spec.rb +35 -0
  225. data/spec/css_builder_spec.rb +3 -1
  226. data/spec/css_splitter_spec.rb +1 -1
  227. data/spec/dsl_spec.rb +33 -22
  228. data/spec/filter_set_spec.rb +5 -5
  229. data/spec/fixtures/selenium_driver_rspec_failure.rb +3 -3
  230. data/spec/fixtures/selenium_driver_rspec_success.rb +3 -3
  231. data/spec/minitest_spec.rb +24 -2
  232. data/spec/minitest_spec_spec.rb +60 -45
  233. data/spec/per_session_config_spec.rb +1 -1
  234. data/spec/rack_test_spec.rb +131 -98
  235. data/spec/regexp_dissassembler_spec.rb +53 -39
  236. data/spec/result_spec.rb +68 -66
  237. data/spec/rspec/features_spec.rb +9 -4
  238. data/spec/rspec/scenarios_spec.rb +6 -2
  239. data/spec/rspec/shared_spec_matchers.rb +137 -98
  240. data/spec/rspec_matchers_spec.rb +25 -0
  241. data/spec/rspec_spec.rb +23 -21
  242. data/spec/sauce_spec_chrome.rb +43 -0
  243. data/spec/selector_spec.rb +77 -21
  244. data/spec/selenium_spec_chrome.rb +141 -39
  245. data/spec/selenium_spec_chrome_remote.rb +32 -17
  246. data/spec/selenium_spec_edge.rb +36 -8
  247. data/spec/selenium_spec_firefox.rb +110 -68
  248. data/spec/selenium_spec_firefox_remote.rb +22 -15
  249. data/spec/selenium_spec_ie.rb +29 -22
  250. data/spec/selenium_spec_safari.rb +162 -0
  251. data/spec/server_spec.rb +153 -81
  252. data/spec/session_spec.rb +11 -4
  253. data/spec/shared_selenium_node.rb +79 -0
  254. data/spec/shared_selenium_session.rb +179 -74
  255. data/spec/spec_helper.rb +80 -5
  256. data/spec/whitespace_normalizer_spec.rb +54 -0
  257. data/spec/xpath_builder_spec.rb +3 -1
  258. metadata +218 -30
  259. data/lib/capybara/spec/session/source_spec.rb +0 -0
  260. data/lib/capybara/spec/views/with_title.erb +0 -5
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Capybara::SpecHelper.spec '#attach_file' do
4
+ let(:test_file_path) { File.expand_path('../fixtures/test_file.txt', File.dirname(__FILE__)) }
5
+ let(:another_test_file_path) { File.expand_path('../fixtures/another_test_file.txt', File.dirname(__FILE__)) }
6
+ let(:test_jpg_file_path) { File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__)) }
7
+ let(:no_extension_file_path) { File.expand_path('../fixtures/no_extension', File.dirname(__FILE__)) }
8
+
4
9
  before do
5
- @test_file_path = File.expand_path('../fixtures/test_file.txt', File.dirname(__FILE__))
6
- @another_test_file_path = File.expand_path('../fixtures/another_test_file.txt', File.dirname(__FILE__))
7
- @test_jpg_file_path = File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))
8
- @no_extension_file_path = File.expand_path('../fixtures/no_extension', File.dirname(__FILE__))
9
10
  @session.visit('/form')
10
11
  end
11
12
 
@@ -38,15 +39,15 @@ Capybara::SpecHelper.spec '#attach_file' do
38
39
 
39
40
  context 'with multipart form' do
40
41
  it 'should set a file path by id' do
41
- @session.attach_file 'form_document', with_os_path_separators(@test_file_path)
42
+ @session.attach_file 'form_document', with_os_path_separators(test_file_path)
42
43
  @session.click_button('Upload Single')
43
- expect(@session).to have_content(File.read(@test_file_path))
44
+ expect(@session).to have_content(File.read(test_file_path))
44
45
  end
45
46
 
46
47
  it 'should set a file path by label' do
47
- @session.attach_file 'Single Document', with_os_path_separators(@test_file_path)
48
+ @session.attach_file 'Single Document', with_os_path_separators(test_file_path)
48
49
  @session.click_button('Upload Single')
49
- expect(@session).to have_content(File.read(@test_file_path))
50
+ expect(@session).to have_content(File.read(test_file_path))
50
51
  end
51
52
 
52
53
  it 'should not break if no file is submitted' do
@@ -54,38 +55,44 @@ Capybara::SpecHelper.spec '#attach_file' do
54
55
  expect(@session).to have_content('No file uploaded')
55
56
  end
56
57
 
58
+ it 'should send prior hidden field if no file submitted' do
59
+ @session.click_button('Upload Empty With Hidden')
60
+ expect(extract_results(@session)['document2']).to eq('hidden_field')
61
+ expect(extract_content_type(@session)).to start_with('multipart/form-data;')
62
+ end
63
+
57
64
  it 'should send content type text/plain when uploading a text file' do
58
- @session.attach_file 'Single Document', with_os_path_separators(@test_file_path)
65
+ @session.attach_file 'Single Document', with_os_path_separators(test_file_path)
59
66
  @session.click_button 'Upload Single'
60
67
  expect(@session).to have_content('text/plain')
61
68
  end
62
69
 
63
70
  it 'should send content type image/jpeg when uploading an image' do
64
- @session.attach_file 'Single Document', with_os_path_separators(@test_jpg_file_path)
71
+ @session.attach_file 'Single Document', with_os_path_separators(test_jpg_file_path)
65
72
  @session.click_button 'Upload Single'
66
73
  expect(@session).to have_content('image/jpeg')
67
74
  end
68
75
 
69
76
  it 'should not break when uploading a file without extension' do
70
- @session.attach_file 'Single Document', with_os_path_separators(@no_extension_file_path)
77
+ @session.attach_file 'Single Document', with_os_path_separators(no_extension_file_path)
71
78
  @session.click_button 'Upload Single'
72
- expect(@session).to have_content(File.read(@no_extension_file_path))
79
+ expect(@session).to have_content(File.read(no_extension_file_path))
73
80
  end
74
81
 
75
82
  it 'should not break when using HTML5 multiple file input' do
76
- @session.attach_file 'Multiple Documents', with_os_path_separators(@test_file_path)
83
+ @session.attach_file 'Multiple Documents', with_os_path_separators(test_file_path)
77
84
  @session.click_button('Upload Multiple')
78
- expect(@session).to have_content(File.read(@test_file_path))
85
+ expect(@session).to have_content(File.read(test_file_path))
79
86
  expect(@session.body).to include('1 | ') # number of files
80
87
  end
81
88
 
82
89
  it 'should not break when using HTML5 multiple file input uploading multiple files' do
83
90
  @session.attach_file('Multiple Documents',
84
- [@test_file_path, @another_test_file_path].map { |f| with_os_path_separators(f) })
91
+ [test_file_path, another_test_file_path].map { |f| with_os_path_separators(f) })
85
92
  @session.click_button('Upload Multiple')
86
- expect(@session.body).to include('2 | ') # number of files
87
- expect(@session.body).to include(File.read(@test_file_path))
88
- expect(@session.body).to include(File.read(@another_test_file_path))
93
+ expect(@session).to have_content('2 | ') # number of files
94
+ expect(@session.body).to include(File.read(test_file_path))
95
+ expect(@session.body).to include(File.read(another_test_file_path))
89
96
  end
90
97
 
91
98
  it 'should not send anything when attaching no files to a multiple upload field' do
@@ -94,35 +101,35 @@ Capybara::SpecHelper.spec '#attach_file' do
94
101
  end
95
102
 
96
103
  it 'should not append files to already attached' do
97
- @session.attach_file 'Multiple Documents', with_os_path_separators(@test_file_path)
98
- @session.attach_file 'Multiple Documents', with_os_path_separators(@another_test_file_path)
104
+ @session.attach_file 'Multiple Documents', with_os_path_separators(test_file_path)
105
+ @session.attach_file 'Multiple Documents', with_os_path_separators(another_test_file_path)
99
106
  @session.click_button('Upload Multiple')
100
- expect(@session.body).to include('1 | ') # number of files
101
- expect(@session.body).to include(File.read(@another_test_file_path))
102
- expect(@session.body).not_to include(File.read(@test_file_path))
107
+ expect(@session).to have_content('1 | ') # number of files
108
+ expect(@session.body).to include(File.read(another_test_file_path))
109
+ expect(@session.body).not_to include(File.read(test_file_path))
103
110
  end
104
111
 
105
112
  it 'should fire change once when uploading multiple files from empty', requires: [:js] do
106
113
  @session.visit('with_js')
107
114
  @session.attach_file('multiple-file',
108
- [@test_file_path, @another_test_file_path].map { |f| with_os_path_separators(f) })
115
+ [test_file_path, another_test_file_path].map { |f| with_os_path_separators(f) })
109
116
  expect(@session).to have_css('.file_change', count: 1)
110
117
  end
111
118
 
112
119
  it 'should fire change once for each set of files uploaded', requires: [:js] do
113
120
  @session.visit('with_js')
114
- @session.attach_file('multiple-file', [@test_jpg_file_path].map { |f| with_os_path_separators(f) })
121
+ @session.attach_file('multiple-file', [test_jpg_file_path].map { |f| with_os_path_separators(f) })
115
122
  @session.attach_file('multiple-file',
116
- [@test_file_path, @another_test_file_path].map { |f| with_os_path_separators(f) })
123
+ [test_file_path, another_test_file_path].map { |f| with_os_path_separators(f) })
117
124
  expect(@session).to have_css('.file_change', count: 2)
118
125
  end
119
126
  end
120
127
 
121
128
  context "with a locator that doesn't exist" do
122
129
  it 'should raise an error' do
123
- msg = 'Unable to find file field "does not exist"'
130
+ msg = /Unable to find file field "does not exist"/
124
131
  expect do
125
- @session.attach_file('does not exist', with_os_path_separators(@test_file_path))
132
+ @session.attach_file('does not exist', with_os_path_separators(test_file_path))
126
133
  end.to raise_error(Capybara::ElementNotFound, msg)
127
134
  end
128
135
  end
@@ -179,11 +186,37 @@ Capybara::SpecHelper.spec '#attach_file' do
179
186
  @session.attach_file('hidden_file', with_os_path_separators(__FILE__), make_visible: true)
180
187
  expect(@session.evaluate_script('arguments[0].style.display', @session.find(:css, '#hidden_file', visible: :all))).to eq 'none'
181
188
  end
189
+
190
+ it 'should fire change' do
191
+ @session.visit('/with_js')
192
+ @session.attach_file('hidden_file', with_os_path_separators(__FILE__), make_visible: true)
193
+ expect(@session).to have_css('.file_change')
194
+ end
182
195
  end
183
196
 
184
- private
197
+ context 'with a block', requires: %i[js] do
198
+ it 'can upload by clicking the file input' do
199
+ @session.attach_file(with_os_path_separators(__FILE__)) do
200
+ @session.find(:file_field, 'form[image]').click
201
+ end
202
+ @session.click_button('awesome')
203
+ expect(extract_results(@session)['image']).to end_with(File.basename(__FILE__))
204
+ end
205
+
206
+ it 'can upload by clicking the label' do
207
+ @session.attach_file(with_os_path_separators(__FILE__)) do
208
+ @session.find(:label, 'Hidden Image').click
209
+ end
210
+ @session.click_button('awesome')
211
+ expect(extract_results(@session)['hidden_image']).to end_with(File.basename(__FILE__))
212
+ end
185
213
 
186
- def with_os_path_separators(path)
187
- Gem.win_platform? ? path.to_s.tr('/', '\\') : path.to_s
214
+ it 'should fire change' do
215
+ @session.visit('/with_js')
216
+ @session.attach_file(with_os_path_separators(__FILE__)) do
217
+ @session.find(:label, 'Label for hidden file input').click
218
+ end
219
+ expect(@session).to have_css('.file_change')
220
+ end
188
221
  end
189
222
  end
@@ -83,7 +83,7 @@ Capybara::SpecHelper.spec '#check' do
83
83
 
84
84
  context "with a locator that doesn't exist" do
85
85
  it 'should raise an error' do
86
- msg = 'Unable to find checkbox "does not exist"'
86
+ msg = /Unable to find checkbox "does not exist"/
87
87
  expect do
88
88
  @session.check('does not exist')
89
89
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -120,6 +120,12 @@ Capybara::SpecHelper.spec '#check' do
120
120
  expect(extract_results(@session)['pets']).to include('cat')
121
121
  end
122
122
 
123
+ it 'should alias `with`' do
124
+ @session.check('form[pets][]', with: 'cat')
125
+ @session.click_button('awesome')
126
+ expect(extract_results(@session)['pets']).to include('cat')
127
+ end
128
+
123
129
  it 'should raise an error if option not found' do
124
130
  expect do
125
131
  @session.check('form[pets][]', option: 'elephant')
@@ -171,11 +177,11 @@ Capybara::SpecHelper.spec '#check' do
171
177
  end
172
178
 
173
179
  it 'should raise original error when no label available' do
174
- expect { @session.check('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, 'Unable to find visible checkbox "form_cars_ariel"')
180
+ expect { @session.check('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, /Unable to find visible checkbox "form_cars_ariel"/)
175
181
  end
176
182
 
177
183
  it 'should raise error if not allowed to click label' do
178
- expect { @session.check('form_cars_mclaren', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound, 'Unable to find visible checkbox "form_cars_mclaren"')
184
+ expect { @session.check('form_cars_mclaren', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound, /Unable to find visible checkbox "form_cars_mclaren"/)
179
185
  end
180
186
  end
181
187
 
@@ -187,7 +193,7 @@ Capybara::SpecHelper.spec '#check' do
187
193
  end
188
194
 
189
195
  it 'should raise error if checkbox not visible' do
190
- expect { @session.check('form_cars_mclaren') }.to raise_error(Capybara::ElementNotFound, 'Unable to find visible checkbox "form_cars_mclaren"')
196
+ expect { @session.check('form_cars_mclaren') }.to raise_error(Capybara::ElementNotFound, /Unable to find visible checkbox "form_cars_mclaren"/)
191
197
  end
192
198
 
193
199
  it 'should include node filter in error if verified' do
@@ -223,6 +229,22 @@ Capybara::SpecHelper.spec '#check' do
223
229
  @session.click_button('awesome')
224
230
  expect(extract_results(@session)['cars']).to include('bugatti')
225
231
  end
232
+
233
+ it 'should check via label if multiple labels' do
234
+ expect(@session).to have_field('multi_label_checkbox', checked: false, visible: :hidden)
235
+ @session.check('Label to click', allow_label_click: true)
236
+ expect(@session).to have_field('multi_label_checkbox', checked: true, visible: :hidden)
237
+ end
238
+ end
239
+
240
+ context 'with allow_label_click options', requires: [:js] do
241
+ it 'should allow offsets to click location on label' do
242
+ Capybara.w3c_click_offset = false
243
+ expect(@session.find(:checkbox, 'form_cars_lotus', unchecked: true, visible: :hidden)).to be_truthy
244
+ @session.check('form_cars_lotus', allow_label_click: { x: 90, y: 10 })
245
+ @session.click_button('awesome')
246
+ expect(extract_results(@session)['cars']).to include('lotus')
247
+ end
226
248
  end
227
249
  end
228
250
  end
@@ -11,6 +11,12 @@ Capybara::SpecHelper.spec '#choose' do
11
11
  expect(extract_results(@session)['gender']).to eq('male')
12
12
  end
13
13
 
14
+ it 'ignores readonly attribute on radio buttons' do
15
+ @session.choose('gender_both')
16
+ @session.click_button('awesome')
17
+ expect(extract_results(@session)['gender']).to eq('both')
18
+ end
19
+
14
20
  it 'should choose a radio button by label' do
15
21
  @session.choose('Both')
16
22
  @session.click_button('awesome')
@@ -38,7 +44,7 @@ Capybara::SpecHelper.spec '#choose' do
38
44
 
39
45
  context "with a locator that doesn't exist" do
40
46
  it 'should raise an error' do
41
- msg = 'Unable to find radio button "does not exist"'
47
+ msg = /Unable to find radio button "does not exist"/
42
48
  expect do
43
49
  @session.choose('does not exist')
44
50
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -74,6 +80,12 @@ Capybara::SpecHelper.spec '#choose' do
74
80
  expect(extract_results(@session)['gender']).to eq('male')
75
81
  end
76
82
 
83
+ it 'should alias `:with` option' do
84
+ @session.choose('form[gender]', with: 'male')
85
+ @session.click_button('awesome')
86
+ expect(extract_results(@session)['gender']).to eq('male')
87
+ end
88
+
77
89
  it 'should raise an error if option not found' do
78
90
  expect do
79
91
  @session.choose('form[gender]', option: 'hermaphrodite')
@@ -103,7 +115,7 @@ Capybara::SpecHelper.spec '#choose' do
103
115
  end
104
116
 
105
117
  it 'should raise error if not allowed to click label' do
106
- expect { @session.choose('party_democrat', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound, 'Unable to find visible radio button "party_democrat"')
118
+ expect { @session.choose('party_democrat', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound, /Unable to find visible radio button "party_democrat"/)
107
119
  end
108
120
  end
109
121
  end
@@ -45,111 +45,113 @@ Capybara::SpecHelper.spec '#click_button' do
45
45
 
46
46
  context 'with value given on a submit button' do
47
47
  context 'on a form with HTML5 fields' do
48
+ let(:results) { extract_results(@session) }
49
+
48
50
  before do
49
51
  @session.click_button('html5_submit')
50
- @results = extract_results(@session)
51
52
  end
52
53
 
53
54
  it 'should serialise and submit search fields' do
54
- expect(@results['html5_search']).to eq('what are you looking for')
55
+ expect(results['html5_search']).to eq('what are you looking for')
55
56
  end
56
57
 
57
58
  it 'should serialise and submit email fields' do
58
- expect(@results['html5_email']).to eq('person@email.com')
59
+ expect(results['html5_email']).to eq('person@email.com')
59
60
  end
60
61
 
61
62
  it 'should serialise and submit url fields' do
62
- expect(@results['html5_url']).to eq('http://www.example.com')
63
+ expect(results['html5_url']).to eq('http://www.example.com')
63
64
  end
64
65
 
65
66
  it 'should serialise and submit tel fields' do
66
- expect(@results['html5_tel']).to eq('911')
67
+ expect(results['html5_tel']).to eq('911')
67
68
  end
68
69
 
69
70
  it 'should serialise and submit color fields' do
70
- expect(@results['html5_color'].upcase).to eq('#FFFFFF')
71
+ expect(results['html5_color'].upcase).to eq('#FFFFFF')
71
72
  end
72
73
  end
73
74
 
74
75
  context 'on an HTML4 form' do
76
+ let(:results) { extract_results(@session) }
77
+
75
78
  before do
76
79
  @session.click_button('awesome')
77
- @results = extract_results(@session)
78
80
  end
79
81
 
80
82
  it 'should serialize and submit text fields' do
81
- expect(@results['first_name']).to eq('John')
83
+ expect(results['first_name']).to eq('John')
82
84
  end
83
85
 
84
86
  it 'should escape fields when submitting' do
85
- expect(@results['phone']).to eq('+1 555 7021')
87
+ expect(results['phone']).to eq('+1 555 7021')
86
88
  end
87
89
 
88
90
  it 'should serialize and submit password fields' do
89
- expect(@results['password']).to eq('seeekrit')
91
+ expect(results['password']).to eq('seeekrit')
90
92
  end
91
93
 
92
94
  it 'should serialize and submit hidden fields' do
93
- expect(@results['token']).to eq('12345')
95
+ expect(results['token']).to eq('12345')
94
96
  end
95
97
 
96
98
  it 'should not serialize fields from other forms' do
97
- expect(@results['middle_name']).to be_nil
99
+ expect(results['middle_name']).to be_nil
98
100
  end
99
101
 
100
102
  it 'should submit the button that was clicked, but not other buttons' do
101
- expect(@results['awesome']).to eq('awesome')
102
- expect(@results['crappy']).to be_nil
103
+ expect(results['awesome']).to eq('awesome')
104
+ expect(results['crappy']).to be_nil
103
105
  end
104
106
 
105
107
  it 'should serialize radio buttons' do
106
- expect(@results['gender']).to eq('female')
108
+ expect(results['gender']).to eq('female')
107
109
  end
108
110
 
109
111
  it "should default radio value to 'on' if none specified" do
110
- expect(@results['valueless_radio']).to eq('on')
112
+ expect(results['valueless_radio']).to eq('on')
111
113
  end
112
114
 
113
115
  it 'should serialize check boxes' do
114
- expect(@results['pets']).to include('dog', 'hamster')
115
- expect(@results['pets']).not_to include('cat')
116
+ expect(results['pets']).to include('dog', 'hamster')
117
+ expect(results['pets']).not_to include('cat')
116
118
  end
117
119
 
118
120
  it "should default checkbox value to 'on' if none specififed" do
119
- expect(@results['valueless_checkbox']).to eq('on')
121
+ expect(results['valueless_checkbox']).to eq('on')
120
122
  end
121
123
 
122
124
  it 'should serialize text areas' do
123
- expect(@results['description']).to eq('Descriptive text goes here')
125
+ expect(results['description']).to eq('Descriptive text goes here')
124
126
  end
125
127
 
126
128
  it 'should serialize select tag with values' do
127
- expect(@results['locale']).to eq('en')
129
+ expect(results['locale']).to eq('en')
128
130
  end
129
131
 
130
132
  it 'should serialize select tag without values' do
131
- expect(@results['region']).to eq('Norway')
133
+ expect(results['region']).to eq('Norway')
132
134
  end
133
135
 
134
136
  it 'should serialize first option for select tag with no selection' do
135
- expect(@results['city']).to eq('London')
137
+ expect(results['city']).to eq('London')
136
138
  end
137
139
 
138
140
  it 'should not serialize a select tag without options' do
139
- expect(@results['tendency']).to be_nil
141
+ expect(results['tendency']).to be_nil
140
142
  end
141
143
 
142
144
  it 'should convert lf to cr/lf in submitted textareas' do
143
- expect(@results['newline']).to eq("\r\nNew line after and before textarea tag\r\n")
145
+ expect(results['newline']).to eq("\r\nNew line after and before textarea tag\r\n")
144
146
  end
145
147
 
146
148
  it 'should not submit disabled fields' do
147
- expect(@results['disabled_text_field']).to be_nil
148
- expect(@results['disabled_textarea']).to be_nil
149
- expect(@results['disabled_checkbox']).to be_nil
150
- expect(@results['disabled_radio']).to be_nil
151
- expect(@results['disabled_select']).to be_nil
152
- expect(@results['disabled_file']).to be_nil
149
+ expect(results['disabled_text_field']).to be_nil
150
+ expect(results['disabled_textarea']).to be_nil
151
+ expect(results['disabled_checkbox']).to be_nil
152
+ expect(results['disabled_radio']).to be_nil
153
+ expect(results['disabled_select']).to be_nil
154
+ expect(results['disabled_file']).to be_nil
153
155
  end
154
156
  end
155
157
  end
@@ -160,6 +162,11 @@ Capybara::SpecHelper.spec '#click_button' do
160
162
  expect(extract_results(@session)['first_name']).to eq('John')
161
163
  end
162
164
 
165
+ it 'should submit by specific button id' do
166
+ @session.click_button(id: 'awe123')
167
+ expect(extract_results(@session)['first_name']).to eq('John')
168
+ end
169
+
163
170
  it 'should submit by button title' do
164
171
  @session.click_button('What an Awesome Button')
165
172
  expect(extract_results(@session)['first_name']).to eq('John')
@@ -169,60 +176,89 @@ Capybara::SpecHelper.spec '#click_button' do
169
176
  @session.click_button('What an Awesome')
170
177
  expect(extract_results(@session)['first_name']).to eq('John')
171
178
  end
179
+
180
+ it 'should submit by button name' do
181
+ @session.click_button('form[awesome]')
182
+ expect(extract_results(@session)['first_name']).to eq('John')
183
+ end
184
+
185
+ it 'should submit by specific button name' do
186
+ @session.click_button(name: 'form[awesome]')
187
+ expect(extract_results(@session)['first_name']).to eq('John')
188
+ end
189
+
190
+ it 'should submit by specific button name regex' do
191
+ @session.click_button(name: /form\[awes.*\]/)
192
+ expect(extract_results(@session)['first_name']).to eq('John')
193
+ end
194
+ end
195
+
196
+ context 'when Capybara.enable_aria_role = true' do
197
+ it 'should click on a button role', requires: [:js] do
198
+ Capybara.enable_aria_role = true
199
+ @session.using_wait_time(1.5) do
200
+ @session.visit('/with_js')
201
+ @session.click_button('ARIA button')
202
+ expect(@session).to have_button('ARIA button has been clicked')
203
+ end
204
+ end
172
205
  end
173
206
 
174
207
  context 'with fields associated with the form using the form attribute', requires: [:form_attribute] do
208
+ let(:results) { extract_results(@session) }
209
+
175
210
  before do
176
211
  @session.click_button('submit_form1')
177
- @results = extract_results(@session)
178
212
  end
179
213
 
180
214
  it 'should serialize and submit text fields' do
181
- expect(@results['outside_input']).to eq('outside_input')
215
+ expect(results['outside_input']).to eq('outside_input')
182
216
  end
183
217
 
184
218
  it 'should serialize text areas' do
185
- expect(@results['outside_textarea']).to eq('Some text here')
219
+ expect(results['outside_textarea']).to eq('Some text here')
186
220
  end
187
221
 
188
222
  it 'should serialize select tags' do
189
- expect(@results['outside_select']).to eq('Ruby')
223
+ expect(results['outside_select']).to eq('Ruby')
190
224
  end
191
225
 
192
226
  it 'should not serliaze fields associated with a different form' do
193
- expect(@results['for_form2']).to be_nil
227
+ expect(results['for_form2']).to be_nil
194
228
  end
195
229
  end
196
230
 
197
231
  context 'with submit button outside the form defined by <button> tag', requires: [:form_attribute] do
232
+ let(:results) { extract_results(@session) }
233
+
198
234
  before do
199
235
  @session.click_button('outside_button')
200
- @results = extract_results(@session)
201
236
  end
202
237
 
203
238
  it 'should submit the associated form' do
204
- expect(@results['which_form']).to eq('form2')
239
+ expect(results['which_form']).to eq('form2')
205
240
  end
206
241
 
207
242
  it 'should submit the button that was clicked, but not other buttons' do
208
- expect(@results['outside_button']).to eq('outside_button')
209
- expect(@results['unused']).to be_nil
243
+ expect(results['outside_button']).to eq('outside_button')
244
+ expect(results['unused']).to be_nil
210
245
  end
211
246
  end
212
247
 
213
248
  context "with submit button outside the form defined by <input type='submit'> tag", requires: [:form_attribute] do
249
+ let(:results) { extract_results(@session) }
250
+
214
251
  before do
215
252
  @session.click_button('outside_submit')
216
- @results = extract_results(@session)
217
253
  end
218
254
 
219
255
  it 'should submit the associated form' do
220
- expect(@results['which_form']).to eq('form1')
256
+ expect(results['which_form']).to eq('form1')
221
257
  end
222
258
 
223
259
  it 'should submit the button that was clicked, but not other buttons' do
224
- expect(@results['outside_submit']).to eq('outside_submit')
225
- expect(@results['submit_form1']).to be_nil
260
+ expect(results['outside_submit']).to eq('outside_submit')
261
+ expect(results['submit_form1']).to be_nil
226
262
  end
227
263
  end
228
264
 
@@ -303,9 +339,21 @@ Capybara::SpecHelper.spec '#click_button' do
303
339
  it 'should serialize and send GET forms' do
304
340
  @session.visit('/form')
305
341
  @session.click_button('med')
306
- @results = extract_results(@session)
307
- expect(@results['middle_name']).to eq('Darren')
308
- expect(@results['foo']).to be_nil
342
+ results = extract_results(@session)
343
+ expect(results['middle_name']).to eq('Darren')
344
+ expect(results['foo']).to be_nil
345
+ end
346
+ end
347
+
348
+ context 'with name given on a button defined by <button> tag' do
349
+ it 'should submit the associated form when name is locator' do
350
+ @session.click_button('form[no_value]')
351
+ expect(extract_results(@session)['first_name']).to eq('John')
352
+ end
353
+
354
+ it 'should submit the associated form when name is specific' do
355
+ @session.click_button(name: 'form[no_value]')
356
+ expect(extract_results(@session)['first_name']).to eq('John')
309
357
  end
310
358
  end
311
359
 
@@ -347,7 +395,7 @@ Capybara::SpecHelper.spec '#click_button' do
347
395
 
348
396
  context "with a locator that doesn't exist" do
349
397
  it 'should raise an error' do
350
- msg = 'Unable to find button "does not exist"'
398
+ msg = /Unable to find button "does not exist"/
351
399
  expect do
352
400
  @session.click_button('does not exist')
353
401
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -357,45 +405,45 @@ Capybara::SpecHelper.spec '#click_button' do
357
405
  context 'with formaction attribute on button' do
358
406
  it 'should submit to the formaction attribute' do
359
407
  @session.click_button('Formaction button')
360
- @results = extract_results(@session)
408
+ results = extract_results(@session)
361
409
  expect(@session.current_path).to eq '/form'
362
- expect(@results['which_form']).to eq 'formaction form'
410
+ expect(results['which_form']).to eq 'formaction form'
363
411
  end
364
412
  end
365
413
 
366
414
  context 'with formmethod attribute on button' do
367
415
  it 'should submit to the formethod attribute' do
368
416
  @session.click_button('Formmethod button')
369
- @results = extract_results(@session)
417
+ results = extract_results(@session)
370
418
  expect(@session.current_path).to eq '/form/get'
371
- expect(@results['which_form']).to eq 'formaction form'
419
+ expect(results['which_form']).to eq 'formaction form'
372
420
  end
373
421
  end
374
422
 
375
423
  it 'should serialize and send valueless buttons that were clicked' do
376
424
  @session.click_button('No Value!')
377
- @results = extract_results(@session)
378
- expect(@results['no_value']).not_to be_nil
425
+ results = extract_results(@session)
426
+ expect(results['no_value']).not_to be_nil
379
427
  end
380
428
 
381
429
  it 'should send button in document order' do
382
430
  @session.click_button('outside_button')
383
- @results = extract_results(@session)
384
- expect(@results.keys).to eq %w[for_form2 outside_button which_form post_count]
431
+ results = extract_results(@session)
432
+ expect(results.keys).to eq %w[for_form2 outside_button which_form post_count]
385
433
  end
386
434
 
387
435
  it 'should not send image buttons that were not clicked' do
388
436
  @session.click_button('Click me!')
389
- @results = extract_results(@session)
390
- expect(@results['okay']).to be_nil
437
+ results = extract_results(@session)
438
+ expect(results['okay']).to be_nil
391
439
  end
392
440
 
393
441
  it 'should serialize and send GET forms' do
394
442
  @session.visit('/form')
395
443
  @session.click_button('med')
396
- @results = extract_results(@session)
397
- expect(@results['middle_name']).to eq('Darren')
398
- expect(@results['foo']).to be_nil
444
+ results = extract_results(@session)
445
+ expect(results['middle_name']).to eq('Darren')
446
+ expect(results['foo']).to be_nil
399
447
  end
400
448
 
401
449
  it 'should follow redirects' do
@@ -38,6 +38,15 @@ Capybara::SpecHelper.spec '#click_link_or_button' do
38
38
  expect(extract_results(@session)['first_name']).to eq('John')
39
39
  end
40
40
 
41
+ context 'with test_id' do
42
+ it 'should click on a button' do
43
+ Capybara.test_id = 'data-test-id'
44
+ @session.visit('/form')
45
+ @session.click_link_or_button('test_id_button')
46
+ expect(extract_results(@session)['first_name']).to eq('John')
47
+ end
48
+ end
49
+
41
50
  context 'with :exact option' do
42
51
  context 'when `false`' do
43
52
  it 'clicks on approximately matching link' do