rubocop-capybara 2.19.0 → 2.20.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|