capybara 3.35.2 → 3.39.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +133 -7
  3. data/README.md +28 -12
  4. data/lib/capybara/config.rb +16 -4
  5. data/lib/capybara/driver/base.rb +4 -0
  6. data/lib/capybara/driver/node.rb +5 -1
  7. data/lib/capybara/dsl.rb +4 -10
  8. data/lib/capybara/helpers.rb +8 -13
  9. data/lib/capybara/minitest/spec.rb +2 -2
  10. data/lib/capybara/node/actions.rb +14 -9
  11. data/lib/capybara/node/base.rb +2 -1
  12. data/lib/capybara/node/document.rb +2 -2
  13. data/lib/capybara/node/element.rb +13 -2
  14. data/lib/capybara/node/finders.rb +11 -2
  15. data/lib/capybara/node/simple.rb +5 -1
  16. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  17. data/lib/capybara/queries/active_element_query.rb +18 -0
  18. data/lib/capybara/queries/ancestor_query.rb +2 -1
  19. data/lib/capybara/queries/base_query.rb +2 -2
  20. data/lib/capybara/queries/current_path_query.rb +1 -1
  21. data/lib/capybara/queries/selector_query.rb +38 -10
  22. data/lib/capybara/queries/sibling_query.rb +2 -1
  23. data/lib/capybara/queries/text_query.rb +1 -1
  24. data/lib/capybara/rack_test/browser.rb +63 -8
  25. data/lib/capybara/rack_test/driver.rb +4 -4
  26. data/lib/capybara/rack_test/form.rb +29 -7
  27. data/lib/capybara/rack_test/node.rb +28 -22
  28. data/lib/capybara/registration_container.rb +0 -3
  29. data/lib/capybara/registrations/drivers.rb +6 -6
  30. data/lib/capybara/registrations/servers.rb +30 -10
  31. data/lib/capybara/rspec/matcher_proxies.rb +6 -6
  32. data/lib/capybara/rspec/matchers/base.rb +8 -6
  33. data/lib/capybara/rspec/matchers/compound.rb +1 -1
  34. data/lib/capybara/rspec/matchers/have_selector.rb +5 -5
  35. data/lib/capybara/rspec/matchers.rb +14 -14
  36. data/lib/capybara/selector/builders/css_builder.rb +1 -1
  37. data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
  38. data/lib/capybara/selector/css.rb +1 -1
  39. data/lib/capybara/selector/definition/button.rb +9 -4
  40. data/lib/capybara/selector/definition/checkbox.rb +1 -1
  41. data/lib/capybara/selector/definition/file_field.rb +1 -1
  42. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  43. data/lib/capybara/selector/definition/link.rb +2 -1
  44. data/lib/capybara/selector/definition/radio_button.rb +1 -1
  45. data/lib/capybara/selector/definition.rb +4 -2
  46. data/lib/capybara/selector/filter_set.rb +4 -7
  47. data/lib/capybara/selector/regexp_disassembler.rb +2 -5
  48. data/lib/capybara/selector/selector.rb +5 -1
  49. data/lib/capybara/selector.rb +1 -0
  50. data/lib/capybara/selenium/driver.rb +30 -13
  51. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
  52. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -5
  53. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +2 -2
  54. data/lib/capybara/selenium/extensions/html5_drag.rb +5 -4
  55. data/lib/capybara/selenium/logger_suppressor.rb +6 -2
  56. data/lib/capybara/selenium/node.rb +82 -33
  57. data/lib/capybara/selenium/nodes/chrome_node.rb +6 -2
  58. data/lib/capybara/selenium/nodes/edge_node.rb +25 -3
  59. data/lib/capybara/selenium/nodes/firefox_node.rb +3 -3
  60. data/lib/capybara/selenium/nodes/safari_node.rb +4 -4
  61. data/lib/capybara/selenium/patches/action_pauser.rb +3 -3
  62. data/lib/capybara/selenium/patches/atoms.rb +1 -1
  63. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -1
  64. data/lib/capybara/server/animation_disabler.rb +40 -23
  65. data/lib/capybara/server/middleware.rb +1 -1
  66. data/lib/capybara/session/config.rb +4 -2
  67. data/lib/capybara/session.rb +31 -32
  68. data/lib/capybara/spec/public/test.js +4 -0
  69. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  70. data/lib/capybara/spec/session/all_spec.rb +10 -14
  71. data/lib/capybara/spec/session/assert_text_spec.rb +17 -17
  72. data/lib/capybara/spec/session/attach_file_spec.rb +6 -0
  73. data/lib/capybara/spec/session/check_spec.rb +10 -0
  74. data/lib/capybara/spec/session/choose_spec.rb +6 -0
  75. data/lib/capybara/spec/session/click_link_spec.rb +11 -0
  76. data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
  77. data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
  78. data/lib/capybara/spec/session/find_link_spec.rb +10 -0
  79. data/lib/capybara/spec/session/find_spec.rb +7 -1
  80. data/lib/capybara/spec/session/first_spec.rb +1 -1
  81. data/lib/capybara/spec/session/frame/within_frame_spec.rb +2 -0
  82. data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
  83. data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -2
  84. data/lib/capybara/spec/session/has_any_selectors_spec.rb +6 -2
  85. data/lib/capybara/spec/session/has_button_spec.rb +30 -0
  86. data/lib/capybara/spec/session/has_current_path_spec.rb +3 -3
  87. data/lib/capybara/spec/session/has_field_spec.rb +25 -1
  88. data/lib/capybara/spec/session/has_link_spec.rb +40 -0
  89. data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
  90. data/lib/capybara/spec/session/has_select_spec.rb +10 -4
  91. data/lib/capybara/spec/session/has_selector_spec.rb +15 -0
  92. data/lib/capybara/spec/session/has_text_spec.rb +6 -14
  93. data/lib/capybara/spec/session/matches_style_spec.rb +2 -0
  94. data/lib/capybara/spec/session/node_spec.rb +82 -1
  95. data/lib/capybara/spec/session/reset_session_spec.rb +13 -0
  96. data/lib/capybara/spec/session/scroll_spec.rb +7 -5
  97. data/lib/capybara/spec/session/visit_spec.rb +20 -0
  98. data/lib/capybara/spec/session/window/window_spec.rb +1 -1
  99. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  100. data/lib/capybara/spec/session/within_spec.rb +13 -0
  101. data/lib/capybara/spec/spec_helper.rb +12 -5
  102. data/lib/capybara/spec/test_app.rb +91 -14
  103. data/lib/capybara/spec/views/animated.erb +1 -1
  104. data/lib/capybara/spec/views/form.erb +28 -3
  105. data/lib/capybara/spec/views/frame_child.erb +1 -1
  106. data/lib/capybara/spec/views/frame_one.erb +1 -1
  107. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  108. data/lib/capybara/spec/views/frame_two.erb +1 -1
  109. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  110. data/lib/capybara/spec/views/layout.erb +10 -0
  111. data/lib/capybara/spec/views/obscured.erb +1 -1
  112. data/lib/capybara/spec/views/offset.erb +2 -1
  113. data/lib/capybara/spec/views/path.erb +2 -2
  114. data/lib/capybara/spec/views/popup_one.erb +1 -1
  115. data/lib/capybara/spec/views/popup_two.erb +1 -1
  116. data/lib/capybara/spec/views/react.erb +2 -2
  117. data/lib/capybara/spec/views/scroll.erb +2 -1
  118. data/lib/capybara/spec/views/spatial.erb +1 -1
  119. data/lib/capybara/spec/views/with_animation.erb +2 -3
  120. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  121. data/lib/capybara/spec/views/with_dragula.erb +2 -2
  122. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  123. data/lib/capybara/spec/views/with_hover.erb +2 -2
  124. data/lib/capybara/spec/views/with_html.erb +3 -3
  125. data/lib/capybara/spec/views/with_jquery_animation.erb +1 -1
  126. data/lib/capybara/spec/views/with_js.erb +2 -3
  127. data/lib/capybara/spec/views/with_jstree.erb +1 -1
  128. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  129. data/lib/capybara/spec/views/with_scope.erb +2 -2
  130. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  131. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  132. data/lib/capybara/spec/views/with_sortable_js.erb +2 -2
  133. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  134. data/lib/capybara/spec/views/with_windows.erb +1 -1
  135. data/lib/capybara/spec/views/within_frames.erb +1 -1
  136. data/lib/capybara/version.rb +1 -1
  137. data/lib/capybara/window.rb +1 -1
  138. data/lib/capybara.rb +23 -24
  139. data/spec/basic_node_spec.rb +16 -3
  140. data/spec/capybara_spec.rb +12 -0
  141. data/spec/counter_spec.rb +35 -0
  142. data/spec/css_builder_spec.rb +1 -1
  143. data/spec/css_splitter_spec.rb +1 -1
  144. data/spec/dsl_spec.rb +5 -3
  145. data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -2
  146. data/spec/fixtures/selenium_driver_rspec_success.rb +2 -2
  147. data/spec/minitest_spec.rb +4 -0
  148. data/spec/minitest_spec_spec.rb +4 -0
  149. data/spec/per_session_config_spec.rb +1 -1
  150. data/spec/rack_test_spec.rb +30 -12
  151. data/spec/result_spec.rb +32 -35
  152. data/spec/rspec/features_spec.rb +3 -3
  153. data/spec/rspec/scenarios_spec.rb +2 -2
  154. data/spec/rspec/shared_spec_matchers.rb +3 -3
  155. data/spec/rspec_matchers_spec.rb +25 -0
  156. data/spec/rspec_spec.rb +2 -2
  157. data/spec/sauce_spec_chrome.rb +4 -4
  158. data/spec/selector_spec.rb +4 -4
  159. data/spec/selenium_spec_chrome.rb +16 -16
  160. data/spec/selenium_spec_chrome_remote.rb +16 -15
  161. data/spec/selenium_spec_edge.rb +12 -6
  162. data/spec/selenium_spec_firefox.rb +24 -7
  163. data/spec/selenium_spec_firefox_remote.rb +19 -4
  164. data/spec/selenium_spec_ie.rb +7 -8
  165. data/spec/selenium_spec_safari.rb +34 -20
  166. data/spec/server_spec.rb +7 -7
  167. data/spec/shared_selenium_node.rb +0 -4
  168. data/spec/shared_selenium_session.rb +24 -14
  169. data/spec/spec_helper.rb +35 -2
  170. data/spec/whitespace_normalizer_spec.rb +54 -0
  171. data/spec/xpath_builder_spec.rb +1 -1
  172. metadata +40 -14
  173. data/lib/capybara/spec/views/with_title.erb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e707b56213a558121aec02091da3b9558d49231937d45c38dfaf80a2dd29b42c
4
- data.tar.gz: c6fee456f607511bd5e2c2113f92100732c1bc317ad027f457bd762f66374f1d
3
+ metadata.gz: '0945d8fedaab75fa31a90d12105de7318d78c20a46955a1b78ae88dc791f6a5a'
4
+ data.tar.gz: 9a59ca68ff9d44ef28597603ed275ebef28c79c8b6fb76ffdc26daaee68ab383
5
5
  SHA512:
6
- metadata.gz: 03f2c85d4a433acc5ae479698b568c90069019fdde4386d7a304c48563ddb2fde06912ca158505734f92879206eb74fa96043e39f8f89c74e76f1a539ed4ae7a
7
- data.tar.gz: aa26c8230d97e0716cb65fac45a660724430ea945a4292afeeba8ef7f49915b8aefb3eda0a592177c6bae8689debab283ea37a7594f01c46a0f453d4954cac54
6
+ metadata.gz: dbb58a338e2408140ce5e6a44bc141fc44833952c10f611996f5a217c9a0ad00f8d6344a1c16b0bf53000801f9e1d45ef3848cb0fa886dabe68c6d766a42372a
7
+ data.tar.gz: db985c0c947ff348c80008fd4c90232a0ad4dcd38dbe8694b157ecfb512c099d6e9bc08177d8a115e1db17cca35c68903e10662da0fdd14c4f1a2ab671932b16
data/History.md CHANGED
@@ -1,12 +1,139 @@
1
+ # Version 3.39.2
2
+ Release date: 2023-06-10
3
+
4
+ ### Fixed
5
+
6
+ * Fix Selenium version comparison [aki77]
7
+
8
+ # Version 3.39.1
9
+ Release date: 2023-05-12
10
+
11
+ ### Fixed
12
+
13
+ * Fix usage of Selenium logger
14
+
15
+ # Version 3.39.0
16
+ Release date: 2023-04-02
17
+
18
+ ### Added
19
+
20
+ * Support `:target` filter option on `:link` selector [Yudai Takada]
21
+ * Experimental Rack 3 support
22
+ * Text normalization performance improvements [Brandon Weaver]
23
+
24
+ ### Fixed
25
+
26
+ * MS Edge button click [Brian J. Bayer]
27
+ * Options/Capabilities choosing based on Selenium versions
28
+ * Support for base versions [Matijs van Zuijlen]
29
+ * ExpectedError not defined in Selenium 4+
30
+ * Filter block forwarding to a number of matchers [Christophe Bliard]
31
+ ### Changed
32
+
33
+ * Dropped support for rack 1.x
34
+
35
+ # Version 3.38.0
36
+ Release date: 2022-11-03
37
+
38
+ ### Changed
39
+
40
+ * Capybara.w3c_click_offset now defaults to true. If you need click offsets to be from the elements top left corner set it to false in your config
41
+
42
+ ### Added
43
+
44
+ * Support Selenium 4.3 changes to click offset calculations
45
+ * `click`, `double_click`, `right_click` can now be called on the session to click the currently scoped element (or document)
46
+ * `Session#within` now passes the scoped element to the block
47
+ * Support rack-test 2+
48
+ * Retry interval is now configurable [Masahiro NOMOTO]
49
+ * Support Puma 6 - Issue #2590
50
+ * Selenium: DetachedShadowRootError is treated as an invalid element error [Perryn Fowler]
51
+ * Selenium: When inspected shadow roots will have a tag name of "ShadowRoot"
52
+ * `evaluate_async_script` added to Session::DSL_METHODS [Henry Blyth]
53
+
54
+ ### Fixed
55
+
56
+ * Use higher precision clock in Capybara::Helpers::Timer if available
57
+ * rack-test driver behavior with \r\n - Issue #2547 [Stefan Hoffmann]
58
+ * Updated for deprecation of positional parameters in Selenium::WebDriver::ActionBuilder#pause
59
+ * Explicitly set cause on server raised errors
60
+ * Options no longer duplicated in have_xxx invalid option error message [Yudai Takada]
61
+ * Animation disabler is now threadsafe [Daniel Sheppard]
62
+ * Server connection count tracking [Oleksandr K.]
63
+ * Ensure scopes are reset when session is [Henry Blyth]
64
+
65
+ # Version 3.37.1
66
+ Release date: 2022-05-09
67
+
68
+ ### Fixed
69
+
70
+ * Regression in rack-test visit - Issue #2548
71
+
72
+ # Version 3.37.0
73
+ Release date: 2022-05-07
74
+
75
+ ### Changed
76
+
77
+ * Ruby 2.7.0+ is now required
78
+
79
+ ### Added
80
+
81
+ * [Beta] CSP nonces inserted into animation disabler additions - Issue #2542
82
+ * Support `<base>` element in rack-test driver - ISsue #2544
83
+ * [Beta] `Element#shadow_root` support. Requires selenium-webdriver 4.1+. Only currently supported with Chrome when using the selenium driver. Note: only CSS can be used to find elements from the shadow root. Therefore you won't be able to use most Capybara helper methods (`fill_in`, `click_link`, `find_field`, etc) directly from the shadow root since those locators are built using XPath. If you first locate a descendant from the shadow root using CSS then you should be able to use all the Capybara methods from there.
84
+ * Regexp now supported for `exact_text` finder option
85
+
86
+ ### Fixed
87
+
88
+ * Fragments in referer headers in rack-test driver - Issue #2525
89
+ * Selenium v4.1 deprecation notice
90
+
91
+ # Version 3.36.0
92
+ Release date: 2021-10-24
93
+
94
+ ### Changed
95
+
96
+ * Ruby 2.6.0+ is now required
97
+ * Minimum selenium-webdriver supported is now 3.142.7
98
+
99
+ ### Added
100
+
101
+ * Support for selenium-webdriver 4.x
102
+ * `allow_label_click` accepts click options to be used when clicking an associated label
103
+ * Deprecated `allow_gumbo=` in favor of `use_html5_parsing=` to enable use of Nokogiri::HTML5 when available
104
+ * `Session#active_element` returns the element with focus - Not supported by the `RackTest` driver [Sean Doyle]
105
+ * Support `focused:` filter for finding interactive elements - Not supported by the `RackTest` driver [Sean Doyle]
106
+
107
+ ### Fixed
108
+
109
+ * Sibling and ancestor queries now work with Simple::Node - Issue #2452
110
+ * rack_test correctly ignores readonly attribute on specific input element types
111
+ * `Node#all_text` always returns a string - Issue #2477
112
+ * `have_any_of_selectors` negated match - Issue #2473
113
+ * `Document#scroll_to` fixed for standards behavior - pass quirks: true if you need the older behavior [Eric Anderson]
114
+ * Use capture on attach file event listener for better React compatibility [Jeff Way]
115
+ * Animation disabler produces valid HTML [Javi Martin]
116
+
117
+ ### Removed
118
+
119
+ * References to non-w3c mode in drivers/tests. Non-w3c mode is obsolete and no one should be using it anymore. Capybara hasn't been testing/supporting it in a while
120
+
121
+ # Version 3.35.3
122
+ Release date: 2021-01-29
123
+
124
+ ### Fixed
125
+
126
+ * Just a release to have the correct dates in the History.md in released gem
127
+
1
128
  # Version 3.35.2
2
- Release date: 2020-01-29
129
+ Release date: 2021-01-29
3
130
 
4
131
  ### Fixed
5
132
 
6
133
  * Selenium deprecation suppressor with Selenium 3.x
7
134
 
8
135
  # Version 3.35.1
9
- Release date: 2020-01-26
136
+ Release date: 2021-01-26
10
137
 
11
138
  ### Fixed
12
139
 
@@ -14,7 +141,7 @@ Release date: 2020-01-26
14
141
  * 'Capybara.test_id' usage with the :button selector - Issue #2443
15
142
 
16
143
  # Version 3.35.0
17
- Release date: 2020-01-25
144
+ Release date: 2021-01-25
18
145
 
19
146
  ### Added
20
147
 
@@ -747,7 +874,7 @@ Release date: 2018-03-23
747
874
 
748
875
  ### Changed
749
876
 
750
- * Visibile text whitespace is no longer fully normalized in favor of being more in line with the WebDriver spec for visible text
877
+ * Visible text whitespace is no longer fully normalized in favor of being more in line with the WebDriver spec for visible text
751
878
  * Drivers are expected to close extra windows when resetting the session
752
879
  * Selenium driver supports Date/Time when filling in date/time/datetime-local inputs
753
880
  * `current_url` returns the url for the top level browsing context
@@ -1153,7 +1280,7 @@ Release date: 2016-01-27
1153
1280
 
1154
1281
  # Version 2.6.0
1155
1282
 
1156
- Relase date: 2016-01-17
1283
+ Release date: 2016-01-17
1157
1284
 
1158
1285
  ### Fixed
1159
1286
 
@@ -1217,7 +1344,7 @@ Release date: 2014-10-13
1217
1344
 
1218
1345
  # Version 2.4.3
1219
1346
 
1220
- Relase date: 2014-09-21
1347
+ Release date: 2014-09-21
1221
1348
 
1222
1349
  ### Fixed
1223
1350
 
@@ -1892,4 +2019,3 @@ too many users, please read the release notes carefully!
1892
2019
  * clicking links where the image's alt attribute contains the text is now possible
1893
2020
  * within_fieldset and within_table work when the default selector is CSS
1894
2021
  * boolean attributes work the same across drivers (return true/false)
1895
-
data/README.md CHANGED
@@ -74,7 +74,7 @@ GitHub): http://groups.google.com/group/ruby-capybara
74
74
 
75
75
  ## <a name="setup"></a>Setup
76
76
 
77
- Capybara requires Ruby 2.5.0 or later. To install, add this line to your
77
+ Capybara requires Ruby 2.7.0 or later. To install, add this line to your
78
78
  `Gemfile` and run `bundle install`:
79
79
 
80
80
  ```ruby
@@ -151,6 +151,8 @@ RSpec](https://relishapp.com/rspec/rspec-rails/v/4-0/docs/directory-structure))
151
151
  and if you have your Capybara specs in a different directory, then tag the
152
152
  example groups with `type: :feature` or `type: :system` depending on which type of test you're writing.
153
153
 
154
+ If you are using Rails system specs please see [their documentation](https://relishapp.com/rspec/rspec-rails/docs/system-specs/system-spec#system-specs-driven-by-selenium-chrome-headless) for selecting the driver you wish to use.
155
+
154
156
  If you are not using Rails, tag all the example groups in which you want to use
155
157
  Capybara with `type: :feature`.
156
158
 
@@ -159,7 +161,7 @@ You can now write your specs like so:
159
161
  ```ruby
160
162
  describe "the signin process", type: :feature do
161
163
  before :each do
162
- User.make(email: 'user@example.com', password: 'password')
164
+ User.create(email: 'user@example.com', password: 'password')
163
165
  end
164
166
 
165
167
  it "signs me in" do
@@ -190,7 +192,7 @@ Capybara also comes with a built in DSL for creating descriptive acceptance test
190
192
  ```ruby
191
193
  feature "Signing in" do
192
194
  background do
193
- User.make(email: 'user@example.com', password: 'caplin')
195
+ User.create(email: 'user@example.com', password: 'caplin')
194
196
  end
195
197
 
196
198
  scenario "Signing in with correct credentials" do
@@ -203,7 +205,7 @@ feature "Signing in" do
203
205
  expect(page).to have_content 'Success'
204
206
  end
205
207
 
206
- given(:other_user) { User.make(email: 'other@example.com', password: 'rous') }
208
+ given(:other_user) { User.create(email: 'other@example.com', password: 'rous') }
207
209
 
208
210
  scenario "Signing in as another user" do
209
211
  visit '/sessions/new'
@@ -258,6 +260,8 @@ end
258
260
 
259
261
  ## <a name="using-capybara-with-minitest"></a>Using Capybara with Minitest
260
262
 
263
+ * If you are using Rails system tests please see their documentation for information on selecting the driver you wish to use.
264
+
261
265
  * If you are using Rails, but not using Rails system tests, add the following code in your `test_helper.rb`
262
266
  file to make Capybara available in all test cases deriving from
263
267
  `ActionDispatch::IntegrationTest`:
@@ -332,7 +336,7 @@ By default, Capybara uses the `:rack_test` driver, which is fast but limited: it
332
336
  does not support JavaScript, nor is it able to access HTTP resources outside of
333
337
  your Rack application, such as remote APIs and OAuth services. To get around
334
338
  these limitations, you can set up a different default driver for your features.
335
- For example if you'd prefer to run everything in Selenium, you could do:
339
+ For example, if you'd prefer to run everything in Selenium, you could do:
336
340
 
337
341
  ```ruby
338
342
  Capybara.default_driver = :selenium # :selenium_chrome and :selenium_chrome_headless are also registered
@@ -626,7 +630,7 @@ JS
626
630
 
627
631
  ### <a name="modals"></a>Modals
628
632
 
629
- In drivers which support it, you can accept, dismiss and respond to alerts, confirms and prompts.
633
+ In drivers which support it, you can accept, dismiss and respond to alerts, confirms, and prompts.
630
634
 
631
635
  You can accept or dismiss alert messages by wrapping the code that produces an alert in a block:
632
636
 
@@ -777,7 +781,7 @@ expect(page).to have_content('baz')
777
781
  If clicking on the *foo* link triggers an asynchronous process, such as
778
782
  an Ajax request, which, when complete will add the *bar* link to the page,
779
783
  clicking on the *bar* link would be expected to fail, since that link doesn't
780
- exist yet. However Capybara is smart enough to retry finding the link for a
784
+ exist yet. However, Capybara is smart enough to retry finding the link for a
781
785
  brief period of time before giving up and throwing an error. The same is true of
782
786
  the next line, which looks for the content *baz* on the page; it will retry
783
787
  looking for that content for a brief time. You can adjust how long this period
@@ -791,13 +795,25 @@ Be aware that because of this behaviour, the following two statements are **not*
791
795
  equivalent, and you should **always** use the latter!
792
796
 
793
797
  ```ruby
794
- !page.has_xpath?('a')
795
- page.has_no_xpath?('a')
798
+ # Given use of a driver where the page is loaded when visit returns
799
+ # and that Capybara.predicates_wait is `true`
800
+ # consider a page where the `a` tag is removed through AJAX after 1s
801
+ visit(some_path)
802
+ !page.has_xpath?('a') # is false
803
+ page.has_no_xpath?('a') # is true
796
804
  ```
797
805
 
798
- The former would immediately fail because the content has not yet been removed.
799
- Only the latter would wait for the asynchronous process to remove the content
800
- from the page.
806
+ First expression:
807
+ - `has_xpath?('a')` is called right after `visit` returns. It is `true` because the link has not yet been removed
808
+ - Capybara does not wait upon successful predicates/assertions, therefore **has_xpath? returns `true` immediately**
809
+ - The expression returns `false` (because it is negated with the leading `!`)
810
+
811
+ Second expression:
812
+ - `has_no_xpath?('a')` is called right after `visit` returns. It is `false` because the link has not yet been removed.
813
+ - Capybara waits upon failed predicates/assertions, therefore **has_no_xpath? does not return `false` immediately**
814
+ - Capybara will periodically re-check the predicate/assertion up to the `default_max_wait_time` defined
815
+ - after 1s, the predicate becomes `true` (because the link has been removed)
816
+ - The expression returns `true`
801
817
 
802
818
  Capybara's RSpec matchers, however, are smart enough to handle either form.
803
819
  The two following statements are functionally equivalent:
@@ -7,10 +7,12 @@ module Capybara
7
7
  class Config
8
8
  extend Forwardable
9
9
 
10
- OPTIONS = %i[app reuse_server threadsafe server default_driver javascript_driver allow_gumbo].freeze
10
+ OPTIONS = %i[
11
+ app reuse_server threadsafe server default_driver javascript_driver use_html5_parsing allow_gumbo
12
+ ].freeze
11
13
 
12
- attr_accessor :app, :allow_gumbo
13
- attr_reader :reuse_server, :threadsafe, :session_options
14
+ attr_accessor :app, :use_html5_parsing
15
+ attr_reader :reuse_server, :threadsafe, :session_options # rubocop:disable Style/BisectedAttrAccessor
14
16
  attr_writer :default_driver, :javascript_driver
15
17
 
16
18
  SessionConfig::OPTIONS.each do |method|
@@ -22,7 +24,7 @@ module Capybara
22
24
  @javascript_driver = nil
23
25
  end
24
26
 
25
- attr_writer :reuse_server
27
+ attr_writer :reuse_server # rubocop:disable Style/BisectedAttrAccessor
26
28
 
27
29
  def threadsafe=(bool)
28
30
  if (bool != threadsafe) && Session.instance_created?
@@ -88,5 +90,15 @@ module Capybara
88
90
  end
89
91
  @deprecation_notified[method] = true
90
92
  end
93
+
94
+ def allow_gumbo=(val)
95
+ deprecate('allow_gumbo=', 'use_html5_parsing=')
96
+ self.use_html5_parsing = val
97
+ end
98
+
99
+ def allow_gumbo
100
+ deprecate('allow_gumbo', 'use_html5_parsing')
101
+ use_html5_parsing
102
+ end
91
103
  end
92
104
  end
@@ -63,6 +63,10 @@ class Capybara::Driver::Base
63
63
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#send_keys'
64
64
  end
65
65
 
66
+ def active_element
67
+ raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#active_element'
68
+ end
69
+
66
70
  ##
67
71
  #
68
72
  # @param frame [Capybara::Node::Element, :parent, :top] The iframe element to switch to
@@ -125,6 +125,10 @@ module Capybara
125
125
  raise NotSupportedByDriverError, 'Capybara::Driver::Node#trigger'
126
126
  end
127
127
 
128
+ def shadow_root
129
+ raise NotSupportedByDriverError, 'Capybara::Driver::Node#shadow_root'
130
+ end
131
+
128
132
  def inspect
129
133
  %(#<#{self.class} tag="#{tag_name}" path="#{path}">)
130
134
  rescue NotSupportedByDriverError
@@ -132,7 +136,7 @@ module Capybara
132
136
  end
133
137
 
134
138
  def ==(other)
135
- raise NotSupportedByDriverError, 'Capybara::Driver::Node#=='
139
+ eql?(other) || (other.respond_to?(:native) && native == other.native)
136
140
  end
137
141
  end
138
142
  end
data/lib/capybara/dsl.rb CHANGED
@@ -47,17 +47,11 @@ module Capybara
47
47
  end
48
48
 
49
49
  Session::DSL_METHODS.each do |method|
50
- if RUBY_VERSION >= '2.7'
51
- class_eval <<~METHOD, __FILE__, __LINE__ + 1
52
- def #{method}(...)
53
- page.method("#{method}").call(...)
54
- end
55
- METHOD
56
- else
57
- define_method method do |*args, &block|
58
- page.send method, *args, &block
50
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
51
+ def #{method}(...)
52
+ page.method("#{method}").call(...)
59
53
  end
60
- end
54
+ METHOD
61
55
  end
62
56
  end
63
57
 
@@ -73,28 +73,23 @@ module Capybara
73
73
  def filter_backtrace(trace)
74
74
  return 'No backtrace' unless trace
75
75
 
76
- filter = %r{lib/capybara/|lib/rspec/|lib/minitest/}
76
+ filter = %r{lib/capybara/|lib/rspec/|lib/minitest/|delegate.rb}
77
77
  new_trace = trace.take_while { |line| line !~ filter }
78
- new_trace = trace.reject { |line| line =~ filter } if new_trace.empty?
78
+ new_trace = trace.grep_v(filter) if new_trace.empty?
79
79
  new_trace = trace.dup if new_trace.empty?
80
80
 
81
81
  new_trace.first.split(/:in /, 2).first
82
82
  end
83
83
 
84
84
  def warn(message, uplevel: 1)
85
- return Kernel.warn(message, uplevel: uplevel) if RUBY_VERSION >= '2.6'
86
-
87
- # TODO: Remove when we drop support for Ruby 2.5
88
- # Workaround for emulating `warn '...', uplevel: n` in Ruby 2.5 or lower.
89
- if (match = /^(?<file>.+?):(?<line>\d+)(?::in `.*')?/.match(caller[uplevel]))
90
- location = [match[:file], match[:line]].join(':')
91
- Kernel.warn "#{location}: #{message}"
92
- else
93
- Kernel.warn message
94
- end
85
+ Kernel.warn(message, uplevel: uplevel)
95
86
  end
96
87
 
97
- if defined?(Process::CLOCK_MONOTONIC)
88
+ if defined?(Process::CLOCK_MONOTONIC_RAW)
89
+ def monotonic_time; Process.clock_gettime Process::CLOCK_MONOTONIC_RAW; end
90
+ elsif defined?(Process::CLOCK_MONOTONIC_PRECISE)
91
+ def monotonic_time; Process.clock_gettime Process::CLOCK_MONOTONIC_PRECISE; end
92
+ elsif defined?(Process::CLOCK_MONOTONIC)
98
93
  def monotonic_time; Process.clock_gettime Process::CLOCK_MONOTONIC; end
99
94
  else
100
95
  def monotonic_time; Time.now.to_f; end
@@ -246,9 +246,9 @@ module Capybara
246
246
 
247
247
  ##
248
248
  # @deprecated
249
- def must_have_style(*args, **kw_args, &block)
249
+ def must_have_style(...)
250
250
  warn 'must_have_style is deprecated, please use must_match_style'
251
- must_match_style(*args, **kw_args, &block)
251
+ must_match_style(...)
252
252
  end
253
253
  end
254
254
  end
@@ -92,8 +92,9 @@ module Capybara
92
92
  end
93
93
 
94
94
  # @!macro label_click
95
- # @option options [Boolean] allow_label_click
95
+ # @option options [Boolean, Hash] allow_label_click
96
96
  # Attempt to click the label to toggle state if element is non-visible. Defaults to {Capybara.configure automatic_label_click}.
97
+ # If set to a Hash it is passed as options to the `click` on the label
97
98
 
98
99
  ##
99
100
  #
@@ -277,7 +278,7 @@ module Capybara
277
278
  # @return [Capybara::Node::Element] The file field element
278
279
  def attach_file(locator = nil, paths, make_visible: nil, **options) # rubocop:disable Style/OptionalArguments
279
280
  if locator && block_given?
280
- raise ArgumentError, '``#attach_file` does not support passing both a locator and a block'
281
+ raise ArgumentError, '`#attach_file` does not support passing both a locator and a block'
281
282
  end
282
283
 
283
284
  Array(paths).each do |path|
@@ -314,7 +315,7 @@ module Capybara
314
315
 
315
316
  begin
316
317
  find(:datalist_input, from, **options)
317
- rescue Capybara::ElementNotFound => dlinput_error # rubocop:disable Naming/RescuedExceptionsVariableName
318
+ rescue Capybara::ElementNotFound => dlinput_error
318
319
  raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}"
319
320
  end
320
321
  end
@@ -371,14 +372,18 @@ module Capybara
371
372
 
372
373
  begin
373
374
  el ||= find(selector, locator, **options.merge(visible: :all))
374
- el.session.find(:label, for: el, visible: true, match: :first).click unless el.checked? == checked
375
+ unless el.checked? == checked
376
+ el.session
377
+ .find(:label, for: el, visible: true, match: :first)
378
+ .click(**(Hash.try_convert(allow_label_click) || {}))
379
+ end
375
380
  rescue StandardError # swallow extra errors - raise original
376
381
  raise e
377
382
  end
378
383
  end
379
384
  end
380
385
 
381
- UPDATE_STYLE_SCRIPT = <<~'JS'
386
+ UPDATE_STYLE_SCRIPT = <<~JS
382
387
  this.capybara_style_cache = this.style.cssText;
383
388
  var css = arguments[0];
384
389
  for (var prop in css){
@@ -388,27 +393,27 @@ module Capybara
388
393
  }
389
394
  JS
390
395
 
391
- RESET_STYLE_SCRIPT = <<~'JS'
396
+ RESET_STYLE_SCRIPT = <<~JS
392
397
  if (this.hasOwnProperty('capybara_style_cache')) {
393
398
  this.style.cssText = this.capybara_style_cache;
394
399
  delete this.capybara_style_cache;
395
400
  }
396
401
  JS
397
402
 
398
- DATALIST_OPTIONS_SCRIPT = <<~'JS'
403
+ DATALIST_OPTIONS_SCRIPT = <<~JS
399
404
  Array.prototype.slice.call((this.list||{}).options || []).
400
405
  filter(function(el){ return !el.disabled }).
401
406
  map(function(el){ return { "value": el.value, "label": el.label} })
402
407
  JS
403
408
 
404
- CAPTURE_FILE_ELEMENT_SCRIPT = <<~'JS'
409
+ CAPTURE_FILE_ELEMENT_SCRIPT = <<~JS
405
410
  document.addEventListener('click', function file_catcher(e){
406
411
  if (e.target.matches("input[type='file']")) {
407
412
  window._capybara_clicked_file_input = e.target;
408
413
  this.removeEventListener('click', file_catcher);
409
414
  e.preventDefault();
410
415
  }
411
- })
416
+ }, {capture: true})
412
417
  JS
413
418
  end
414
419
  end
@@ -77,6 +77,7 @@ module Capybara
77
77
  return yield if session.synchronized
78
78
 
79
79
  seconds = session_options.default_max_wait_time if [nil, true].include? seconds
80
+ interval = session_options.default_retry_interval
80
81
  session.synchronized = true
81
82
  timer = Capybara::Helpers.timer(expire_in: seconds)
82
83
  begin
@@ -88,7 +89,7 @@ module Capybara
88
89
  if driver.wait?
89
90
  raise e if timer.expired?
90
91
 
91
- sleep(0.01)
92
+ sleep interval
92
93
  reload if session_options.automatic_reload
93
94
  else
94
95
  old_base = @base
@@ -40,8 +40,8 @@ module Capybara
40
40
  find(:xpath, '/html').evaluate_script(*args)
41
41
  end
42
42
 
43
- def scroll_to(*args, **options)
44
- find(:xpath, '//body').scroll_to(*args, **options)
43
+ def scroll_to(*args, quirks: false, **options)
44
+ find(:xpath, quirks ? '//body' : '/html').scroll_to(*args, **options)
45
45
  end
46
46
  end
47
47
  end
@@ -115,7 +115,7 @@ module Capybara
115
115
  #
116
116
  # @return [Capybara::Node::Element] The element
117
117
  def set(value, **options)
118
- if ENV['CAPYBARA_THOROUGH'] && readonly?
118
+ if ENV.fetch('CAPYBARA_THOROUGH', nil) && readonly?
119
119
  raise Capybara::ReadOnlyElementError, "Attempt to set readonly element with value: #{value}"
120
120
  end
121
121
 
@@ -472,6 +472,17 @@ module Capybara
472
472
  self
473
473
  end
474
474
 
475
+ ##
476
+ #
477
+ # Return the shadow_root for the current element
478
+ #
479
+ # @return [Capybara::Node::Element] The shadow root
480
+
481
+ def shadow_root
482
+ root = synchronize { base.shadow_root }
483
+ root && Capybara::Node::Element.new(session, root, nil, nil)
484
+ end
485
+
475
486
  ##
476
487
  #
477
488
  # Execute the given JS in the context of the element not returning a result. This is useful for scripts that return
@@ -550,7 +561,7 @@ module Capybara
550
561
  return self unless @allow_reload
551
562
 
552
563
  begin
553
- reloaded = @query.resolve_for(query_scope.reload)[@query_idx.to_i]
564
+ reloaded = @query.resolve_for(query_scope ? query_scope.reload : session)[@query_idx.to_i]
554
565
  @base = reloaded.base if reloaded
555
566
  rescue StandardError => e
556
567
  raise e unless catch_error?(e)
@@ -18,11 +18,11 @@ module Capybara
18
18
  #
19
19
  # @!macro system_filters
20
20
  # @option options [String, Regexp] text Only find elements which contain this text or match this regexp
21
- # @option options [String, Boolean] exact_text
21
+ # @option options [String, Regexp, String] exact_text
22
22
  # When String the elements contained text must match exactly, when Boolean controls whether the `text` option must match exactly.
23
23
  # Defaults to {Capybara.configure exact_text}.
24
24
  # @option options [Boolean] normalize_ws
25
- # Whether the `text`/`exact_text` options are compared against elment text with whitespace normalized or as returned by the driver.
25
+ # Whether the `text`/`exact_text` options are compared against element text with whitespace normalized or as returned by the driver.
26
26
  # Defaults to {Capybara.configure default_normalize_ws}.
27
27
  # @option options [Boolean, Symbol] visible
28
28
  # Only find elements with the specified visibility. Defaults to behavior indicated by {Capybara.configure ignore_hidden_elements}.
@@ -50,6 +50,13 @@ module Capybara
50
50
  #
51
51
  def find(*args, **options, &optional_filter_block)
52
52
  options[:session_options] = session_options
53
+ count_options = options.slice(*Capybara::Queries::BaseQuery::COUNT_KEYS)
54
+ unless count_options.empty?
55
+ Capybara::Helpers.warn(
56
+ "'find' does not support count options (#{count_options}) ignoring. " \
57
+ "Called from: #{Capybara::Helpers.filter_backtrace(caller)}"
58
+ )
59
+ end
53
60
  synced_resolve Capybara::Queries::SelectorQuery.new(*args, **options, &optional_filter_block)
54
61
  end
55
62
 
@@ -142,6 +149,8 @@ module Capybara
142
149
  # @option options [String, Regexp] id Match links with the id provided
143
150
  # @option options [String] title Match links with the title provided
144
151
  # @option options [String] alt Match links with a contained img element whose alt matches
152
+ # @option options [String, Boolean] download Match links with the download provided
153
+ # @option options [String] target Match links with the target provided
145
154
  # @option options [String, Array<String>, Regexp] class Match links that match the class(es) provided
146
155
  # @return [Capybara::Node::Element] The found element
147
156
  #
@@ -110,7 +110,7 @@ module Capybara
110
110
  # No need for an xpath if only checking the current element
111
111
  !(native.key?('hidden') ||
112
112
  /display:\s?none/.match?(native[:style] || '') ||
113
- %w[script head].include?(tag_name))
113
+ %w[script head style].include?(tag_name))
114
114
  end
115
115
  end
116
116
 
@@ -191,6 +191,10 @@ module Capybara
191
191
  {}
192
192
  end
193
193
 
194
+ def ==(other)
195
+ eql?(other) || (other.respond_to?(:native) && native == other.native)
196
+ end
197
+
194
198
  private
195
199
 
196
200
  def option_value(option)