capybara 3.36.0 → 3.39.2
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.
- checksums.yaml +4 -4
- data/History.md +94 -4
- data/README.md +24 -12
- data/lib/capybara/driver/node.rb +4 -0
- data/lib/capybara/dsl.rb +4 -10
- data/lib/capybara/helpers.rb +6 -2
- data/lib/capybara/minitest/spec.rb +2 -2
- data/lib/capybara/node/actions.rb +4 -4
- data/lib/capybara/node/base.rb +2 -1
- data/lib/capybara/node/element.rb +12 -1
- data/lib/capybara/node/finders.rb +10 -1
- data/lib/capybara/node/whitespace_normalizer.rb +81 -0
- data/lib/capybara/queries/base_query.rb +2 -2
- data/lib/capybara/queries/selector_query.rb +24 -9
- data/lib/capybara/queries/text_query.rb +1 -1
- data/lib/capybara/rack_test/browser.rb +63 -8
- data/lib/capybara/rack_test/driver.rb +4 -4
- data/lib/capybara/rack_test/form.rb +29 -7
- data/lib/capybara/rack_test/node.rb +19 -16
- data/lib/capybara/registration_container.rb +0 -3
- data/lib/capybara/registrations/drivers.rb +3 -3
- data/lib/capybara/registrations/servers.rb +30 -10
- data/lib/capybara/rspec/matcher_proxies.rb +3 -3
- data/lib/capybara/rspec/matchers/base.rb +8 -6
- data/lib/capybara/rspec/matchers/compound.rb +1 -1
- data/lib/capybara/rspec/matchers/have_selector.rb +4 -4
- data/lib/capybara/rspec/matchers.rb +14 -14
- data/lib/capybara/selector/definition/link.rb +2 -1
- data/lib/capybara/selector/definition.rb +3 -2
- data/lib/capybara/selector/filter_set.rb +4 -5
- data/lib/capybara/selector/regexp_disassembler.rb +2 -5
- data/lib/capybara/selector/selector.rb +5 -1
- data/lib/capybara/selenium/driver.rb +11 -4
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +8 -4
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +1 -1
- data/lib/capybara/selenium/extensions/html5_drag.rb +5 -4
- data/lib/capybara/selenium/logger_suppressor.rb +6 -2
- data/lib/capybara/selenium/node.rb +72 -25
- data/lib/capybara/selenium/nodes/chrome_node.rb +5 -1
- data/lib/capybara/selenium/nodes/edge_node.rb +24 -2
- data/lib/capybara/selenium/nodes/firefox_node.rb +2 -2
- data/lib/capybara/selenium/nodes/safari_node.rb +2 -2
- data/lib/capybara/selenium/patches/action_pauser.rb +3 -3
- data/lib/capybara/selenium/patches/atoms.rb +1 -1
- data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -1
- data/lib/capybara/server/animation_disabler.rb +36 -25
- data/lib/capybara/server/middleware.rb +1 -1
- data/lib/capybara/session/config.rb +4 -2
- data/lib/capybara/session.rb +19 -30
- data/lib/capybara/spec/public/test.js +4 -0
- data/lib/capybara/spec/session/all_spec.rb +6 -8
- data/lib/capybara/spec/session/assert_text_spec.rb +17 -17
- data/lib/capybara/spec/session/attach_file_spec.rb +6 -0
- data/lib/capybara/spec/session/check_spec.rb +1 -0
- data/lib/capybara/spec/session/click_link_spec.rb +11 -0
- data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
- data/lib/capybara/spec/session/find_link_spec.rb +10 -0
- data/lib/capybara/spec/session/find_spec.rb +7 -1
- data/lib/capybara/spec/session/first_spec.rb +1 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +2 -0
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
- data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -2
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +2 -2
- data/lib/capybara/spec/session/has_button_spec.rb +6 -0
- data/lib/capybara/spec/session/has_current_path_spec.rb +3 -3
- data/lib/capybara/spec/session/has_field_spec.rb +1 -1
- data/lib/capybara/spec/session/has_link_spec.rb +16 -0
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
- data/lib/capybara/spec/session/has_select_spec.rb +10 -4
- data/lib/capybara/spec/session/has_selector_spec.rb +15 -0
- data/lib/capybara/spec/session/has_text_spec.rb +5 -13
- data/lib/capybara/spec/session/matches_style_spec.rb +2 -0
- data/lib/capybara/spec/session/node_spec.rb +81 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +13 -0
- data/lib/capybara/spec/session/scroll_spec.rb +3 -1
- data/lib/capybara/spec/session/visit_spec.rb +20 -0
- data/lib/capybara/spec/session/window/window_spec.rb +1 -1
- data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
- data/lib/capybara/spec/session/within_spec.rb +13 -0
- data/lib/capybara/spec/spec_helper.rb +8 -2
- data/lib/capybara/spec/test_app.rb +74 -6
- data/lib/capybara/spec/views/form.erb +17 -0
- data/lib/capybara/spec/views/with_html.erb +3 -3
- data/lib/capybara/spec/views/with_scope.erb +2 -2
- data/lib/capybara/spec/views/with_shadow.erb +31 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +1 -1
- data/lib/capybara.rb +5 -2
- data/spec/capybara_spec.rb +12 -0
- data/spec/counter_spec.rb +35 -0
- data/spec/css_builder_spec.rb +1 -1
- data/spec/css_splitter_spec.rb +1 -1
- data/spec/dsl_spec.rb +4 -2
- data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -2
- data/spec/fixtures/selenium_driver_rspec_success.rb +2 -2
- data/spec/minitest_spec.rb +4 -0
- data/spec/minitest_spec_spec.rb +4 -0
- data/spec/per_session_config_spec.rb +1 -1
- data/spec/rack_test_spec.rb +16 -2
- data/spec/result_spec.rb +27 -29
- data/spec/rspec/features_spec.rb +2 -2
- data/spec/rspec/scenarios_spec.rb +2 -2
- data/spec/rspec/shared_spec_matchers.rb +1 -1
- data/spec/rspec_matchers_spec.rb +25 -0
- data/spec/rspec_spec.rb +2 -2
- data/spec/sauce_spec_chrome.rb +4 -4
- data/spec/selector_spec.rb +4 -4
- data/spec/selenium_spec_chrome.rb +8 -7
- data/spec/selenium_spec_chrome_remote.rb +9 -9
- data/spec/selenium_spec_edge.rb +12 -6
- data/spec/selenium_spec_firefox.rb +21 -5
- data/spec/selenium_spec_firefox_remote.rb +19 -4
- data/spec/selenium_spec_ie.rb +4 -2
- data/spec/selenium_spec_safari.rb +8 -2
- data/spec/server_spec.rb +7 -7
- data/spec/shared_selenium_session.rb +13 -6
- data/spec/spec_helper.rb +35 -2
- data/spec/whitespace_normalizer_spec.rb +54 -0
- data/spec/xpath_builder_spec.rb +1 -1
- metadata +9 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0945d8fedaab75fa31a90d12105de7318d78c20a46955a1b78ae88dc791f6a5a'
|
|
4
|
+
data.tar.gz: 9a59ca68ff9d44ef28597603ed275ebef28c79c8b6fb76ffdc26daaee68ab383
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dbb58a338e2408140ce5e6a44bc141fc44833952c10f611996f5a217c9a0ad00f8d6344a1c16b0bf53000801f9e1d45ef3848cb0fa886dabe68c6d766a42372a
|
|
7
|
+
data.tar.gz: db985c0c947ff348c80008fd4c90232a0ad4dcd38dbe8694b157ecfb512c099d6e9bc08177d8a115e1db17cca35c68903e10662da0fdd14c4f1a2ab671932b16
|
data/History.md
CHANGED
|
@@ -1,3 +1,93 @@
|
|
|
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
|
+
|
|
1
91
|
# Version 3.36.0
|
|
2
92
|
Release date: 2021-10-24
|
|
3
93
|
|
|
@@ -10,7 +100,7 @@ Release date: 2021-10-24
|
|
|
10
100
|
|
|
11
101
|
* Support for selenium-webdriver 4.x
|
|
12
102
|
* `allow_label_click` accepts click options to be used when clicking an associated label
|
|
13
|
-
* Deprecated `allow_gumbo=` in favor of `use_html5_parsing=` to enable use of Nokogiri::
|
|
103
|
+
* Deprecated `allow_gumbo=` in favor of `use_html5_parsing=` to enable use of Nokogiri::HTML5 when available
|
|
14
104
|
* `Session#active_element` returns the element with focus - Not supported by the `RackTest` driver [Sean Doyle]
|
|
15
105
|
* Support `focused:` filter for finding interactive elements - Not supported by the `RackTest` driver [Sean Doyle]
|
|
16
106
|
|
|
@@ -784,7 +874,7 @@ Release date: 2018-03-23
|
|
|
784
874
|
|
|
785
875
|
### Changed
|
|
786
876
|
|
|
787
|
-
*
|
|
877
|
+
* Visible text whitespace is no longer fully normalized in favor of being more in line with the WebDriver spec for visible text
|
|
788
878
|
* Drivers are expected to close extra windows when resetting the session
|
|
789
879
|
* Selenium driver supports Date/Time when filling in date/time/datetime-local inputs
|
|
790
880
|
* `current_url` returns the url for the top level browsing context
|
|
@@ -1190,7 +1280,7 @@ Release date: 2016-01-27
|
|
|
1190
1280
|
|
|
1191
1281
|
# Version 2.6.0
|
|
1192
1282
|
|
|
1193
|
-
|
|
1283
|
+
Release date: 2016-01-17
|
|
1194
1284
|
|
|
1195
1285
|
### Fixed
|
|
1196
1286
|
|
|
@@ -1254,7 +1344,7 @@ Release date: 2014-10-13
|
|
|
1254
1344
|
|
|
1255
1345
|
# Version 2.4.3
|
|
1256
1346
|
|
|
1257
|
-
|
|
1347
|
+
Release date: 2014-09-21
|
|
1258
1348
|
|
|
1259
1349
|
### Fixed
|
|
1260
1350
|
|
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.
|
|
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
|
|
@@ -161,7 +161,7 @@ You can now write your specs like so:
|
|
|
161
161
|
```ruby
|
|
162
162
|
describe "the signin process", type: :feature do
|
|
163
163
|
before :each do
|
|
164
|
-
User.
|
|
164
|
+
User.create(email: 'user@example.com', password: 'password')
|
|
165
165
|
end
|
|
166
166
|
|
|
167
167
|
it "signs me in" do
|
|
@@ -192,7 +192,7 @@ Capybara also comes with a built in DSL for creating descriptive acceptance test
|
|
|
192
192
|
```ruby
|
|
193
193
|
feature "Signing in" do
|
|
194
194
|
background do
|
|
195
|
-
User.
|
|
195
|
+
User.create(email: 'user@example.com', password: 'caplin')
|
|
196
196
|
end
|
|
197
197
|
|
|
198
198
|
scenario "Signing in with correct credentials" do
|
|
@@ -205,7 +205,7 @@ feature "Signing in" do
|
|
|
205
205
|
expect(page).to have_content 'Success'
|
|
206
206
|
end
|
|
207
207
|
|
|
208
|
-
given(:other_user) { User.
|
|
208
|
+
given(:other_user) { User.create(email: 'other@example.com', password: 'rous') }
|
|
209
209
|
|
|
210
210
|
scenario "Signing in as another user" do
|
|
211
211
|
visit '/sessions/new'
|
|
@@ -336,7 +336,7 @@ By default, Capybara uses the `:rack_test` driver, which is fast but limited: it
|
|
|
336
336
|
does not support JavaScript, nor is it able to access HTTP resources outside of
|
|
337
337
|
your Rack application, such as remote APIs and OAuth services. To get around
|
|
338
338
|
these limitations, you can set up a different default driver for your features.
|
|
339
|
-
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:
|
|
340
340
|
|
|
341
341
|
```ruby
|
|
342
342
|
Capybara.default_driver = :selenium # :selenium_chrome and :selenium_chrome_headless are also registered
|
|
@@ -630,7 +630,7 @@ JS
|
|
|
630
630
|
|
|
631
631
|
### <a name="modals"></a>Modals
|
|
632
632
|
|
|
633
|
-
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.
|
|
634
634
|
|
|
635
635
|
You can accept or dismiss alert messages by wrapping the code that produces an alert in a block:
|
|
636
636
|
|
|
@@ -781,7 +781,7 @@ expect(page).to have_content('baz')
|
|
|
781
781
|
If clicking on the *foo* link triggers an asynchronous process, such as
|
|
782
782
|
an Ajax request, which, when complete will add the *bar* link to the page,
|
|
783
783
|
clicking on the *bar* link would be expected to fail, since that link doesn't
|
|
784
|
-
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
|
|
785
785
|
brief period of time before giving up and throwing an error. The same is true of
|
|
786
786
|
the next line, which looks for the content *baz* on the page; it will retry
|
|
787
787
|
looking for that content for a brief time. You can adjust how long this period
|
|
@@ -795,13 +795,25 @@ Be aware that because of this behaviour, the following two statements are **not*
|
|
|
795
795
|
equivalent, and you should **always** use the latter!
|
|
796
796
|
|
|
797
797
|
```ruby
|
|
798
|
-
|
|
799
|
-
|
|
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
|
|
800
804
|
```
|
|
801
805
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
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`
|
|
805
817
|
|
|
806
818
|
Capybara's RSpec matchers, however, are smart enough to handle either form.
|
|
807
819
|
The two following statements are functionally equivalent:
|
data/lib/capybara/driver/node.rb
CHANGED
|
@@ -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
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
54
|
+
METHOD
|
|
61
55
|
end
|
|
62
56
|
end
|
|
63
57
|
|
data/lib/capybara/helpers.rb
CHANGED
|
@@ -73,7 +73,7 @@ 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
78
|
new_trace = trace.grep_v(filter) if new_trace.empty?
|
|
79
79
|
new_trace = trace.dup if new_trace.empty?
|
|
@@ -85,7 +85,11 @@ module Capybara
|
|
|
85
85
|
Kernel.warn(message, uplevel: uplevel)
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
-
if defined?(Process::
|
|
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)
|
|
89
93
|
def monotonic_time; Process.clock_gettime Process::CLOCK_MONOTONIC; end
|
|
90
94
|
else
|
|
91
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(
|
|
249
|
+
def must_have_style(...)
|
|
250
250
|
warn 'must_have_style is deprecated, please use must_match_style'
|
|
251
|
-
must_match_style(
|
|
251
|
+
must_match_style(...)
|
|
252
252
|
end
|
|
253
253
|
end
|
|
254
254
|
end
|
|
@@ -383,7 +383,7 @@ module Capybara
|
|
|
383
383
|
end
|
|
384
384
|
end
|
|
385
385
|
|
|
386
|
-
UPDATE_STYLE_SCRIPT = <<~
|
|
386
|
+
UPDATE_STYLE_SCRIPT = <<~JS
|
|
387
387
|
this.capybara_style_cache = this.style.cssText;
|
|
388
388
|
var css = arguments[0];
|
|
389
389
|
for (var prop in css){
|
|
@@ -393,20 +393,20 @@ module Capybara
|
|
|
393
393
|
}
|
|
394
394
|
JS
|
|
395
395
|
|
|
396
|
-
RESET_STYLE_SCRIPT = <<~
|
|
396
|
+
RESET_STYLE_SCRIPT = <<~JS
|
|
397
397
|
if (this.hasOwnProperty('capybara_style_cache')) {
|
|
398
398
|
this.style.cssText = this.capybara_style_cache;
|
|
399
399
|
delete this.capybara_style_cache;
|
|
400
400
|
}
|
|
401
401
|
JS
|
|
402
402
|
|
|
403
|
-
DATALIST_OPTIONS_SCRIPT = <<~
|
|
403
|
+
DATALIST_OPTIONS_SCRIPT = <<~JS
|
|
404
404
|
Array.prototype.slice.call((this.list||{}).options || []).
|
|
405
405
|
filter(function(el){ return !el.disabled }).
|
|
406
406
|
map(function(el){ return { "value": el.value, "label": el.label} })
|
|
407
407
|
JS
|
|
408
408
|
|
|
409
|
-
CAPTURE_FILE_ELEMENT_SCRIPT = <<~
|
|
409
|
+
CAPTURE_FILE_ELEMENT_SCRIPT = <<~JS
|
|
410
410
|
document.addEventListener('click', function file_catcher(e){
|
|
411
411
|
if (e.target.matches("input[type='file']")) {
|
|
412
412
|
window._capybara_clicked_file_input = e.target;
|
data/lib/capybara/node/base.rb
CHANGED
|
@@ -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
|
|
92
|
+
sleep interval
|
|
92
93
|
reload if session_options.automatic_reload
|
|
93
94
|
else
|
|
94
95
|
old_base = @base
|
|
@@ -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
|
|
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
|
|
@@ -18,7 +18,7 @@ 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,
|
|
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
|
|
@@ -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
|
#
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Capybara
|
|
4
|
+
module Node
|
|
5
|
+
##
|
|
6
|
+
#
|
|
7
|
+
# {Capybara::Node::WhitespaceNormalizer} provides methods that
|
|
8
|
+
# help to normalize the spacing of text content inside of
|
|
9
|
+
# {Capybara::Node::Element}s by removing various unicode
|
|
10
|
+
# spacing and directional markings.
|
|
11
|
+
#
|
|
12
|
+
module WhitespaceNormalizer
|
|
13
|
+
# Unicode for NBSP, or
|
|
14
|
+
NON_BREAKING_SPACE = "\u00a0"
|
|
15
|
+
LINE_SEPERATOR = "\u2028"
|
|
16
|
+
PARAGRAPH_SEPERATOR = "\u2029"
|
|
17
|
+
|
|
18
|
+
# All spaces except for NBSP
|
|
19
|
+
BREAKING_SPACES = "[[:space:]&&[^#{NON_BREAKING_SPACE}]]"
|
|
20
|
+
|
|
21
|
+
# Whitespace we want to substitute with plain spaces
|
|
22
|
+
SQUEEZED_SPACES = " \n\f\t\v#{LINE_SEPERATOR}#{PARAGRAPH_SEPERATOR}"
|
|
23
|
+
|
|
24
|
+
# Any whitespace at the front of text
|
|
25
|
+
LEADING_SPACES = /\A#{BREAKING_SPACES}+/.freeze
|
|
26
|
+
|
|
27
|
+
# Any whitespace at the end of text
|
|
28
|
+
TRAILING_SPACES = /#{BREAKING_SPACES}+\z/.freeze
|
|
29
|
+
|
|
30
|
+
# "Invisible" space character
|
|
31
|
+
ZERO_WIDTH_SPACE = "\u200b"
|
|
32
|
+
|
|
33
|
+
# Signifies text is read left to right
|
|
34
|
+
LEFT_TO_RIGHT_MARK = "\u200e"
|
|
35
|
+
|
|
36
|
+
# Signifies text is read right to left
|
|
37
|
+
RIGHT_TO_LEFT_MARK = "\u200f"
|
|
38
|
+
|
|
39
|
+
# Characters we want to truncate from text
|
|
40
|
+
REMOVED_CHARACTERS = [ZERO_WIDTH_SPACE, LEFT_TO_RIGHT_MARK, RIGHT_TO_LEFT_MARK].join
|
|
41
|
+
|
|
42
|
+
# Matches multiple empty lines
|
|
43
|
+
EMPTY_LINES = /[\ \n]*\n[\ \n]*/.freeze
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
#
|
|
47
|
+
# Normalizes the spacing of a node's text to be similar to
|
|
48
|
+
# what matchers might expect.
|
|
49
|
+
#
|
|
50
|
+
# @param text [String]
|
|
51
|
+
# @return [String]
|
|
52
|
+
#
|
|
53
|
+
def normalize_spacing(text)
|
|
54
|
+
text
|
|
55
|
+
.delete(REMOVED_CHARACTERS)
|
|
56
|
+
.tr(SQUEEZED_SPACES, ' ')
|
|
57
|
+
.squeeze(' ')
|
|
58
|
+
.sub(LEADING_SPACES, '')
|
|
59
|
+
.sub(TRAILING_SPACES, '')
|
|
60
|
+
.tr(NON_BREAKING_SPACE, ' ')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
##
|
|
64
|
+
#
|
|
65
|
+
# Variant on {Capybara::Node::Normalizer#normalize_spacing} that
|
|
66
|
+
# targets the whitespace of visible elements only.
|
|
67
|
+
#
|
|
68
|
+
# @param text [String]
|
|
69
|
+
# @return [String]
|
|
70
|
+
#
|
|
71
|
+
def normalize_visible_spacing(text)
|
|
72
|
+
text
|
|
73
|
+
.squeeze(' ')
|
|
74
|
+
.gsub(EMPTY_LINES, "\n")
|
|
75
|
+
.sub(LEADING_SPACES, '')
|
|
76
|
+
.sub(TRAILING_SPACES, '')
|
|
77
|
+
.tr(NON_BREAKING_SPACE, ' ')
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -79,8 +79,8 @@ module Capybara
|
|
|
79
79
|
if count
|
|
80
80
|
message << " #{occurrences count}"
|
|
81
81
|
elsif between
|
|
82
|
-
message << " between #{between.begin ? between.first : 1} and" \
|
|
83
|
-
"
|
|
82
|
+
message << " between #{between.begin ? between.first : 1} and " \
|
|
83
|
+
"#{between.end ? between.last : 'infinite'} times"
|
|
84
84
|
elsif maximum
|
|
85
85
|
message << " at most #{occurrences maximum}"
|
|
86
86
|
elsif minimum
|
|
@@ -27,6 +27,12 @@ module Capybara
|
|
|
27
27
|
@order = order
|
|
28
28
|
@filter_cache = Hash.new { |hsh, key| hsh[key] = {} }
|
|
29
29
|
|
|
30
|
+
if @options[:text].is_a?(Regexp) && [true, false].include?(@options[:exact_text])
|
|
31
|
+
Capybara::Helpers.warn(
|
|
32
|
+
"Boolean 'exact_text' option is not supported when 'text' option is a Regexp - ignoring"
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
30
36
|
super(@options)
|
|
31
37
|
self.session_options = session_options
|
|
32
38
|
|
|
@@ -266,7 +272,7 @@ module Capybara
|
|
|
266
272
|
end
|
|
267
273
|
|
|
268
274
|
def valid_keys
|
|
269
|
-
VALID_KEYS + custom_keys
|
|
275
|
+
(VALID_KEYS + custom_keys).uniq
|
|
270
276
|
end
|
|
271
277
|
|
|
272
278
|
def matches_node_filters?(node, errors)
|
|
@@ -541,16 +547,19 @@ module Capybara
|
|
|
541
547
|
def matches_text_filter?(node)
|
|
542
548
|
value = options[:text]
|
|
543
549
|
return true unless value
|
|
544
|
-
return matches_text_exactly?(node, value) if exact_text == true
|
|
550
|
+
return matches_text_exactly?(node, value) if exact_text == true && !value.is_a?(Regexp)
|
|
545
551
|
|
|
546
552
|
regexp = value.is_a?(Regexp) ? value : Regexp.escape(value.to_s)
|
|
547
553
|
matches_text_regexp?(node, regexp)
|
|
548
554
|
end
|
|
549
555
|
|
|
550
556
|
def matches_exact_text_filter?(node)
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
557
|
+
case exact_text
|
|
558
|
+
when String, Regexp
|
|
559
|
+
matches_text_exactly?(node, exact_text)
|
|
560
|
+
else
|
|
561
|
+
true
|
|
562
|
+
end
|
|
554
563
|
end
|
|
555
564
|
|
|
556
565
|
def matches_visibility_filters?(node)
|
|
@@ -561,7 +570,9 @@ module Capybara
|
|
|
561
570
|
when :visible
|
|
562
571
|
node.initial_cache[:visible] || (node.initial_cache[:visible].nil? && node.visible?)
|
|
563
572
|
when :hidden
|
|
564
|
-
|
|
573
|
+
# TODO: check why the 'visbile' cache spelling mistake wasn't caught in a test
|
|
574
|
+
# (node.initial_cache[:visible] == false) || (node.initial_cache[:visbile].nil? && !node.visible?)
|
|
575
|
+
(node.initial_cache[:visible] == false) || (node.initial_cache[:visible].nil? && !node.visible?)
|
|
565
576
|
else
|
|
566
577
|
true
|
|
567
578
|
end
|
|
@@ -578,17 +589,21 @@ module Capybara
|
|
|
578
589
|
|
|
579
590
|
def matches_text_exactly?(node, value)
|
|
580
591
|
regexp = value.is_a?(Regexp) ? value : /\A#{Regexp.escape(value.to_s)}\z/
|
|
581
|
-
matches_text_regexp
|
|
592
|
+
matches_text_regexp(node, regexp).then { |m| m&.pre_match == '' && m&.post_match == '' }
|
|
582
593
|
end
|
|
583
594
|
|
|
584
595
|
def normalize_ws
|
|
585
596
|
options.fetch(:normalize_ws, session_options.default_normalize_ws)
|
|
586
597
|
end
|
|
587
598
|
|
|
588
|
-
def matches_text_regexp
|
|
599
|
+
def matches_text_regexp(node, regexp)
|
|
589
600
|
text_visible = visible
|
|
590
601
|
text_visible = :all if text_visible == :hidden
|
|
591
|
-
node.text(text_visible, normalize_ws: normalize_ws).match
|
|
602
|
+
node.text(text_visible, normalize_ws: normalize_ws).match(regexp)
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
def matches_text_regexp?(node, regexp)
|
|
606
|
+
!matches_text_regexp(node, regexp).nil?
|
|
592
607
|
end
|
|
593
608
|
|
|
594
609
|
def default_visibility
|
|
@@ -13,7 +13,7 @@ module Capybara
|
|
|
13
13
|
self.session_options = session_options
|
|
14
14
|
|
|
15
15
|
if expected_text.nil? && !exact?
|
|
16
|
-
warn 'Checking for expected text of nil is confusing and/or pointless since it will always match. '\
|
|
16
|
+
warn 'Checking for expected text of nil is confusing and/or pointless since it will always match. ' \
|
|
17
17
|
"Please specify a string or regexp instead. #{Capybara::Helpers.filter_backtrace(caller)}"
|
|
18
18
|
end
|
|
19
19
|
|