rubocop-capybara 2.19.0 → 2.20.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 +9 -0
- data/config/default.yml +12 -4
- 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/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 +10 -10
- 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_finders.rb +1 -1
- data/lib/rubocop/cop/capybara/specific_matcher.rb +6 -0
- data/lib/rubocop/cop/capybara_cops.rb +1 -0
- data/lib/rubocop-capybara.rb +1 -0
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 963a68452b58c47db1d1d9e7f9201db0a98a8b70bb8089473b406911fa5cc33e
|
|
4
|
+
data.tar.gz: 58e60dd5ff6097695a1029b9e37414209f7c26d2da0d16cbc6b808c8cd56efd8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cec93e7919aeefbb1f2b2c13f1f0caeb7627c5556f85fe219f107b6520237cccd792ad4713905dfb47151f0bcb82e04d4bd0034a7a747b741e607ea9d4de5e54
|
|
7
|
+
data.tar.gz: 3e359ec71065b5daf64cdb080d8ddfad4f6144778ad7fb89d932aa083353547663a1316efe7f9e9fd3cb7bca6a6f012812ea7f18e00c76a8af22316f24325f7c
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Edge (Unreleased)
|
|
4
4
|
|
|
5
|
+
## 2.20.0 (2024-01-03)
|
|
6
|
+
|
|
7
|
+
- Change to default `EnforcedStyle: link_or_button` for `Capybara/ClickLinkOrButtonStyle` cop. ([@ydah])
|
|
8
|
+
- Fix a false negative for `RSpec/HaveSelector` when first argument is dstr node. ([@ydah])
|
|
9
|
+
- Add new `Capybara/RedundantWithinFind` cop. ([@ydah])
|
|
10
|
+
- Fix an invalid attributes parse when name with multiple `[]` for `Capybara/SpecificFinders` and `Capybara/SpecificActions` and `Capybara/SpecificMatcher`. ([@ydah])
|
|
11
|
+
- Change to default `EnforcedStyle: have_no` for `Capybara/NegationMatcher` cop. ([@ydah])
|
|
12
|
+
- Fix a false positive for `Capybara/SpecificMatcher` when `text:` or `exact_text:` with regexp. ([@ydah])
|
|
13
|
+
|
|
5
14
|
## 2.19.0 (2023-09-20)
|
|
6
15
|
|
|
7
16
|
- 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
|
|
@@ -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)
|
|
@@ -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.chars 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,16 +5,7 @@ module RuboCop
|
|
|
5
5
|
module Capybara
|
|
6
6
|
# Enforces use of `have_no_*` or `not_to` for negated expectations.
|
|
7
7
|
#
|
|
8
|
-
# @example EnforcedStyle:
|
|
9
|
-
# # bad
|
|
10
|
-
# expect(page).to have_no_selector
|
|
11
|
-
# expect(page).to have_no_css('a')
|
|
12
|
-
#
|
|
13
|
-
# # good
|
|
14
|
-
# expect(page).not_to have_selector
|
|
15
|
-
# expect(page).not_to have_css('a')
|
|
16
|
-
#
|
|
17
|
-
# @example EnforcedStyle: have_no
|
|
8
|
+
# @example EnforcedStyle: have_no (default)
|
|
18
9
|
# # bad
|
|
19
10
|
# expect(page).not_to have_selector
|
|
20
11
|
# expect(page).not_to have_css('a')
|
|
@@ -23,6 +14,15 @@ module RuboCop
|
|
|
23
14
|
# expect(page).to have_no_selector
|
|
24
15
|
# expect(page).to have_no_css('a')
|
|
25
16
|
#
|
|
17
|
+
# @example EnforcedStyle: not_to
|
|
18
|
+
# # bad
|
|
19
|
+
# expect(page).to have_no_selector
|
|
20
|
+
# expect(page).to have_no_css('a')
|
|
21
|
+
#
|
|
22
|
+
# # good
|
|
23
|
+
# expect(page).not_to have_selector
|
|
24
|
+
# expect(page).not_to have_css('a')
|
|
25
|
+
#
|
|
26
26
|
class NegationMatcher < ::RuboCop::Cop::Base
|
|
27
27
|
extend AutoCorrector
|
|
28
28
|
include ConfigurableEnforcedStyle
|
|
@@ -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
|
|
@@ -42,6 +42,11 @@ module RuboCop
|
|
|
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.20.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yudai Takada
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-01-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rubocop
|
|
@@ -47,8 +47,10 @@ files:
|
|
|
47
47
|
- lib/rubocop/cop/capybara/current_path_expectation.rb
|
|
48
48
|
- lib/rubocop/cop/capybara/match_style.rb
|
|
49
49
|
- lib/rubocop/cop/capybara/mixin/capybara_help.rb
|
|
50
|
+
- lib/rubocop/cop/capybara/mixin/css_attributes_parser.rb
|
|
50
51
|
- lib/rubocop/cop/capybara/mixin/css_selector.rb
|
|
51
52
|
- lib/rubocop/cop/capybara/negation_matcher.rb
|
|
53
|
+
- lib/rubocop/cop/capybara/redundant_within_find.rb
|
|
52
54
|
- lib/rubocop/cop/capybara/rspec/have_selector.rb
|
|
53
55
|
- lib/rubocop/cop/capybara/rspec/predicate_matcher.rb
|
|
54
56
|
- lib/rubocop/cop/capybara/specific_actions.rb
|
|
@@ -78,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
78
80
|
- !ruby/object:Gem::Version
|
|
79
81
|
version: '0'
|
|
80
82
|
requirements: []
|
|
81
|
-
rubygems_version: 3.
|
|
83
|
+
rubygems_version: 3.4.22
|
|
82
84
|
signing_key:
|
|
83
85
|
specification_version: 4
|
|
84
86
|
summary: Code style checking for Capybara test files
|