capybara 3.8.1 → 3.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (242) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +465 -0
  4. data/License.txt +1 -1
  5. data/README.md +58 -57
  6. data/lib/capybara/config.rb +10 -4
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/base.rb +2 -2
  9. data/lib/capybara/driver/node.rb +26 -5
  10. data/lib/capybara/dsl.rb +12 -4
  11. data/lib/capybara/helpers.rb +8 -4
  12. data/lib/capybara/minitest/spec.rb +162 -85
  13. data/lib/capybara/minitest.rb +248 -148
  14. data/lib/capybara/node/actions.rb +149 -96
  15. data/lib/capybara/node/base.rb +27 -10
  16. data/lib/capybara/node/document.rb +12 -0
  17. data/lib/capybara/node/document_matchers.rb +9 -5
  18. data/lib/capybara/node/element.rb +254 -109
  19. data/lib/capybara/node/finders.rb +83 -76
  20. data/lib/capybara/node/matchers.rb +279 -141
  21. data/lib/capybara/node/simple.rb +25 -6
  22. data/lib/capybara/queries/ancestor_query.rb +5 -7
  23. data/lib/capybara/queries/base_query.rb +11 -5
  24. data/lib/capybara/queries/current_path_query.rb +3 -3
  25. data/lib/capybara/queries/match_query.rb +1 -0
  26. data/lib/capybara/queries/selector_query.rb +467 -103
  27. data/lib/capybara/queries/sibling_query.rb +5 -4
  28. data/lib/capybara/queries/style_query.rb +6 -2
  29. data/lib/capybara/queries/text_query.rb +17 -3
  30. data/lib/capybara/queries/title_query.rb +2 -2
  31. data/lib/capybara/rack_test/browser.rb +22 -15
  32. data/lib/capybara/rack_test/driver.rb +10 -1
  33. data/lib/capybara/rack_test/errors.rb +6 -0
  34. data/lib/capybara/rack_test/form.rb +33 -28
  35. data/lib/capybara/rack_test/node.rb +74 -6
  36. data/lib/capybara/registration_container.rb +44 -0
  37. data/lib/capybara/registrations/drivers.rb +36 -0
  38. data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
  39. data/lib/capybara/registrations/servers.rb +44 -0
  40. data/lib/capybara/result.rb +55 -23
  41. data/lib/capybara/rspec/features.rb +4 -4
  42. data/lib/capybara/rspec/matcher_proxies.rb +36 -15
  43. data/lib/capybara/rspec/matchers/base.rb +111 -0
  44. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  45. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  46. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  47. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  48. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  49. data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
  50. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  51. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  52. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  53. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  54. data/lib/capybara/rspec/matchers/match_style.rb +38 -0
  55. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  56. data/lib/capybara/rspec/matchers.rb +117 -311
  57. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  58. data/lib/capybara/selector/builders/xpath_builder.rb +69 -0
  59. data/lib/capybara/selector/css.rb +17 -15
  60. data/lib/capybara/selector/definition/button.rb +52 -0
  61. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  62. data/lib/capybara/selector/definition/css.rb +10 -0
  63. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  64. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  65. data/lib/capybara/selector/definition/element.rb +27 -0
  66. data/lib/capybara/selector/definition/field.rb +40 -0
  67. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  68. data/lib/capybara/selector/definition/file_field.rb +13 -0
  69. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  70. data/lib/capybara/selector/definition/frame.rb +17 -0
  71. data/lib/capybara/selector/definition/id.rb +6 -0
  72. data/lib/capybara/selector/definition/label.rb +62 -0
  73. data/lib/capybara/selector/definition/link.rb +54 -0
  74. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  75. data/lib/capybara/selector/definition/option.rb +27 -0
  76. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  77. data/lib/capybara/selector/definition/select.rb +81 -0
  78. data/lib/capybara/selector/definition/table.rb +109 -0
  79. data/lib/capybara/selector/definition/table_row.rb +21 -0
  80. data/lib/capybara/selector/definition/xpath.rb +5 -0
  81. data/lib/capybara/selector/definition.rb +277 -0
  82. data/lib/capybara/selector/filter.rb +1 -0
  83. data/lib/capybara/selector/filter_set.rb +26 -19
  84. data/lib/capybara/selector/filters/base.rb +24 -5
  85. data/lib/capybara/selector/filters/expression_filter.rb +3 -3
  86. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  87. data/lib/capybara/selector/filters/node_filter.rb +16 -2
  88. data/lib/capybara/selector/regexp_disassembler.rb +214 -0
  89. data/lib/capybara/selector/selector.rb +73 -367
  90. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  91. data/lib/capybara/selector.rb +221 -480
  92. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  93. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  94. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  95. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  96. data/lib/capybara/selenium/driver.rb +203 -86
  97. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +88 -14
  98. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
  99. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
  100. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  101. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  102. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  103. data/lib/capybara/selenium/extensions/find.rb +110 -0
  104. data/lib/capybara/selenium/extensions/html5_drag.rb +191 -22
  105. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  106. data/lib/capybara/selenium/extensions/scroll.rb +78 -0
  107. data/lib/capybara/selenium/logger_suppressor.rb +34 -0
  108. data/lib/capybara/selenium/node.rb +298 -93
  109. data/lib/capybara/selenium/nodes/chrome_node.rb +100 -8
  110. data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
  111. data/lib/capybara/selenium/nodes/firefox_node.rb +131 -0
  112. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  113. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  114. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  115. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  116. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  117. data/lib/capybara/selenium/patches/logs.rb +45 -0
  118. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -3
  119. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  120. data/lib/capybara/server/animation_disabler.rb +4 -3
  121. data/lib/capybara/server/checker.rb +6 -2
  122. data/lib/capybara/server/middleware.rb +23 -13
  123. data/lib/capybara/server.rb +30 -7
  124. data/lib/capybara/session/config.rb +14 -10
  125. data/lib/capybara/session/matchers.rb +11 -7
  126. data/lib/capybara/session.rb +152 -111
  127. data/lib/capybara/spec/public/offset.js +6 -0
  128. data/lib/capybara/spec/public/test.js +101 -10
  129. data/lib/capybara/spec/session/all_spec.rb +96 -6
  130. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  131. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +29 -0
  132. data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
  133. data/lib/capybara/spec/session/assert_selector_spec.rb +0 -10
  134. data/lib/capybara/spec/session/assert_style_spec.rb +4 -4
  135. data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
  136. data/lib/capybara/spec/session/attach_file_spec.rb +63 -36
  137. data/lib/capybara/spec/session/check_spec.rb +10 -4
  138. data/lib/capybara/spec/session/choose_spec.rb +8 -2
  139. data/lib/capybara/spec/session/click_button_spec.rb +117 -61
  140. data/lib/capybara/spec/session/click_link_or_button_spec.rb +16 -0
  141. data/lib/capybara/spec/session/click_link_spec.rb +17 -6
  142. data/lib/capybara/spec/session/element/matches_selector_spec.rb +40 -39
  143. data/lib/capybara/spec/session/evaluate_script_spec.rb +13 -0
  144. data/lib/capybara/spec/session/execute_script_spec.rb +1 -0
  145. data/lib/capybara/spec/session/fill_in_spec.rb +47 -6
  146. data/lib/capybara/spec/session/find_field_spec.rb +1 -1
  147. data/lib/capybara/spec/session/find_spec.rb +74 -4
  148. data/lib/capybara/spec/session/first_spec.rb +1 -1
  149. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +13 -1
  150. data/lib/capybara/spec/session/frame/within_frame_spec.rb +12 -1
  151. data/lib/capybara/spec/session/has_all_selectors_spec.rb +1 -1
  152. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  153. data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
  154. data/lib/capybara/spec/session/has_button_spec.rb +16 -0
  155. data/lib/capybara/spec/session/has_css_spec.rb +122 -12
  156. data/lib/capybara/spec/session/has_current_path_spec.rb +6 -4
  157. data/lib/capybara/spec/session/has_field_spec.rb +55 -0
  158. data/lib/capybara/spec/session/has_select_spec.rb +34 -6
  159. data/lib/capybara/spec/session/has_selector_spec.rb +11 -4
  160. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  161. data/lib/capybara/spec/session/has_table_spec.rb +166 -0
  162. data/lib/capybara/spec/session/has_text_spec.rb +48 -1
  163. data/lib/capybara/spec/session/has_xpath_spec.rb +17 -0
  164. data/lib/capybara/spec/session/html_spec.rb +7 -0
  165. data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
  166. data/lib/capybara/spec/session/node_spec.rb +643 -18
  167. data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
  168. data/lib/capybara/spec/session/refresh_spec.rb +4 -0
  169. data/lib/capybara/spec/session/reset_session_spec.rb +23 -8
  170. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  171. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  172. data/lib/capybara/spec/session/scroll_spec.rb +117 -0
  173. data/lib/capybara/spec/session/select_spec.rb +10 -10
  174. data/lib/capybara/spec/session/selectors_spec.rb +36 -5
  175. data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
  176. data/lib/capybara/spec/session/unselect_spec.rb +1 -1
  177. data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
  178. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +4 -0
  179. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +4 -0
  180. data/lib/capybara/spec/session/window/window_spec.rb +59 -58
  181. data/lib/capybara/spec/session/window/windows_spec.rb +4 -0
  182. data/lib/capybara/spec/session/within_spec.rb +23 -0
  183. data/lib/capybara/spec/spec_helper.rb +16 -6
  184. data/lib/capybara/spec/test_app.rb +28 -23
  185. data/lib/capybara/spec/views/animated.erb +49 -0
  186. data/lib/capybara/spec/views/form.erb +48 -7
  187. data/lib/capybara/spec/views/frame_child.erb +3 -2
  188. data/lib/capybara/spec/views/frame_one.erb +1 -0
  189. data/lib/capybara/spec/views/obscured.erb +47 -0
  190. data/lib/capybara/spec/views/offset.erb +32 -0
  191. data/lib/capybara/spec/views/react.erb +45 -0
  192. data/lib/capybara/spec/views/scroll.erb +20 -0
  193. data/lib/capybara/spec/views/spatial.erb +31 -0
  194. data/lib/capybara/spec/views/tables.erb +67 -0
  195. data/lib/capybara/spec/views/with_animation.erb +29 -1
  196. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  197. data/lib/capybara/spec/views/with_hover.erb +1 -0
  198. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  199. data/lib/capybara/spec/views/with_html.erb +32 -6
  200. data/lib/capybara/spec/views/with_js.erb +3 -1
  201. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  202. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  203. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  204. data/lib/capybara/version.rb +1 -1
  205. data/lib/capybara/window.rb +11 -11
  206. data/lib/capybara.rb +118 -111
  207. data/spec/basic_node_spec.rb +14 -3
  208. data/spec/capybara_spec.rb +29 -29
  209. data/spec/css_builder_spec.rb +101 -0
  210. data/spec/dsl_spec.rb +46 -21
  211. data/spec/filter_set_spec.rb +5 -5
  212. data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
  213. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  214. data/spec/minitest_spec.rb +18 -4
  215. data/spec/minitest_spec_spec.rb +59 -44
  216. data/spec/rack_test_spec.rb +117 -89
  217. data/spec/regexp_dissassembler_spec.rb +250 -0
  218. data/spec/result_spec.rb +51 -49
  219. data/spec/rspec/features_spec.rb +3 -0
  220. data/spec/rspec/shared_spec_matchers.rb +112 -97
  221. data/spec/rspec_spec.rb +35 -17
  222. data/spec/sauce_spec_chrome.rb +43 -0
  223. data/spec/selector_spec.rb +244 -28
  224. data/spec/selenium_spec_chrome.rb +125 -54
  225. data/spec/selenium_spec_chrome_remote.rb +26 -12
  226. data/spec/selenium_spec_edge.rb +23 -8
  227. data/spec/selenium_spec_firefox.rb +208 -0
  228. data/spec/selenium_spec_firefox_remote.rb +15 -18
  229. data/spec/selenium_spec_ie.rb +82 -13
  230. data/spec/selenium_spec_safari.rb +148 -0
  231. data/spec/server_spec.rb +118 -77
  232. data/spec/session_spec.rb +19 -3
  233. data/spec/shared_selenium_node.rb +83 -0
  234. data/spec/shared_selenium_session.rb +110 -65
  235. data/spec/spec_helper.rb +57 -9
  236. data/spec/xpath_builder_spec.rb +93 -0
  237. metadata +257 -17
  238. data/lib/capybara/rspec/compound.rb +0 -94
  239. data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +0 -49
  240. data/lib/capybara/selenium/nodes/marionette_node.rb +0 -121
  241. data/lib/capybara/spec/session/has_style_spec.rb +0 -25
  242. data/spec/selenium_spec_marionette.rb +0 -172
@@ -11,9 +11,115 @@ Capybara::SpecHelper.spec '#has_table?' do
11
11
  expect(@session).to have_table(:villain_table)
12
12
  end
13
13
 
14
+ it 'should accept rows with column header hashes' do
15
+ expect(@session).to have_table('Horizontal Headers', with_rows:
16
+ [
17
+ { 'First Name' => 'Vern', 'Last Name' => 'Konopelski', 'City' => 'Everette' },
18
+ { 'First Name' => 'Palmer', 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
19
+ ])
20
+ end
21
+
22
+ it 'should accept rows with partial column header hashses' do
23
+ expect(@session).to have_table('Horizontal Headers', with_rows:
24
+ [
25
+ { 'First Name' => 'Thomas' },
26
+ { 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
27
+ ])
28
+ end
29
+
30
+ it 'should accept rows with array of cell values' do
31
+ expect(@session).to have_table('Horizontal Headers', with_rows:
32
+ [
33
+ %w[Thomas Walpole Oceanside],
34
+ ['Ratke', 'Lawrence', 'East Sorayashire']
35
+ ])
36
+ end
37
+
38
+ it 'should consider order of cells in each row' do
39
+ expect(@session).not_to have_table('Horizontal Headers', with_rows:
40
+ [
41
+ %w[Thomas Walpole Oceanside],
42
+ ['Lawrence', 'Ratke', 'East Sorayashire']
43
+ ])
44
+ end
45
+
46
+ it 'should accept all rows with array of cell values' do
47
+ expect(@session).to have_table('Horizontal Headers', rows:
48
+ [
49
+ %w[Thomas Walpole Oceanside],
50
+ %w[Danilo Wilkinson Johnsonville],
51
+ %w[Vern Konopelski Everette],
52
+ ['Ratke', 'Lawrence', 'East Sorayashire'],
53
+ ['Palmer', 'Sawayn', 'West Trinidad']
54
+ ])
55
+ end
56
+
57
+ it 'should match with vertical headers' do
58
+ expect(@session).to have_table('Vertical Headers', with_cols:
59
+ [
60
+ { 'First Name' => 'Thomas' },
61
+ { 'First Name' => 'Danilo', 'Last Name' => 'Wilkinson', 'City' => 'Johnsonville' },
62
+ { 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
63
+ ])
64
+ end
65
+
66
+ it 'should match col with array of cell values' do
67
+ expect(@session).to have_table('Vertical Headers', with_cols:
68
+ [
69
+ %w[Vern Konopelski Everette]
70
+ ])
71
+ end
72
+
73
+ it 'should match cols with array of cell values' do
74
+ expect(@session).to have_table('Vertical Headers', with_cols:
75
+ [
76
+ %w[Danilo Wilkinson Johnsonville],
77
+ %w[Vern Konopelski Everette]
78
+ ])
79
+ end
80
+
81
+ it 'should match all cols with array of cell values' do
82
+ expect(@session).to have_table('Vertical Headers', cols:
83
+ [
84
+ %w[Thomas Walpole Oceanside],
85
+ %w[Danilo Wilkinson Johnsonville],
86
+ %w[Vern Konopelski Everette],
87
+ ['Ratke', 'Lawrence', 'East Sorayashire'],
88
+ ['Palmer', 'Sawayn', 'West Trinidad']
89
+ ])
90
+ end
91
+
92
+ it "should not match if the order of cell values doesn't match" do
93
+ expect(@session).not_to have_table('Vertical Headers', with_cols:
94
+ [
95
+ %w[Vern Everette Konopelski]
96
+ ])
97
+ end
98
+
99
+ it "should not match with vertical headers if the columns don't match" do
100
+ expect(@session).not_to have_table('Vertical Headers', with_cols:
101
+ [
102
+ { 'First Name' => 'Thomas' },
103
+ { 'First Name' => 'Danilo', 'Last Name' => 'Walpole', 'City' => 'Johnsonville' },
104
+ { 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
105
+ ])
106
+ end
107
+
14
108
  it 'should be false if the table is not on the page' do
15
109
  expect(@session).not_to have_table('Monkey')
16
110
  end
111
+
112
+ it 'should find row by header and cell values' do
113
+ expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, 'First Name' => 'Thomas', 'Last Name' => 'Walpole')
114
+ expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, 'Last Name' => 'Walpole')
115
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, 'First Name' => 'Walpole')
116
+ end
117
+
118
+ it 'should find row by cell values' do
119
+ expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, %w[Thomas Walpole])
120
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, %w[Walpole Thomas])
121
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, %w[Other])
122
+ end
17
123
  end
18
124
 
19
125
  Capybara::SpecHelper.spec '#has_no_table?' do
@@ -29,4 +135,64 @@ Capybara::SpecHelper.spec '#has_no_table?' do
29
135
  it 'should be true if the table is not on the page' do
30
136
  expect(@session).to have_no_table('Monkey')
31
137
  end
138
+
139
+ it 'should consider rows' do
140
+ expect(@session).to have_no_table('Horizontal Headers', with_rows:
141
+ [
142
+ { 'First Name' => 'Thomas', 'City' => 'Los Angeles' }
143
+ ])
144
+ end
145
+
146
+ context 'using :with_cols' do
147
+ it 'should consider a single column' do
148
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
149
+ [
150
+ { 'First Name' => 'Joe' }
151
+ ])
152
+ end
153
+
154
+ it 'should be true even if the last column does exist' do
155
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
156
+ [
157
+ {
158
+ 'First Name' => 'What?',
159
+ 'What?' => 'Walpole',
160
+ 'City' => 'Oceanside' # This line makes the example fail
161
+ }
162
+ ])
163
+ end
164
+
165
+ it 'should be true if none of the columns exist' do
166
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
167
+ [
168
+ {
169
+ 'First Name' => 'What?',
170
+ 'What?' => 'Walpole',
171
+ 'City' => 'What?'
172
+ }
173
+ ])
174
+ end
175
+
176
+ it 'should be true if the first column does match' do
177
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
178
+ [
179
+ {
180
+ 'First Name' => 'Thomas',
181
+ 'Last Name' => 'What',
182
+ 'City' => 'What'
183
+ }
184
+ ])
185
+ end
186
+
187
+ it 'should be true if none of the columns match' do
188
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
189
+ [
190
+ {
191
+ 'First Name' => 'What',
192
+ 'Last Name' => 'What',
193
+ 'City' => 'What'
194
+ }
195
+ ])
196
+ end
197
+ end
32
198
  end
@@ -111,6 +111,41 @@ Capybara::SpecHelper.spec '#has_text?' do
111
111
  expect(@session).not_to have_text(/xxxxyzzz/)
112
112
  end
113
113
 
114
+ context 'with object implementing to_s and to_hash' do
115
+ it 'should work if the object is passed alone' do
116
+ with_to_hash = Class.new do
117
+ def to_s; '42' end
118
+ def to_hash; { value: 'Other hash' } end
119
+ end.new
120
+ @session.visit('/with_html')
121
+ expect(@session).to have_text(with_to_hash)
122
+ end
123
+
124
+ it 'should work if passed with empty options' do
125
+ with_to_hash = Class.new do
126
+ def to_s; '42' end
127
+ def to_hash; { value: 'Other hash' } end
128
+ end.new
129
+ @session.visit('/with_html')
130
+ if RUBY_VERSION >= '2.7'
131
+ expect(@session).to have_text(:visible, with_to_hash, **{})
132
+ else
133
+ expect(@session).to have_text(:visible, with_to_hash, {})
134
+ end
135
+ end
136
+
137
+ it 'should fail if passed without empty options' do
138
+ with_to_hash = Class.new do
139
+ def to_s; '42' end
140
+ def to_hash; { blah: 'Other hash' } end
141
+ end.new
142
+ @session.visit('/with_html')
143
+ expect do
144
+ expect(@session).to have_text(:visible, with_to_hash)
145
+ end.to raise_error(ArgumentError)
146
+ end
147
+ end
148
+
114
149
  context 'with exact: true option' do
115
150
  it 'should be true if text matches exactly' do
116
151
  @session.visit('/with_html')
@@ -139,6 +174,12 @@ Capybara::SpecHelper.spec '#has_text?' do
139
174
  expect(@session).to have_text(nil)
140
175
  end
141
176
 
177
+ it 'should warn when passed nil' do
178
+ @session.visit('/with_html')
179
+ expect_any_instance_of(Kernel).to receive(:warn).with(/Checking for expected text of nil is confusing/) # rubocop:disable RSpec/AnyInstance
180
+ expect(@session).to have_text(nil)
181
+ end
182
+
142
183
  it 'should wait for text to appear', requires: [:js] do
143
184
  Capybara.using_wait_time(3) do
144
185
  @session.visit('/with_js')
@@ -166,12 +207,14 @@ Capybara::SpecHelper.spec '#has_text?' do
166
207
  it 'should be true if the text occurs the given number of times' do
167
208
  @session.visit('/with_count')
168
209
  expect(@session).to have_text('count', count: 2)
210
+ expect(@session).to have_text('count').exactly(2).times
169
211
  end
170
212
 
171
213
  it 'should be false if the text occurs a different number of times than the given' do
172
214
  @session.visit('/with_count')
173
215
  expect(@session).not_to have_text('count', count: 0)
174
216
  expect(@session).not_to have_text('count', count: 1)
217
+ expect(@session).not_to have_text('count').once
175
218
  expect(@session).not_to have_text(/count/, count: 3)
176
219
  end
177
220
 
@@ -186,12 +229,14 @@ Capybara::SpecHelper.spec '#has_text?' do
186
229
  it 'should be true when text occurs same or fewer times than given' do
187
230
  @session.visit('/with_count')
188
231
  expect(@session).to have_text('count', maximum: 2)
232
+ expect(@session).to have_text('count').at_most(2).times
189
233
  expect(@session).to have_text(/count/, maximum: 3)
190
234
  end
191
235
 
192
236
  it 'should be false when text occurs more times than given' do
193
237
  @session.visit('/with_count')
194
238
  expect(@session).not_to have_text('count', maximum: 1)
239
+ expect(@session).not_to have_text('count').at_most(1).times
195
240
  expect(@session).not_to have_text('count', maximum: 0)
196
241
  end
197
242
 
@@ -206,12 +251,14 @@ Capybara::SpecHelper.spec '#has_text?' do
206
251
  it 'should be true when text occurs same or more times than given' do
207
252
  @session.visit('/with_count')
208
253
  expect(@session).to have_text('count', minimum: 2)
254
+ expect(@session).to have_text('count').at_least(2).times
209
255
  expect(@session).to have_text(/count/, minimum: 0)
210
256
  end
211
257
 
212
258
  it 'should be false when text occurs fewer times than given' do
213
259
  @session.visit('/with_count')
214
260
  expect(@session).not_to have_text('count', minimum: 3)
261
+ expect(@session).not_to have_text('count').at_least(3).times
215
262
  end
216
263
 
217
264
  it 'should coerce minimum to an integer' do
@@ -226,7 +273,7 @@ Capybara::SpecHelper.spec '#has_text?' do
226
273
  Capybara.using_wait_time(0.1) do
227
274
  @session.visit('/with_js')
228
275
  @session.click_link('Click me')
229
- expect(@session).to have_text('Has been clicked', wait: 2)
276
+ expect(@session).to have_text('Has been clicked', wait: 3)
230
277
  end
231
278
  end
232
279
  end
@@ -11,6 +11,20 @@ Capybara::SpecHelper.spec '#has_xpath?' do
11
11
  expect(@session).to have_xpath("//p[contains(.,'est')]")
12
12
  end
13
13
 
14
+ it 'should support :id option' do
15
+ expect(@session).to have_xpath('//h2', id: 'h2one')
16
+ expect(@session).to have_xpath('//h2')
17
+ expect(@session).to have_xpath('//h2', id: /h2o/)
18
+ end
19
+
20
+ it 'should support :class option' do
21
+ expect(@session).to have_xpath('//li', class: 'guitarist')
22
+ expect(@session).to have_xpath('//li', class: /guitar/)
23
+ expect(@session).to have_xpath('//li', class: /guitar|drummer/)
24
+ expect(@session).to have_xpath('//li', class: %w[beatle guitarist])
25
+ expect(@session).to have_xpath('//li', class: /.*/)
26
+ end
27
+
14
28
  it 'should be false if the given selector is not on the page' do
15
29
  expect(@session).not_to have_xpath('//abbr')
16
30
  expect(@session).not_to have_xpath("//p//a[@id='doesnotexist']")
@@ -43,6 +57,9 @@ Capybara::SpecHelper.spec '#has_xpath?' do
43
57
  expect(@session).to have_xpath("//p//a[@id='foo']", count: 1)
44
58
  expect(@session).to have_xpath("//p[contains(.,'est')]", count: 1)
45
59
  expect(@session).to have_xpath("//p//a[@id='doesnotexist']", count: 0)
60
+ expect(@session).to have_xpath('//li', class: /guitar|drummer/, count: 4)
61
+ expect(@session).to have_xpath('//li', id: /john|paul/, class: /guitar|drummer/, count: 2)
62
+ expect(@session).to have_xpath('//li', class: %w[beatle guitarist], count: 2)
46
63
  end
47
64
 
48
65
  it 'should be false if the content occurs a different number of times than the given' do
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Note: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
4
+ # because of the methods being tested. In tests using Capybara this type of behavior should be implemented
5
+ # using Capybara provided assertions with builtin waiting behavior.
6
+
3
7
  Capybara::SpecHelper.spec '#html' do
4
8
  it 'should return the unmodified page body' do
5
9
  @session.visit('/')
@@ -8,6 +12,7 @@ Capybara::SpecHelper.spec '#html' do
8
12
 
9
13
  it 'should return the current state of the page', requires: [:js] do
10
14
  @session.visit('/with_js')
15
+ sleep 1
11
16
  expect(@session.html).to include('I changed it')
12
17
  expect(@session.html).not_to include('This is text')
13
18
  end
@@ -21,6 +26,7 @@ Capybara::SpecHelper.spec '#source' do
21
26
 
22
27
  it 'should return the current state of the page', requires: [:js] do
23
28
  @session.visit('/with_js')
29
+ sleep 1
24
30
  expect(@session.source).to include('I changed it')
25
31
  expect(@session.source).not_to include('This is text')
26
32
  end
@@ -34,6 +40,7 @@ Capybara::SpecHelper.spec '#body' do
34
40
 
35
41
  it 'should return the current state of the page', requires: [:js] do
36
42
  @session.visit('/with_js')
43
+ sleep 1
37
44
  expect(@session.body).to include('I changed it')
38
45
  expect(@session.body).not_to include('This is text')
39
46
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ Capybara::SpecHelper.spec '#matches_style?', requires: [:css] do
4
+ before do
5
+ @session.visit('/with_html')
6
+ end
7
+
8
+ it 'should be true if the element has the given style' do
9
+ expect(@session.find(:css, '#first')).to match_style(display: 'block')
10
+ expect(@session.find(:css, '#first').matches_style?(display: 'block')).to be true
11
+ expect(@session.find(:css, '#second')).to match_style('display' => 'inline')
12
+ expect(@session.find(:css, '#second').matches_style?('display' => 'inline')).to be true
13
+ end
14
+
15
+ it 'should be false if the element does not have the given style' do
16
+ expect(@session.find(:css, '#first').matches_style?('display' => 'inline')).to be false
17
+ expect(@session.find(:css, '#second').matches_style?(display: 'block')).to be false
18
+ end
19
+
20
+ it 'allows Regexp for value matching' do
21
+ expect(@session.find(:css, '#first')).to match_style(display: /^bl/)
22
+ expect(@session.find(:css, '#first').matches_style?('display' => /^bl/)).to be true
23
+ expect(@session.find(:css, '#first').matches_style?(display: /^in/)).to be false
24
+ end
25
+
26
+ it 'deprecated has_style?' do
27
+ expect { have_style(display: /^bl/) }.to \
28
+ output(/have_style is deprecated/).to_stderr
29
+
30
+ el = @session.find(:css, '#first')
31
+ allow(el).to receive(:warn).and_return(nil)
32
+ el.has_style?('display' => /^bl/)
33
+ expect(el).to have_received(:warn)
34
+ end
35
+ end