rubocop-capybara 2.19.0 → 2.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/config/default.yml +12 -4
- data/lib/rubocop/capybara/cop/generator.rb +25 -0
- data/lib/rubocop/capybara/version.rb +1 -1
- data/lib/rubocop/cop/capybara/click_link_or_button_style.rb +18 -11
- data/lib/rubocop/cop/capybara/current_path_expectation.rb +3 -3
- data/lib/rubocop/cop/capybara/mixin/css_attributes_parser.rb +72 -0
- data/lib/rubocop/cop/capybara/mixin/css_selector.rb +2 -24
- data/lib/rubocop/cop/capybara/negation_matcher.rb +15 -14
- data/lib/rubocop/cop/capybara/redundant_within_find.rb +66 -0
- data/lib/rubocop/cop/capybara/rspec/have_selector.rb +1 -1
- data/lib/rubocop/cop/capybara/specific_actions.rb +1 -1
- data/lib/rubocop/cop/capybara/specific_finders.rb +10 -4
- data/lib/rubocop/cop/capybara/specific_matcher.rb +8 -2
- data/lib/rubocop/cop/capybara_cops.rb +1 -0
- data/lib/rubocop-capybara.rb +1 -0
- metadata +13 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed8a103d3d11a90d7873a5569246e580d816e2ebad0a614827bd2ed3546bf6bf
|
4
|
+
data.tar.gz: d09792f9ea669f7556814b898fbfd9829e8db25fdd3b8873ac85487ee9f199ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0798dc5b62b3dc8a8ea31bd1f79cedde039d0d69e94cf18a902ced3da7ae757b0529fa17b8d5711baae964fb591eccfcce4f7b16320598cd9dafb657c4aee85c'
|
7
|
+
data.tar.gz: 7de56f77982c7b52973c38698317233da3ebeb2a55dff962c380105419d2708e43e16d5f1f63a87338ec935d6c5c24941efd95a2d308b2236d7dd840bf8c63ab
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,20 @@
|
|
2
2
|
|
3
3
|
## Edge (Unreleased)
|
4
4
|
|
5
|
+
## 2.21.0 (2024-06-08)
|
6
|
+
|
7
|
+
- Fix a false negative for `Capybara/NegationMatcher` when using `to_not`. ([@ydah])
|
8
|
+
- Fix a false negative for `Capybara/SpecificFinders` when using `find(:id, 'some-id')`. ([@ydah])
|
9
|
+
|
10
|
+
## 2.20.0 (2024-01-03)
|
11
|
+
|
12
|
+
- Change to default `EnforcedStyle: link_or_button` for `Capybara/ClickLinkOrButtonStyle` cop. ([@ydah])
|
13
|
+
- Fix a false negative for `RSpec/HaveSelector` when first argument is dstr node. ([@ydah])
|
14
|
+
- Add new `Capybara/RedundantWithinFind` cop. ([@ydah])
|
15
|
+
- Fix an invalid attributes parse when name with multiple `[]` for `Capybara/SpecificFinders` and `Capybara/SpecificActions` and `Capybara/SpecificMatcher`. ([@ydah])
|
16
|
+
- Change to default `EnforcedStyle: have_no` for `Capybara/NegationMatcher` cop. ([@ydah])
|
17
|
+
- Fix a false positive for `Capybara/SpecificMatcher` when `text:` or `exact_text:` with regexp. ([@ydah])
|
18
|
+
|
5
19
|
## 2.19.0 (2023-09-20)
|
6
20
|
|
7
21
|
- Add new `Capybara/RSpec/PredicateMatcher` cop. ([@ydah])
|
data/config/default.yml
CHANGED
@@ -10,13 +10,14 @@ Capybara:
|
|
10
10
|
- "**/features/step_definitions/**/*"
|
11
11
|
|
12
12
|
Capybara/ClickLinkOrButtonStyle:
|
13
|
-
Description: Checks for
|
13
|
+
Description: Checks for methods of button or link clicks.
|
14
14
|
Enabled: pending
|
15
15
|
VersionAdded: '2.19'
|
16
|
-
|
16
|
+
VersionChanged: '2.20'
|
17
|
+
EnforcedStyle: link_or_button
|
17
18
|
SupportedStyles:
|
18
|
-
- strict
|
19
19
|
- link_or_button
|
20
|
+
- strict
|
20
21
|
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/ClickLinkOrButtonStyle
|
21
22
|
|
22
23
|
Capybara/CurrentPathExpectation:
|
@@ -36,12 +37,19 @@ Capybara/NegationMatcher:
|
|
36
37
|
Description: Enforces use of `have_no_*` or `not_to` for negated expectations.
|
37
38
|
Enabled: pending
|
38
39
|
VersionAdded: '2.14'
|
39
|
-
|
40
|
+
VersionChanged: '2.20'
|
41
|
+
EnforcedStyle: have_no
|
40
42
|
SupportedStyles:
|
41
43
|
- have_no
|
42
44
|
- not_to
|
43
45
|
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/NegationMatcher
|
44
46
|
|
47
|
+
Capybara/RedundantWithinFind:
|
48
|
+
Description: Checks for redundant `within find(...)` calls.
|
49
|
+
Enabled: pending
|
50
|
+
VersionAdded: '2.20'
|
51
|
+
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/RedundantWithinFind
|
52
|
+
|
45
53
|
Capybara/SpecificActions:
|
46
54
|
Description: Checks for there is a more specific actions offered by Capybara.
|
47
55
|
Enabled: pending
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Capybara
|
5
|
+
module Cop
|
6
|
+
# Source and spec generator for new cops
|
7
|
+
#
|
8
|
+
# This generator will take a cop name and generate a source file
|
9
|
+
# and spec file when given a valid qualified cop name.
|
10
|
+
# @api private
|
11
|
+
class Generator < RuboCop::Cop::Generator
|
12
|
+
def todo
|
13
|
+
<<~TODO
|
14
|
+
Do 4 steps:
|
15
|
+
1. Modify the description of #{badge} in config/default.yml
|
16
|
+
2. Implement your new cop in the generated file!
|
17
|
+
3. Add an entry about new cop to CHANGELOG.md
|
18
|
+
4. Commit your new cop with a message such as
|
19
|
+
e.g. "Add new `#{badge}` cop"
|
20
|
+
TODO
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -3,18 +3,16 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Capybara
|
6
|
-
# Checks for
|
6
|
+
# Checks for methods of button or link clicks.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# click_on('foo')
|
8
|
+
# By default, prefer to use `click_link_or_button` or `click_on`.
|
9
|
+
# These methods offer a weaker coupling between the test and HTML,
|
10
|
+
# allowing for a more faithful reflection of how the user behaves.
|
12
11
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# click_button('foo')
|
12
|
+
# You can set `EnforcedStyle: strict` to prefer the use of
|
13
|
+
# `click_link` and `click_button`, but this is a deprecated setting.
|
16
14
|
#
|
17
|
-
# @example EnforcedStyle: link_or_button
|
15
|
+
# @example EnforcedStyle: link_or_button (default)
|
18
16
|
# # bad
|
19
17
|
# click_link('foo')
|
20
18
|
# click_button('foo')
|
@@ -23,6 +21,15 @@ module RuboCop
|
|
23
21
|
# click_link_or_button('foo')
|
24
22
|
# click_on('foo')
|
25
23
|
#
|
24
|
+
# @example EnforcedStyle: strict
|
25
|
+
# # bad
|
26
|
+
# click_link_or_button('foo')
|
27
|
+
# click_on('foo')
|
28
|
+
#
|
29
|
+
# # good
|
30
|
+
# click_link('foo')
|
31
|
+
# click_button('foo')
|
32
|
+
#
|
26
33
|
class ClickLinkOrButtonStyle < ::RuboCop::Cop::Base
|
27
34
|
include ConfigurableEnforcedStyle
|
28
35
|
|
@@ -43,8 +50,8 @@ module RuboCop
|
|
43
50
|
private
|
44
51
|
|
45
52
|
def offense?(node)
|
46
|
-
style == :strict && !strict_method?(node) ||
|
47
|
-
style == :link_or_button && !link_or_button_method?(node)
|
53
|
+
(style == :strict && !strict_method?(node)) ||
|
54
|
+
(style == :link_or_button && !link_or_button_method?(node))
|
48
55
|
end
|
49
56
|
|
50
57
|
def offense_message(node)
|
@@ -37,20 +37,20 @@ module RuboCop
|
|
37
37
|
RESTRICT_ON_SEND = %i[expect].freeze
|
38
38
|
|
39
39
|
# @!method expectation_set_on_current_path(node)
|
40
|
-
def_node_matcher :expectation_set_on_current_path,
|
40
|
+
def_node_matcher :expectation_set_on_current_path, <<~PATTERN
|
41
41
|
(send nil? :expect (send {(send nil? :page) nil?} :current_path))
|
42
42
|
PATTERN
|
43
43
|
|
44
44
|
# Supported matchers: eq(...) / match(/regexp/) / match('regexp')
|
45
45
|
# @!method as_is_matcher(node)
|
46
|
-
def_node_matcher :as_is_matcher,
|
46
|
+
def_node_matcher :as_is_matcher, <<~PATTERN
|
47
47
|
(send
|
48
48
|
#expectation_set_on_current_path ${:to :to_not :not_to}
|
49
49
|
${(send nil? :eq ...) (send nil? :match (regexp ...))})
|
50
50
|
PATTERN
|
51
51
|
|
52
52
|
# @!method regexp_node_matcher(node)
|
53
|
-
def_node_matcher :regexp_node_matcher,
|
53
|
+
def_node_matcher :regexp_node_matcher, <<~PATTERN
|
54
54
|
(send
|
55
55
|
#expectation_set_on_current_path ${:to :to_not :not_to}
|
56
56
|
$(send nil? :match ${str dstr xstr}))
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Capybara
|
6
|
+
# Css selector parser.
|
7
|
+
# @api private
|
8
|
+
class CssAttributesParser
|
9
|
+
def initialize(selector)
|
10
|
+
@selector = selector
|
11
|
+
@state = :initial
|
12
|
+
@temp = ''
|
13
|
+
@results = {}
|
14
|
+
@bracket_count = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Array<String>]
|
18
|
+
def parse # rubocop:disable Metrics/MethodLength
|
19
|
+
@selector.each_char do |char|
|
20
|
+
if char == '['
|
21
|
+
on_bracket_start
|
22
|
+
elsif char == ']'
|
23
|
+
on_bracket_end
|
24
|
+
elsif @state == :inside_attr
|
25
|
+
@temp += char
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@results
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def on_bracket_start
|
34
|
+
@bracket_count += 1
|
35
|
+
if @state == :initial
|
36
|
+
@state = :inside_attr
|
37
|
+
else
|
38
|
+
@temp += '['
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_bracket_end
|
43
|
+
@bracket_count -= 1
|
44
|
+
if @bracket_count.zero?
|
45
|
+
@state = :initial
|
46
|
+
key, value = @temp.split('=')
|
47
|
+
@results[key] = normalize_value(value)
|
48
|
+
@temp.clear
|
49
|
+
else
|
50
|
+
@temp += ']'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# @param value [String]
|
55
|
+
# @return [Boolean, String]
|
56
|
+
# @example
|
57
|
+
# normalize_value('true') # => true
|
58
|
+
# normalize_value('false') # => false
|
59
|
+
# normalize_value(nil) # => nil
|
60
|
+
# normalize_value("foo") # => "'foo'"
|
61
|
+
def normalize_value(value)
|
62
|
+
case value
|
63
|
+
when 'true' then true
|
64
|
+
when 'false' then false
|
65
|
+
when nil then nil
|
66
|
+
else "'#{value.gsub(/"|'/, '')}'"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -55,15 +55,9 @@ module RuboCop
|
|
55
55
|
# attributes('a[foo-bar_baz]') # => {"foo-bar_baz=>nil}
|
56
56
|
# attributes('button[foo][bar=baz]') # => {"foo"=>nil, "bar"=>"'baz'"}
|
57
57
|
# attributes('table[foo=bar]') # => {"foo"=>"'bar'"}
|
58
|
+
# attributes('[foo="bar[baz][qux]"]') # => {"foo"=>"'bar[baz][qux]'"}
|
58
59
|
def attributes(selector)
|
59
|
-
|
60
|
-
# For example, extract the following:
|
61
|
-
# 'button[foo][bar=baz]' => 'foo][bar=baz'
|
62
|
-
inside_attributes = selector.scan(/\[(.*)\]/).flatten.join
|
63
|
-
inside_attributes.split('][').to_h do |attr|
|
64
|
-
key, value = attr.split('=')
|
65
|
-
[key, normalize_value(value)]
|
66
|
-
end
|
60
|
+
CssAttributesParser.new(selector).parse
|
67
61
|
end
|
68
62
|
|
69
63
|
# @param selector [String]
|
@@ -89,22 +83,6 @@ module RuboCop
|
|
89
83
|
normalize = selector.gsub(/(\\[>,+~]|\(.*\))/, '')
|
90
84
|
normalize.match?(/[ >,+~]/)
|
91
85
|
end
|
92
|
-
|
93
|
-
# @param value [String]
|
94
|
-
# @return [Boolean, String]
|
95
|
-
# @example
|
96
|
-
# normalize_value('true') # => true
|
97
|
-
# normalize_value('false') # => false
|
98
|
-
# normalize_value(nil) # => nil
|
99
|
-
# normalize_value("foo") # => "'foo'"
|
100
|
-
def normalize_value(value)
|
101
|
-
case value
|
102
|
-
when 'true' then true
|
103
|
-
when 'false' then false
|
104
|
-
when nil then nil
|
105
|
-
else "'#{value.gsub(/"|'/, '')}'"
|
106
|
-
end
|
107
|
-
end
|
108
86
|
end
|
109
87
|
end
|
110
88
|
end
|
@@ -5,23 +5,23 @@ module RuboCop
|
|
5
5
|
module Capybara
|
6
6
|
# Enforces use of `have_no_*` or `not_to` for negated expectations.
|
7
7
|
#
|
8
|
-
# @example EnforcedStyle:
|
8
|
+
# @example EnforcedStyle: have_no (default)
|
9
9
|
# # bad
|
10
|
-
# expect(page).
|
11
|
-
# expect(page).
|
10
|
+
# expect(page).not_to have_selector 'a'
|
11
|
+
# expect(page).not_to have_css('a')
|
12
12
|
#
|
13
13
|
# # good
|
14
|
-
# expect(page).
|
15
|
-
# expect(page).
|
14
|
+
# expect(page).to have_no_selector 'a'
|
15
|
+
# expect(page).to have_no_css('a')
|
16
16
|
#
|
17
|
-
# @example EnforcedStyle:
|
17
|
+
# @example EnforcedStyle: not_to
|
18
18
|
# # bad
|
19
|
-
# expect(page).
|
20
|
-
# expect(page).
|
19
|
+
# expect(page).to have_no_selector 'a'
|
20
|
+
# expect(page).to have_no_css('a')
|
21
21
|
#
|
22
22
|
# # good
|
23
|
-
# expect(page).
|
24
|
-
# expect(page).
|
23
|
+
# expect(page).not_to have_selector 'a'
|
24
|
+
# expect(page).not_to have_css('a')
|
25
25
|
#
|
26
26
|
class NegationMatcher < ::RuboCop::Cop::Base
|
27
27
|
extend AutoCorrector
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
|
43
43
|
# @!method not_to?(node)
|
44
44
|
def_node_matcher :not_to?, <<~PATTERN
|
45
|
-
(send ... :not_to
|
45
|
+
(send ... {:not_to :to_not}
|
46
46
|
(send nil? %POSITIVE_MATCHERS ...))
|
47
47
|
PATTERN
|
48
48
|
|
@@ -53,7 +53,7 @@ module RuboCop
|
|
53
53
|
PATTERN
|
54
54
|
|
55
55
|
def on_send(node)
|
56
|
-
return unless offense?(node
|
56
|
+
return unless offense?(node)
|
57
57
|
|
58
58
|
matcher = node.method_name.to_s
|
59
59
|
add_offense(offense_range(node),
|
@@ -67,8 +67,9 @@ module RuboCop
|
|
67
67
|
private
|
68
68
|
|
69
69
|
def offense?(node)
|
70
|
-
|
71
|
-
(style == :
|
70
|
+
node.arguments? &&
|
71
|
+
((style == :have_no && not_to?(node.parent)) ||
|
72
|
+
(style == :not_to && have_no?(node.parent)))
|
72
73
|
end
|
73
74
|
|
74
75
|
def offense_range(node)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Capybara
|
6
|
+
# Checks for redundant `within find(...)` calls.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# within find('foo.bar') do
|
11
|
+
# # ...
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# within 'foo.bar' do
|
16
|
+
# # ...
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# within find_by_id('foo') do
|
21
|
+
# # ...
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# within '#foo' do
|
26
|
+
# # ...
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
class RedundantWithinFind < ::RuboCop::Cop::Base
|
30
|
+
extend AutoCorrector
|
31
|
+
MSG = 'Redundant `within %<method>s(...)` call detected.'
|
32
|
+
RESTRICT_ON_SEND = %i[within].freeze
|
33
|
+
FIND_METHODS = Set.new(%i[find find_by_id]).freeze
|
34
|
+
|
35
|
+
# @!method within_find(node)
|
36
|
+
def_node_matcher :within_find, <<~PATTERN
|
37
|
+
(send nil? :within
|
38
|
+
$(send nil? %FIND_METHODS ...))
|
39
|
+
PATTERN
|
40
|
+
|
41
|
+
def on_send(node)
|
42
|
+
within_find(node) do |find_node|
|
43
|
+
add_offense(find_node, message: msg(find_node)) do |corrector|
|
44
|
+
corrector.replace(find_node, replaced(find_node))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def msg(node)
|
52
|
+
format(MSG, method: node.method_name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def replaced(node)
|
56
|
+
replaced = node.arguments.map(&:source).join(', ')
|
57
|
+
if node.method?(:find_by_id)
|
58
|
+
replaced.sub(/\A(["'])/, '\1#')
|
59
|
+
else
|
60
|
+
replaced
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
def on_send(node)
|
45
45
|
argument = node.first_argument
|
46
46
|
on_select_with_type(node, argument) if argument.sym_type?
|
47
|
-
on_select_without_type(node) if argument.
|
47
|
+
on_select_without_type(node) if %i[str dstr].include?(argument.type)
|
48
48
|
end
|
49
49
|
|
50
50
|
private
|
@@ -10,6 +10,7 @@ module RuboCop
|
|
10
10
|
# find('#some-id')
|
11
11
|
# find('[id=some-id]')
|
12
12
|
# find(:css, '#some-id')
|
13
|
+
# find(:id, 'some-id')
|
13
14
|
#
|
14
15
|
# # good
|
15
16
|
# find_by_id('some-id')
|
@@ -23,7 +24,7 @@ module RuboCop
|
|
23
24
|
|
24
25
|
# @!method find_argument(node)
|
25
26
|
def_node_matcher :find_argument, <<~PATTERN
|
26
|
-
(send _ :find $(sym :css)? (str $_) ...)
|
27
|
+
(send _ :find $(sym {:css :id})? (str $_) ...)
|
27
28
|
PATTERN
|
28
29
|
|
29
30
|
# @!method class_options(node)
|
@@ -38,6 +39,7 @@ module RuboCop
|
|
38
39
|
|
39
40
|
on_attr(node, sym, arg) if attribute?(arg)
|
40
41
|
on_id(node, sym, arg) if CssSelector.id?(arg)
|
42
|
+
on_sym_id(node, sym, arg) if sym.first&.value == :id
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
@@ -59,6 +61,10 @@ module RuboCop
|
|
59
61
|
CssSelector.classes(arg.sub("##{id}", '')))
|
60
62
|
end
|
61
63
|
|
64
|
+
def on_sym_id(node, sym, id)
|
65
|
+
register_offense(node, sym, "'#{id}'")
|
66
|
+
end
|
67
|
+
|
62
68
|
def attribute?(arg)
|
63
69
|
CssSelector.attribute?(arg) &&
|
64
70
|
CapybaraHelp.common_attributes?(arg)
|
@@ -76,7 +82,7 @@ module RuboCop
|
|
76
82
|
end
|
77
83
|
|
78
84
|
def deletion_range(node)
|
79
|
-
range_between(node.
|
85
|
+
range_between(node.first_argument.source_range.end_pos,
|
80
86
|
node.arguments[1].source_range.end_pos)
|
81
87
|
end
|
82
88
|
|
@@ -106,11 +112,11 @@ module RuboCop
|
|
106
112
|
end
|
107
113
|
|
108
114
|
def to_options(attrs)
|
109
|
-
attrs.each.
|
115
|
+
attrs.each.filter_map do |key, value|
|
110
116
|
next if key == 'id'
|
111
117
|
|
112
118
|
"#{key}: #{value}"
|
113
|
-
end.
|
119
|
+
end.join(', ')
|
114
120
|
end
|
115
121
|
|
116
122
|
def offense_range(node)
|
@@ -23,7 +23,7 @@ module RuboCop
|
|
23
23
|
# expect(page).to have_no_link('foo', class: 'cls', href: 'http://example.com')
|
24
24
|
# expect(page).to have_table(class: 'cls')
|
25
25
|
# expect(page).to have_select
|
26
|
-
# expect(page).to have_field('foo')
|
26
|
+
# expect(page).to have_field(with: 'foo')
|
27
27
|
#
|
28
28
|
class SpecificMatcher < ::RuboCop::Cop::Base
|
29
29
|
MSG = 'Prefer `%<good_matcher>s` over `%<bad_matcher>s`.'
|
@@ -38,10 +38,15 @@ module RuboCop
|
|
38
38
|
}.freeze
|
39
39
|
|
40
40
|
# @!method first_argument(node)
|
41
|
-
def_node_matcher :first_argument,
|
41
|
+
def_node_matcher :first_argument, <<~PATTERN
|
42
42
|
(send nil? _ (str $_) ... )
|
43
43
|
PATTERN
|
44
44
|
|
45
|
+
# @!method text_with_regexp?(node)
|
46
|
+
def_node_search :text_with_regexp?, <<~PATTERN
|
47
|
+
(pair (sym {:text :exact_text}) (regexp ...))
|
48
|
+
PATTERN
|
49
|
+
|
45
50
|
def on_send(node)
|
46
51
|
first_argument(node) do |arg|
|
47
52
|
next unless (matcher = specific_matcher(arg))
|
@@ -61,6 +66,7 @@ module RuboCop
|
|
61
66
|
|
62
67
|
def replaceable?(node, arg, matcher)
|
63
68
|
replaceable_attributes?(arg) &&
|
69
|
+
!text_with_regexp?(node) &&
|
64
70
|
CapybaraHelp.replaceable_option?(node, arg, matcher) &&
|
65
71
|
CapybaraHelp.replaceable_pseudo_classes?(arg)
|
66
72
|
end
|
@@ -7,6 +7,7 @@ require_relative 'capybara/click_link_or_button_style'
|
|
7
7
|
require_relative 'capybara/current_path_expectation'
|
8
8
|
require_relative 'capybara/match_style'
|
9
9
|
require_relative 'capybara/negation_matcher'
|
10
|
+
require_relative 'capybara/redundant_within_find'
|
10
11
|
require_relative 'capybara/specific_actions'
|
11
12
|
require_relative 'capybara/specific_finders'
|
12
13
|
require_relative 'capybara/specific_matcher'
|
data/lib/rubocop-capybara.rb
CHANGED
@@ -6,6 +6,7 @@ require 'yaml'
|
|
6
6
|
require 'rubocop'
|
7
7
|
|
8
8
|
require_relative 'rubocop/cop/capybara/mixin/capybara_help'
|
9
|
+
require_relative 'rubocop/cop/capybara/mixin/css_attributes_parser'
|
9
10
|
require_relative 'rubocop/cop/capybara/mixin/css_selector'
|
10
11
|
|
11
12
|
require_relative 'rubocop/cop/capybara_cops'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-capybara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yudai Takada
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -24,10 +24,10 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.41'
|
27
|
-
description: |
|
28
|
-
|
29
|
-
|
30
|
-
email:
|
27
|
+
description: |
|
28
|
+
Code style checking for Capybara test files (RSpec, Cucumber, Minitest).
|
29
|
+
A plugin for the RuboCop code style enforcing & linting tool.
|
30
|
+
email:
|
31
31
|
executables: []
|
32
32
|
extensions: []
|
33
33
|
extra_rdoc_files:
|
@@ -41,14 +41,17 @@ files:
|
|
41
41
|
- config/default.yml
|
42
42
|
- lib/rubocop-capybara.rb
|
43
43
|
- lib/rubocop/capybara/config_formatter.rb
|
44
|
+
- lib/rubocop/capybara/cop/generator.rb
|
44
45
|
- lib/rubocop/capybara/description_extractor.rb
|
45
46
|
- lib/rubocop/capybara/version.rb
|
46
47
|
- lib/rubocop/cop/capybara/click_link_or_button_style.rb
|
47
48
|
- lib/rubocop/cop/capybara/current_path_expectation.rb
|
48
49
|
- lib/rubocop/cop/capybara/match_style.rb
|
49
50
|
- lib/rubocop/cop/capybara/mixin/capybara_help.rb
|
51
|
+
- lib/rubocop/cop/capybara/mixin/css_attributes_parser.rb
|
50
52
|
- lib/rubocop/cop/capybara/mixin/css_selector.rb
|
51
53
|
- lib/rubocop/cop/capybara/negation_matcher.rb
|
54
|
+
- lib/rubocop/cop/capybara/redundant_within_find.rb
|
52
55
|
- lib/rubocop/cop/capybara/rspec/have_selector.rb
|
53
56
|
- lib/rubocop/cop/capybara/rspec/predicate_matcher.rb
|
54
57
|
- lib/rubocop/cop/capybara/specific_actions.rb
|
@@ -63,7 +66,7 @@ metadata:
|
|
63
66
|
changelog_uri: https://github.com/rubocop/rubocop-capybara/blob/main/CHANGELOG.md
|
64
67
|
documentation_uri: https://docs.rubocop.org/rubocop-capybara/
|
65
68
|
rubygems_mfa_required: 'true'
|
66
|
-
post_install_message:
|
69
|
+
post_install_message:
|
67
70
|
rdoc_options: []
|
68
71
|
require_paths:
|
69
72
|
- lib
|
@@ -78,8 +81,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
81
|
- !ruby/object:Gem::Version
|
79
82
|
version: '0'
|
80
83
|
requirements: []
|
81
|
-
rubygems_version: 3.
|
82
|
-
signing_key:
|
84
|
+
rubygems_version: 3.5.9
|
85
|
+
signing_key:
|
83
86
|
specification_version: 4
|
84
87
|
summary: Code style checking for Capybara test files
|
85
88
|
test_files: []
|