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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5af741b67ec2d02d9e27e688d553e5e1c8cbb04c845f5d9771b480b291b1d805
4
- data.tar.gz: cbef51994ffa79af69a8a7aac9aabf69ccc307b3c2c104eae2a3a4c635467d26
3
+ metadata.gz: 963a68452b58c47db1d1d9e7f9201db0a98a8b70bb8089473b406911fa5cc33e
4
+ data.tar.gz: 58e60dd5ff6097695a1029b9e37414209f7c26d2da0d16cbc6b808c8cd56efd8
5
5
  SHA512:
6
- metadata.gz: 98bcff699a8ee323a24118f26b412ed8e4d26754df9ee82eab0b107f1b96cb2a0ad7ba898925fde7683501244f1474231bd53591f450e6080321e0bd83245257
7
- data.tar.gz: 4194b54f6b12d4b168122c59fbfa18ec210e92cb4d20207665787ae870a3a92a240938818e187889f239e5ce29244db5c612c368bf761ee68f65f1617f72092f
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 click button or link style.
13
+ Description: Checks for methods of button or link clicks.
14
14
  Enabled: pending
15
15
  VersionAdded: '2.19'
16
- EnforcedStyle: strict
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
- EnforcedStyle: not_to
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
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Capybara
5
5
  # Version information for the Capybara RuboCop plugin.
6
6
  module Version
7
- STRING = '2.19.0'
7
+ STRING = '2.20.0'
8
8
  end
9
9
  end
10
10
  end
@@ -3,18 +3,16 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Capybara
6
- # Checks for click button or link style.
6
+ # Checks for methods of button or link clicks.
7
7
  #
8
- # @example EnforcedStyle: strict (default)
9
- # # bad
10
- # click_link_or_button('foo')
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
- # # good
14
- # click_link('foo')
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
- # Extract the inner strings of attributes.
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: not_to (default)
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.str_type?
47
+ on_select_without_type(node) if %i[str dstr].include?(argument.type)
48
48
  end
49
49
 
50
50
  private
@@ -76,7 +76,7 @@ module RuboCop
76
76
  end
77
77
 
78
78
  def deletion_range(node)
79
- range_between(node.arguments[0].source_range.end_pos,
79
+ range_between(node.first_argument.source_range.end_pos,
80
80
  node.arguments[1].source_range.end_pos)
81
81
  end
82
82
 
@@ -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'
@@ -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.19.0
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: 2023-09-19 00:00:00.000000000 Z
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.3.7
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