capybara 3.39.2 → 3.40.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +22 -0
- data/README.md +173 -29
- data/lib/capybara/helpers.rb +1 -1
- data/lib/capybara/minitest/spec.rb +16 -4
- data/lib/capybara/minitest.rb +14 -1
- data/lib/capybara/node/matchers.rb +25 -0
- data/lib/capybara/node/whitespace_normalizer.rb +5 -5
- data/lib/capybara/queries/selector_query.rb +2 -1
- data/lib/capybara/rack_test/browser.rb +3 -2
- data/lib/capybara/rack_test/node.rb +5 -12
- data/lib/capybara/registration_container.rb +2 -2
- data/lib/capybara/registrations/drivers.rb +1 -1
- data/lib/capybara/registrations/servers.rb +8 -7
- data/lib/capybara/result.rb +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +4 -12
- data/lib/capybara/rspec/matchers.rb +7 -2
- data/lib/capybara/selector/css.rb +5 -5
- data/lib/capybara/selector/definition/table.rb +1 -1
- data/lib/capybara/selector/definition/table_row.rb +2 -2
- data/lib/capybara/selector.rb +251 -0
- data/lib/capybara/selenium/driver.rb +11 -51
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +1 -6
- data/lib/capybara/selenium/node.rb +4 -31
- data/lib/capybara/selenium/nodes/chrome_node.rb +3 -19
- data/lib/capybara/selenium/nodes/edge_node.rb +0 -16
- data/lib/capybara/server/animation_disabler.rb +1 -1
- data/lib/capybara/server.rb +1 -1
- data/lib/capybara/session.rb +3 -2
- data/lib/capybara/spec/session/all_spec.rb +1 -1
- data/lib/capybara/spec/session/click_link_spec.rb +1 -1
- data/lib/capybara/spec/session/find_spec.rb +8 -0
- data/lib/capybara/spec/session/has_element_spec.rb +47 -0
- data/lib/capybara/spec/session/has_table_spec.rb +13 -2
- data/lib/capybara/spec/session/node_spec.rb +6 -0
- data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
- data/lib/capybara/spec/session/uncheck_spec.rb +1 -1
- data/lib/capybara/spec/spec_helper.rb +2 -2
- data/lib/capybara/spec/test_app.rb +1 -1
- data/lib/capybara/spec/views/form.erb +5 -0
- data/lib/capybara/spec/views/with_html.erb +2 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara.rb +7 -6
- data/spec/minitest_spec.rb +8 -1
- data/spec/result_spec.rb +9 -0
- data/spec/rspec/shared_spec_matchers.rb +26 -2
- data/spec/rspec_spec.rb +1 -1
- data/spec/sauce_spec_chrome.rb +1 -1
- data/spec/selector_spec.rb +1 -1
- data/spec/selenium_spec_chrome.rb +7 -5
- data/spec/selenium_spec_chrome_remote.rb +0 -5
- data/spec/selenium_spec_edge.rb +11 -4
- data/spec/selenium_spec_firefox.rb +4 -3
- data/spec/selenium_spec_firefox_remote.rb +2 -3
- data/spec/server_spec.rb +12 -0
- data/spec/shared_selenium_session.rb +0 -2
- data/spec/spec_helper.rb +2 -2
- metadata +25 -32
- data/lib/capybara/selenium/logger_suppressor.rb +0 -44
- data/lib/capybara/selenium/patches/action_pauser.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0537a83e6809595a8e15b9c450f4f4b0976c5ebf1327cc0611ae20a05b3574b
|
4
|
+
data.tar.gz: c3035e7a05874cc93ab27c6aea26e529dea4c3b63bd5d3281deaaf34c45a91b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48c7bc5cbfc8e3324ea09d937a207299ad91ffc2e255dbbb7ed13265e4541c3672271ccb2f19b3902588d5c649cb6f561b7c483e7b815b824ccf37df8bbb5075
|
7
|
+
data.tar.gz: 5b3a9cc9a6ba6ed67a54ef381c00ed9cc94027d26bdfc98ba1c509a097c9dc123d39bd72a6a5728e5b5b4e503202e475889d22cf47c07ce88eb7afedf604ed83
|
data/History.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
#Version 3.40.0
|
2
|
+
Release date: 2024-01-26
|
3
|
+
|
4
|
+
### Changned
|
5
|
+
|
6
|
+
* Dropped support for Ruby 2.7, 3.0+ is now required
|
7
|
+
* Dropped support for Selenium < 4.8
|
8
|
+
* Use the new headless option on chromedriver with registered selenium driver [Neil Carvalho]
|
9
|
+
|
10
|
+
### Added
|
11
|
+
|
12
|
+
* `Capybara::Result#to_ary` to support multiple assignment [Sean Doyle]
|
13
|
+
* `has_element?` and related matchers [Sean Doyle]
|
14
|
+
* Rack 3 support
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
|
18
|
+
* Forward save_screenshot options to selenium - Issue 2738
|
19
|
+
* Rack test - don't auto submit forms with multiple inputs [Mitchell Henke]
|
20
|
+
* Table row selector matches cell values in order - Issue 2686 [Jeff Parr]
|
21
|
+
* Table row selector fixes for first column - Issue 2685 [Jeff Par]
|
22
|
+
|
1
23
|
# Version 3.39.2
|
2
24
|
Release date: 2023-06-10
|
3
25
|
|
data/README.md
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
# Capybara
|
2
2
|
|
3
|
-
[![Build Status](https://
|
4
|
-
[![Build Status](https://ci.appveyor.com/api/projects/status/github/teamcapybara/capybara?svg=true)](https://ci.appveyor.com/api/projects/github/teamcapybara/capybara)
|
3
|
+
[![Build Status](https://github.com/teamcapybara/capybara/actions/workflows/build.yml/badge.svg)](https://github.com/teamcapybara/capybara/actions/workflows/build.yml)
|
5
4
|
[![Code Climate](https://codeclimate.com/github/teamcapybara/capybara.svg)](https://codeclimate.com/github/teamcapybara/capybara)
|
6
5
|
[![Coverage Status](https://coveralls.io/repos/github/teamcapybara/capybara/badge.svg?branch=master)](https://coveralls.io/github/teamcapybara/capybara?branch=master)
|
7
|
-
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jnicklas/capybara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
8
|
-
[![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=capybara&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=capybara&package-manager=bundler&version-scheme=semver)
|
9
6
|
|
10
7
|
Capybara helps you test web applications by simulating how a real user would
|
11
8
|
interact with your app. It is agnostic about the driver running your tests and
|
@@ -18,8 +15,7 @@ If you and/or your company find value in Capybara and would like to contribute f
|
|
18
15
|
<a href="https://www.patreon.com/capybara">Patreon</a>
|
19
16
|
|
20
17
|
|
21
|
-
**Need help?** Ask on the
|
22
|
-
GitHub): http://groups.google.com/group/ruby-capybara
|
18
|
+
**Need help?** Ask on the discussions (please do not open an issue): https://github.com/orgs/teamcapybara/discussions/categories/q-a
|
23
19
|
|
24
20
|
## Table of contents
|
25
21
|
|
@@ -34,7 +30,6 @@ GitHub): http://groups.google.com/group/ruby-capybara
|
|
34
30
|
- [Selecting the Driver](#selecting-the-driver)
|
35
31
|
- [RackTest](#racktest)
|
36
32
|
- [Selenium](#selenium)
|
37
|
-
- [Apparition](#apparition)
|
38
33
|
- [The DSL](#the-dsl)
|
39
34
|
- [Navigating](#navigating)
|
40
35
|
- [Clicking links and buttons](#clicking-links-and-buttons)
|
@@ -46,6 +41,10 @@ GitHub): http://groups.google.com/group/ruby-capybara
|
|
46
41
|
- [Scripting](#scripting)
|
47
42
|
- [Modals](#modals)
|
48
43
|
- [Debugging](#debugging)
|
44
|
+
- [Selectors](#selectors)
|
45
|
+
- [Name](#selectors-name)
|
46
|
+
- [Locator](#selectors-locator)
|
47
|
+
- [Filters](#selectors-filters)
|
49
48
|
- [Matching](#matching)
|
50
49
|
- [Exactness](#exactness)
|
51
50
|
- [Strategy](#strategy)
|
@@ -74,7 +73,7 @@ GitHub): http://groups.google.com/group/ruby-capybara
|
|
74
73
|
|
75
74
|
## <a name="setup"></a>Setup
|
76
75
|
|
77
|
-
Capybara requires Ruby
|
76
|
+
Capybara requires Ruby 3.0.0 or later. To install, add this line to your
|
78
77
|
`Gemfile` and run `bundle install`:
|
79
78
|
|
80
79
|
```ruby
|
@@ -145,13 +144,13 @@ Load RSpec 3.5+ support by adding the following line (typically to your
|
|
145
144
|
require 'capybara/rspec'
|
146
145
|
```
|
147
146
|
|
148
|
-
If you are using Rails, put your Capybara specs in `spec/features` or `spec/system` (only works
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
example groups with `type: :feature` or `type: :system` depending on which type of test you're writing.
|
147
|
+
If you are using Rails, put your Capybara specs in `spec/features` or `spec/system` (only works if
|
148
|
+
[you have it configured in RSpec](https://rspec.info/features/6-0/rspec-rails/directory-structure/))
|
149
|
+
and if you have your Capybara specs in a different directory, then tag the example groups with
|
150
|
+
`type: :feature` or `type: :system` depending on which type of test you're writing.
|
153
151
|
|
154
|
-
If you are using Rails system specs please see [their documentation](https://
|
152
|
+
If you are using Rails system specs please see [their documentation](https://rspec.info/features/6-0/rspec-rails/system-specs/system-specs)
|
153
|
+
for selecting the driver you wish to use.
|
155
154
|
|
156
155
|
If you are not using Rails, tag all the example groups in which you want to use
|
157
156
|
Capybara with `type: :feature`.
|
@@ -183,7 +182,7 @@ to one specific driver. For example:
|
|
183
182
|
```ruby
|
184
183
|
describe 'some stuff which requires js', js: true do
|
185
184
|
it 'will use the default js driver'
|
186
|
-
it 'will switch to one specific driver', driver: :
|
185
|
+
it 'will switch to one specific driver', driver: :selenium
|
187
186
|
end
|
188
187
|
```
|
189
188
|
|
@@ -353,7 +352,7 @@ You can also change the driver temporarily (typically in the Before/setup and
|
|
353
352
|
After/teardown blocks):
|
354
353
|
|
355
354
|
```ruby
|
356
|
-
Capybara.current_driver = :
|
355
|
+
Capybara.current_driver = :selenium # temporarily select different driver
|
357
356
|
# tests here
|
358
357
|
Capybara.use_default_driver # switch back to default driver
|
359
358
|
```
|
@@ -409,15 +408,6 @@ to the browsers. See the section on adding and configuring drivers.
|
|
409
408
|
same transaction as your tests, causing data not to be shared between your test
|
410
409
|
and test server, see [Transactions and database setup](#transactions-and-database-setup) below.
|
411
410
|
|
412
|
-
### <a name="apparition"></a>Apparition
|
413
|
-
|
414
|
-
The [apparition driver](https://github.com/twalpole/apparition) is a new driver that allows you to run tests using Chrome in a headless
|
415
|
-
or headed configuration. It attempts to provide backwards compatibility with the [Poltergeist driver API](https://github.com/teampoltergeist/poltergeist)
|
416
|
-
and [capybara-webkit API](https://github.com/thoughtbot/capybara-webkit) while allowing for the use of modern JS/CSS. It
|
417
|
-
uses CDP to communicate with Chrome, thereby obviating the need for chromedriver. This driver is being developed by the
|
418
|
-
current developer of Capybara and will attempt to keep up to date with new Capybara releases. It will probably be moved into the
|
419
|
-
teamcapybara repo once it reaches v1.0.
|
420
|
-
|
421
411
|
## <a name="the-dsl"></a>The DSL
|
422
412
|
|
423
413
|
*A complete reference is available at
|
@@ -632,10 +622,10 @@ JS
|
|
632
622
|
|
633
623
|
In drivers which support it, you can accept, dismiss and respond to alerts, confirms, and prompts.
|
634
624
|
|
635
|
-
You can accept
|
625
|
+
You can accept alert messages by wrapping the code that produces an alert in a block:
|
636
626
|
|
637
627
|
```ruby
|
638
|
-
accept_alert do
|
628
|
+
accept_alert 'optional text or regex' do
|
639
629
|
click_link('Show Alert')
|
640
630
|
end
|
641
631
|
```
|
@@ -643,7 +633,13 @@ end
|
|
643
633
|
You can accept or dismiss a confirmation by wrapping it in a block, as well:
|
644
634
|
|
645
635
|
```ruby
|
646
|
-
|
636
|
+
accept_confirm 'optional text' do
|
637
|
+
click_link('Show Confirm')
|
638
|
+
end
|
639
|
+
```
|
640
|
+
|
641
|
+
```ruby
|
642
|
+
dismiss_confirm 'optional text' do
|
647
643
|
click_link('Show Confirm')
|
648
644
|
end
|
649
645
|
```
|
@@ -651,7 +647,13 @@ end
|
|
651
647
|
You can accept or dismiss prompts as well, and also provide text to fill in for the response:
|
652
648
|
|
653
649
|
```ruby
|
654
|
-
accept_prompt(with: 'Linus Torvalds') do
|
650
|
+
accept_prompt('optional text', with: 'Linus Torvalds') do
|
651
|
+
click_link('Show Prompt About Linux')
|
652
|
+
end
|
653
|
+
```
|
654
|
+
|
655
|
+
```ruby
|
656
|
+
dismiss_prompt('optional text') do
|
655
657
|
click_link('Show Prompt About Linux')
|
656
658
|
end
|
657
659
|
```
|
@@ -701,6 +703,148 @@ Screenshots are saved to `Capybara.save_path`, relative to the app directory.
|
|
701
703
|
If you have required `capybara/rails`, `Capybara.save_path` will default to
|
702
704
|
`tmp/capybara`.
|
703
705
|
|
706
|
+
## <a name="selectors"></a>Selectors
|
707
|
+
|
708
|
+
Helpers and matchers that accept Selectors share a common method signature that
|
709
|
+
includes:
|
710
|
+
|
711
|
+
1. a positional Name argument
|
712
|
+
2. a positional Locator argument
|
713
|
+
3. keyword Filter arguments
|
714
|
+
4. a predicate Filter block argument
|
715
|
+
|
716
|
+
These arguments are usually optional in one way or another.
|
717
|
+
|
718
|
+
### <a name="selectors-name"></a>Name
|
719
|
+
|
720
|
+
The name argument determines the Selector to use. The argument is optional when
|
721
|
+
a helper explicitly conveys the selector name (for example, [`find_field`][]
|
722
|
+
uses `:field`, [`find_link`][] uses `:link`, etc):
|
723
|
+
|
724
|
+
```ruby
|
725
|
+
page.html # => '<a href="/">Home</a>'
|
726
|
+
|
727
|
+
page.find(:link) == page.find_link
|
728
|
+
|
729
|
+
page.html # => '<input>'
|
730
|
+
|
731
|
+
page.find(:field) == page.find_field
|
732
|
+
```
|
733
|
+
|
734
|
+
### <a name="selectors-locator"></a>Locator
|
735
|
+
|
736
|
+
The locator argument usually represents information that can most meaningfully
|
737
|
+
distinguish an element that matches the selector from an element that does not:
|
738
|
+
|
739
|
+
```ruby
|
740
|
+
page.html # => '<div id="greeting">Hello world</div>'
|
741
|
+
|
742
|
+
page.find(:css, 'div').text # => 'Hello world'
|
743
|
+
page.find(:xpath, './/div').text # => 'Hello world'
|
744
|
+
```
|
745
|
+
|
746
|
+
General purpose finder methods like [`find`][] and [`all`][] can accept the
|
747
|
+
locator as their first positional argument when the method can infer the default
|
748
|
+
value from the [`Capybara.default_selector`][] configuration:
|
749
|
+
|
750
|
+
```ruby
|
751
|
+
page.html # => '<div id="greeting">Hello world</div>'
|
752
|
+
|
753
|
+
Capybara.default_selector = :css
|
754
|
+
|
755
|
+
page.find('div').text # => 'Hello world'
|
756
|
+
|
757
|
+
Capybara.default_selector = :xpath
|
758
|
+
|
759
|
+
page.find('.//div').text # => 'Hello world'
|
760
|
+
```
|
761
|
+
|
762
|
+
The locator argument's semantics are context-specific, and depend on the
|
763
|
+
selector. The types of arguments are varied. Some selectors support `String` or
|
764
|
+
`Regexp` arguments, while others like `:table_row` support `Array<String>` and
|
765
|
+
`Hash<String, String>`:
|
766
|
+
|
767
|
+
```ruby
|
768
|
+
page.html # => '<label for="greeting">Greeting</label>
|
769
|
+
<input id="greeting" name="content">'
|
770
|
+
|
771
|
+
# find by the <input> element's [id] attribute
|
772
|
+
page.find(:id, 'greeting') == page.find_by_id('greeting') # => true
|
773
|
+
|
774
|
+
# find by the <input> element's [id] attribute
|
775
|
+
page.find(:field, 'greeting') == page.find_field('greeting') # => true
|
776
|
+
|
777
|
+
# find by the <input> element's [name] attribute
|
778
|
+
page.find(:field, 'content') == page.find_field('content') # => true
|
779
|
+
|
780
|
+
# find by the <label> element's text
|
781
|
+
page.find(:field, 'Greeting') == page.find_field('Greeting') # => true
|
782
|
+
|
783
|
+
page.html # => '<table>
|
784
|
+
<tr>
|
785
|
+
<th>A</th>
|
786
|
+
<th>B</th>
|
787
|
+
</tr>
|
788
|
+
<tr>
|
789
|
+
<td>1</td>
|
790
|
+
<td>2</td>
|
791
|
+
</tr>
|
792
|
+
</table>'
|
793
|
+
|
794
|
+
# find by <td> content
|
795
|
+
page.find(:table_row, ['1', '2']) == page.find(:css, 'tr:last-of-type') # => true
|
796
|
+
|
797
|
+
# find by <th> content paired with corresponding <td> content
|
798
|
+
page.find(:table_row, 'A' => '1') == page.find(:table_row, 'B' => '2') # => true
|
799
|
+
```
|
800
|
+
|
801
|
+
### <a name="selectors-filters"></a> Filters
|
802
|
+
|
803
|
+
All filters are optional. The supported set of keys is a mixture of both global
|
804
|
+
and context-specific filters.The supported types of values depend on the
|
805
|
+
context:
|
806
|
+
|
807
|
+
```ruby
|
808
|
+
page.html # => '<a href="/">Home</a>'
|
809
|
+
|
810
|
+
# find by the [href] attribute
|
811
|
+
page.find_link(href: '/') == page.find_link(text: 'Home') # => true
|
812
|
+
|
813
|
+
page.html # => '<div id="element" data-attribute="value">Content</div>'
|
814
|
+
|
815
|
+
# find by the [id] attribute
|
816
|
+
page.find(id: 'element') == page.find(text: 'Content') # => true
|
817
|
+
|
818
|
+
# find by the [data-attribute] attribute
|
819
|
+
page.find(:element, 'data-attribute': /value/) == page.find(text: 'Content') # => true
|
820
|
+
|
821
|
+
page.html # => '<input type="checkbox">'
|
822
|
+
|
823
|
+
# find by the absence of the [checked] attribute
|
824
|
+
page.find_field(checked: false) == page.find_field(unchecked: true) # => true
|
825
|
+
```
|
826
|
+
|
827
|
+
The predicate block is always optional. When there are results for a selector
|
828
|
+
query, the block is called with each item in the result set. When the block
|
829
|
+
evaluates to true, the item is included from the result set. Otherwise, the item
|
830
|
+
is excluded:
|
831
|
+
|
832
|
+
```ruby
|
833
|
+
page.html # => '<input role="switch" type="checkbox" checked>'
|
834
|
+
|
835
|
+
switch = page.find_field { |input| input["role"] == "switch" }
|
836
|
+
field = page.find_field(checked: true)
|
837
|
+
|
838
|
+
switch == field # => true
|
839
|
+
```
|
840
|
+
|
841
|
+
[`find`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders:find
|
842
|
+
[`all`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders:all
|
843
|
+
[`Capybara.default_selector`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2Econfigure
|
844
|
+
[`find_by_id`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders:find_by_id
|
845
|
+
[`find_field`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders:find_field
|
846
|
+
[`find_link`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders:find_link
|
847
|
+
|
704
848
|
## <a name="matching"></a>Matching
|
705
849
|
|
706
850
|
It is possible to customize how Capybara finds elements. At your disposal
|
data/lib/capybara/helpers.rb
CHANGED
@@ -95,6 +95,18 @@ module Capybara
|
|
95
95
|
# @!method wont_have_field
|
96
96
|
# See {Capybara::Node::Matchers#has_no_field?}
|
97
97
|
|
98
|
+
##
|
99
|
+
# Expectation that there is element
|
100
|
+
#
|
101
|
+
# @!method must_have_element
|
102
|
+
# See {Capybara::Node::Matchers#has_element?}
|
103
|
+
|
104
|
+
##
|
105
|
+
# Expectation that there is no element
|
106
|
+
#
|
107
|
+
# @!method wont_have_element
|
108
|
+
# See {Capybara::Node::Matchers#has_no_element?}
|
109
|
+
|
98
110
|
##
|
99
111
|
# Expectation that there is link
|
100
112
|
#
|
@@ -230,15 +242,15 @@ module Capybara
|
|
230
242
|
%W[refute_matches_#{assertion} wont_match_#{assertion}]]
|
231
243
|
end).each do |(meth, new_name)|
|
232
244
|
class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
|
233
|
-
def #{new_name}
|
234
|
-
::Minitest::Expectation.new(self, ::Minitest::Spec.current).#{new_name}(
|
245
|
+
def #{new_name}(...)
|
246
|
+
::Minitest::Expectation.new(self, ::Minitest::Spec.current).#{new_name}(...)
|
235
247
|
end
|
236
248
|
ASSERTION
|
237
249
|
|
238
250
|
::Minitest::Expectation.class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
|
239
|
-
def #{new_name}
|
251
|
+
def #{new_name}(...)
|
240
252
|
raise "Calling ##{new_name} outside of test." unless ctx
|
241
|
-
ctx.#{meth}(target,
|
253
|
+
ctx.#{meth}(target, ...)
|
242
254
|
end
|
243
255
|
ASSERTION
|
244
256
|
end
|
data/lib/capybara/minitest.rb
CHANGED
@@ -190,6 +190,19 @@ module Capybara
|
|
190
190
|
# @!method assert_no_css
|
191
191
|
# See {Capybara::Node::Matchers#has_no_css?}
|
192
192
|
|
193
|
+
##
|
194
|
+
# Assert that provided element exists
|
195
|
+
#
|
196
|
+
# @!method assert_element
|
197
|
+
# See {Capybara::Node::Matchers#has_element?}
|
198
|
+
|
199
|
+
##
|
200
|
+
# Assert that provided element does not exist
|
201
|
+
#
|
202
|
+
# @!method assert_no_element
|
203
|
+
# @!method refute_element
|
204
|
+
# See {Capybara::Node::Matchers#has_no_element?}
|
205
|
+
|
193
206
|
##
|
194
207
|
# Assert that provided link exists
|
195
208
|
#
|
@@ -281,7 +294,7 @@ module Capybara
|
|
281
294
|
# @!method assert_no_table
|
282
295
|
# See {Capybara::Node::Matchers#has_no_table?}
|
283
296
|
|
284
|
-
%w[xpath css link button field select table].each do |selector_type|
|
297
|
+
%w[xpath css element link button field select table].each do |selector_type|
|
285
298
|
define_method "assert_#{selector_type}" do |*args, &optional_filter_block|
|
286
299
|
subject, args = determine_subject(args)
|
287
300
|
locator, options = extract_locator(args)
|
@@ -322,6 +322,31 @@ module Capybara
|
|
322
322
|
has_no_selector?(:css, path, **options, &optional_filter_block)
|
323
323
|
end
|
324
324
|
|
325
|
+
##
|
326
|
+
#
|
327
|
+
# Checks if the page or current node has a element with the given
|
328
|
+
# local name.
|
329
|
+
#
|
330
|
+
# @param [String] locator The local name of a element to check for
|
331
|
+
# @option options [String, Regexp] The attributes values of matching elements
|
332
|
+
# @return [Boolean] Whether it exists
|
333
|
+
#
|
334
|
+
def has_element?(locator = nil, **options, &optional_filter_block)
|
335
|
+
has_selector?(:element, locator, **options, &optional_filter_block)
|
336
|
+
end
|
337
|
+
|
338
|
+
##
|
339
|
+
#
|
340
|
+
# Checks if the page or current node has no element with the given
|
341
|
+
# local name.
|
342
|
+
#
|
343
|
+
# @param (see #has_element?)
|
344
|
+
# @return [Boolean] Whether it doesn't exist
|
345
|
+
#
|
346
|
+
def has_no_element?(locator = nil, **options, &optional_filter_block)
|
347
|
+
has_no_selector?(:element, locator, **options, &optional_filter_block)
|
348
|
+
end
|
349
|
+
|
325
350
|
##
|
326
351
|
#
|
327
352
|
# Checks if the page or current node has a link with the given
|
@@ -16,16 +16,16 @@ module Capybara
|
|
16
16
|
PARAGRAPH_SEPERATOR = "\u2029"
|
17
17
|
|
18
18
|
# All spaces except for NBSP
|
19
|
-
BREAKING_SPACES = "[[:space:]&&[^#{NON_BREAKING_SPACE}]]"
|
19
|
+
BREAKING_SPACES = "[[:space:]&&[^#{NON_BREAKING_SPACE}]]".freeze
|
20
20
|
|
21
21
|
# Whitespace we want to substitute with plain spaces
|
22
|
-
SQUEEZED_SPACES = " \n\f\t\v#{LINE_SEPERATOR}#{PARAGRAPH_SEPERATOR}"
|
22
|
+
SQUEEZED_SPACES = " \n\f\t\v#{LINE_SEPERATOR}#{PARAGRAPH_SEPERATOR}".freeze
|
23
23
|
|
24
24
|
# Any whitespace at the front of text
|
25
|
-
LEADING_SPACES = /\A#{BREAKING_SPACES}
|
25
|
+
LEADING_SPACES = /\A#{BREAKING_SPACES}+/
|
26
26
|
|
27
27
|
# Any whitespace at the end of text
|
28
|
-
TRAILING_SPACES = /#{BREAKING_SPACES}+\z
|
28
|
+
TRAILING_SPACES = /#{BREAKING_SPACES}+\z/
|
29
29
|
|
30
30
|
# "Invisible" space character
|
31
31
|
ZERO_WIDTH_SPACE = "\u200b"
|
@@ -40,7 +40,7 @@ module Capybara
|
|
40
40
|
REMOVED_CHARACTERS = [ZERO_WIDTH_SPACE, LEFT_TO_RIGHT_MARK, RIGHT_TO_LEFT_MARK].join
|
41
41
|
|
42
42
|
# Matches multiple empty lines
|
43
|
-
EMPTY_LINES = /[\ \n]*\n[\ \n]
|
43
|
+
EMPTY_LINES = /[\ \n]*\n[\ \n]*/
|
44
44
|
|
45
45
|
##
|
46
46
|
#
|
@@ -70,7 +70,8 @@ module Capybara
|
|
70
70
|
desc << 'non-visible ' if visible == :hidden
|
71
71
|
end
|
72
72
|
|
73
|
-
desc <<
|
73
|
+
desc << label.to_s
|
74
|
+
desc << " #{locator.inspect}" unless locator.nil?
|
74
75
|
|
75
76
|
if show_for[:any]
|
76
77
|
desc << " with#{' exact' if exact_text == true} text #{options[:text].inspect}" if options[:text]
|
@@ -35,12 +35,13 @@ class Capybara::RackTest::Browser
|
|
35
35
|
path = request_path if path.nil? || path.empty?
|
36
36
|
uri = build_uri(path)
|
37
37
|
uri.query = '' if method.to_s.casecmp('get').zero?
|
38
|
+
env = { 'HTTP_REFERER' => referer_url }
|
39
|
+
env['CONTENT_TYPE'] = content_type if content_type
|
38
40
|
process_and_follow_redirects(
|
39
41
|
method,
|
40
42
|
uri.to_s,
|
41
43
|
attributes,
|
42
|
-
|
43
|
-
'CONTENT_TYPE' => content_type
|
44
|
+
env
|
44
45
|
)
|
45
46
|
end
|
46
47
|
|
@@ -125,19 +125,12 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
125
125
|
alias_method "unchecked_#{meth_name}", meth_name
|
126
126
|
private "unchecked_#{meth_name}" # rubocop:disable Style/AccessModifierDeclarations
|
127
127
|
|
128
|
-
|
129
|
-
|
130
|
-
def #{meth_name}(...)
|
131
|
-
stale_check
|
132
|
-
method(:"unchecked_#{meth_name}").call(...)
|
133
|
-
end
|
134
|
-
METHOD
|
135
|
-
else
|
136
|
-
define_method meth_name do |*args|
|
128
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
129
|
+
def #{meth_name}(...)
|
137
130
|
stale_check
|
138
|
-
|
131
|
+
method(:"unchecked_#{meth_name}").call(...)
|
139
132
|
end
|
140
|
-
|
133
|
+
METHOD
|
141
134
|
end
|
142
135
|
|
143
136
|
protected
|
@@ -232,7 +225,7 @@ private
|
|
232
225
|
native.remove
|
233
226
|
else
|
234
227
|
value.to_s.tap do |set_value|
|
235
|
-
if set_value.end_with?("\n") && form&.css('input, textarea')&.count
|
228
|
+
if set_value.end_with?("\n") && form&.css('input, textarea')&.count == 1
|
236
229
|
native['value'] = set_value.to_s.chop
|
237
230
|
Capybara::RackTest::Form.new(driver, form).submit(self)
|
238
231
|
else
|
@@ -16,10 +16,10 @@ module Capybara
|
|
16
16
|
@registered[name] = value
|
17
17
|
end
|
18
18
|
|
19
|
-
def method_missing(method_name,
|
19
|
+
def method_missing(method_name, ...)
|
20
20
|
if @registered.respond_to?(method_name)
|
21
21
|
Capybara::Helpers.warn "DEPRECATED: Calling '#{method_name}' on the drivers/servers container is deprecated without replacement"
|
22
|
-
return @registered.public_send(method_name,
|
22
|
+
return @registered.public_send(method_name, ...)
|
23
23
|
end
|
24
24
|
super
|
25
25
|
end
|
@@ -32,7 +32,7 @@ Capybara.register_driver :selenium_chrome_headless do |app|
|
|
32
32
|
version = Capybara::Selenium::Driver.load_selenium
|
33
33
|
options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
|
34
34
|
browser_options = Selenium::WebDriver::Chrome::Options.new.tap do |opts|
|
35
|
-
opts.add_argument('--headless')
|
35
|
+
opts.add_argument('--headless=new')
|
36
36
|
opts.add_argument('--disable-gpu') if Gem.win_platform?
|
37
37
|
# Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
|
38
38
|
opts.add_argument('--disable-site-isolation-trials')
|
@@ -27,19 +27,20 @@ Capybara.register_server :puma do |app, port, host, **options| # rubocop:disable
|
|
27
27
|
require 'rack/handler/puma'
|
28
28
|
rescue LoadError
|
29
29
|
raise LoadError, 'Capybara is unable to load `puma` for its server, please add `puma` to your project or specify a different server via something like `Capybara.server = :webrick`.'
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
end
|
31
|
+
puma_rack_handler = defined?(Rackup::Handler::Puma) ? Rackup::Handler::Puma : Rack::Handler::Puma
|
32
|
+
|
33
|
+
unless puma_rack_handler.respond_to?(:config)
|
34
|
+
raise LoadError, 'Capybara requires `puma` version 3.8.0 or higher, please upgrade `puma` or register and specify your own server block'
|
34
35
|
end
|
35
36
|
|
36
37
|
# If we just run the Puma Rack handler it installs signal handlers which prevent us from being able to interrupt tests.
|
37
38
|
# Therefore construct and run the Server instance ourselves.
|
38
|
-
#
|
39
|
+
# puma_rack_handler.run(app, { Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false }.merge(options))
|
39
40
|
default_options = { Host: host, Port: port, Threads: '0:4', workers: 0, daemon: false }
|
40
41
|
options = default_options.merge(options)
|
41
42
|
|
42
|
-
conf =
|
43
|
+
conf = puma_rack_handler.config(app, options)
|
43
44
|
conf.clamp
|
44
45
|
|
45
46
|
puma_ver = Gem::Version.new(Puma::Const::PUMA_VERSION)
|
@@ -51,7 +52,7 @@ Capybara.register_server :puma do |app, port, host, **options| # rubocop:disable
|
|
51
52
|
conf.options[:log_writer] = logger
|
52
53
|
|
53
54
|
logger.log 'Capybara starting Puma...'
|
54
|
-
logger.log "* Version #{Puma::Const::PUMA_VERSION}
|
55
|
+
logger.log "* Version #{Puma::Const::PUMA_VERSION}, codename: #{Puma::Const::CODE_NAME}"
|
55
56
|
logger.log "* Min threads: #{conf.options[:min_threads]}, max threads: #{conf.options[:max_threads]}"
|
56
57
|
|
57
58
|
Puma::Server.new(
|
data/lib/capybara/result.rb
CHANGED
@@ -34,7 +34,7 @@ module Capybara
|
|
34
34
|
@allow_reload = false
|
35
35
|
end
|
36
36
|
|
37
|
-
def_delegators :full_results, :size, :length, :last, :values_at, :inspect, :sample
|
37
|
+
def_delegators :full_results, :size, :length, :last, :values_at, :inspect, :sample, :to_ary
|
38
38
|
|
39
39
|
alias index find_index
|
40
40
|
|
@@ -116,7 +116,7 @@ module Capybara
|
|
116
116
|
message << ' but there were no matches'
|
117
117
|
else
|
118
118
|
message << ", found #{count} #{Capybara::Helpers.declension('match', 'matches', count)}: " \
|
119
|
-
<< full_results.map
|
119
|
+
<< full_results.map { |r| r.text.inspect }.join(', ')
|
120
120
|
end
|
121
121
|
unless rest.empty?
|
122
122
|
elements = rest.map { |el| el.text rescue '<<ERROR>>' }.map(&:inspect).join(', ') # rubocop:disable Style/RescueModifier
|
@@ -22,9 +22,7 @@ module Capybara
|
|
22
22
|
el.assert_no_selector(*@args, **session_query_options, &@filter_block)
|
23
23
|
end
|
24
24
|
|
25
|
-
def description
|
26
|
-
"have #{query.description}"
|
27
|
-
end
|
25
|
+
def description = "have #{query.description}"
|
28
26
|
|
29
27
|
def query
|
30
28
|
@query ||= Capybara::Queries::SelectorQuery.new(*session_query_args, **session_query_options, &@filter_block)
|
@@ -40,9 +38,7 @@ module Capybara
|
|
40
38
|
raise ArgumentError, 'The have_all_selectors matcher does not support use with not_to/should_not'
|
41
39
|
end
|
42
40
|
|
43
|
-
def description
|
44
|
-
'have all selectors'
|
45
|
-
end
|
41
|
+
def description = 'have all selectors'
|
46
42
|
end
|
47
43
|
|
48
44
|
class HaveNoSelectors < WrappedElementMatcher
|
@@ -54,9 +50,7 @@ module Capybara
|
|
54
50
|
raise ArgumentError, 'The have_none_of_selectors matcher does not support use with not_to/should_not'
|
55
51
|
end
|
56
52
|
|
57
|
-
def description
|
58
|
-
'have no selectors'
|
59
|
-
end
|
53
|
+
def description = 'have no selectors'
|
60
54
|
end
|
61
55
|
|
62
56
|
class HaveAnySelectors < WrappedElementMatcher
|
@@ -68,9 +62,7 @@ module Capybara
|
|
68
62
|
el.assert_none_of_selectors(*@args, **session_query_options, &@filter_block)
|
69
63
|
end
|
70
64
|
|
71
|
-
def description
|
72
|
-
'have any selectors'
|
73
|
-
end
|
65
|
+
def description = 'have any selectors'
|
74
66
|
end
|
75
67
|
end
|
76
68
|
end
|