rubocop-capybara 2.23.0 → 3.1.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +53 -0
  3. data/README.md +1 -1
  4. data/config/default.yml +97 -32
  5. data/lib/rubocop/capybara/plugin.rb +2 -3
  6. data/lib/rubocop/capybara/version.rb +1 -1
  7. data/lib/rubocop/cop/capybara/absolute_x_path_in_element_scope.rb +104 -0
  8. data/lib/rubocop/cop/capybara/always_true_count_query.rb +75 -0
  9. data/lib/rubocop/cop/capybara/ambiguous_click.rb +1 -1
  10. data/lib/rubocop/cop/capybara/assert_style.rb +1 -1
  11. data/lib/rubocop/cop/capybara/chained_find.rb +175 -0
  12. data/lib/rubocop/cop/capybara/find_all_first.rb +13 -41
  13. data/lib/rubocop/cop/capybara/ignored_query_option.rb +242 -0
  14. data/lib/rubocop/cop/capybara/mixin/capybara_help.rb +86 -2
  15. data/lib/rubocop/cop/capybara/mixin/css_attributes_parser.rb +23 -5
  16. data/lib/rubocop/cop/capybara/mixin/css_selector.rb +13 -10
  17. data/lib/rubocop/cop/capybara/mixin/query_methods.rb +120 -0
  18. data/lib/rubocop/cop/capybara/mixin/visibility.rb +53 -0
  19. data/lib/rubocop/cop/capybara/modal_method_without_block.rb +37 -0
  20. data/lib/rubocop/cop/capybara/native_attribute.rb +76 -0
  21. data/lib/rubocop/cop/capybara/redundant_within_find.rb +10 -21
  22. data/lib/rubocop/cop/capybara/rspec/current_path_expectation.rb +13 -16
  23. data/lib/rubocop/cop/capybara/rspec/current_url_expectation.rb +122 -0
  24. data/lib/rubocop/cop/capybara/rspec/find_element_value_eq.rb +173 -0
  25. data/lib/rubocop/cop/capybara/rspec/have_content.rb +1 -1
  26. data/lib/rubocop/cop/capybara/rspec/have_selector.rb +26 -15
  27. data/lib/rubocop/cop/capybara/rspec/match_style.rb +1 -1
  28. data/lib/rubocop/cop/capybara/rspec/negation_matcher.rb +1 -1
  29. data/lib/rubocop/cop/capybara/rspec/negation_matcher_after_visit.rb +2 -2
  30. data/lib/rubocop/cop/capybara/rspec/predicate_matcher.rb +43 -7
  31. data/lib/rubocop/cop/capybara/rspec/specific_matcher.rb +8 -2
  32. data/lib/rubocop/cop/capybara/rspec/visibility_matcher.rb +29 -24
  33. data/lib/rubocop/cop/capybara/rspec.rb +25 -0
  34. data/lib/rubocop/cop/capybara/specific_actions.rb +12 -7
  35. data/lib/rubocop/cop/capybara/specific_finders.rb +149 -28
  36. data/lib/rubocop/cop/capybara/unordered_window_access.rb +40 -0
  37. data/lib/rubocop/cop/capybara/visibility_option.rb +64 -0
  38. data/lib/rubocop/cop/capybara.rb +28 -0
  39. data/lib/rubocop/cop/capybara_cops.rb +4 -17
  40. data/lib/rubocop-capybara.rb +7 -5
  41. metadata +18 -6
  42. data/config/obsoletion.yml +0 -18
  43. data/lib/rubocop/cop/capybara/click_link_or_button_style.rb +0 -87
@@ -3,6 +3,43 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Capybara
6
+ # Help methods for SpecificFinders.
7
+ # @api private
8
+ module SpecificFindersHelp
9
+ MESSAGE = 'Prefer `%<good_finder>s` over `find`.'
10
+ FIELD_OPTIONS = CapybaraHelp::SPECIFIC_OPTIONS['field']
11
+ FIELD_SELECTOR_PATTERN = /\Ainput(?:\[.+\])+\z/.freeze
12
+ UNSAFE_FIELD_TYPES = %w[hidden image submit].freeze
13
+ FIELD_STATE_OPTIONS = %w[checked disabled multiple readonly].freeze
14
+
15
+ module_function
16
+
17
+ def field_selector?(arg)
18
+ return false unless FIELD_SELECTOR_PATTERN.match?(arg)
19
+
20
+ attrs = CssSelector.attributes(arg)
21
+ type = attrs['type'].to_s.downcase
22
+ return false if UNSAFE_FIELD_TYPES.include?(type)
23
+ return false if (attrs.keys & FIELD_STATE_OPTIONS).any?
24
+
25
+ CapybaraHelp.replaceable_attributes?(attrs) &&
26
+ attrs.keys.all? { |attr| FIELD_OPTIONS.include?(attr) }
27
+ end
28
+
29
+ def options(attrs)
30
+ attrs.filter_map { |key, value| "#{key}: #{yield(value)}" }.join(', ')
31
+ end
32
+
33
+ def unsupported_selector?(arg)
34
+ CssSelector.pseudo_classes(arg).any? ||
35
+ CssSelector.multiple_selectors?(arg)
36
+ end
37
+
38
+ def message(finder)
39
+ format(MESSAGE, good_finder: finder)
40
+ end
41
+ end
42
+
6
43
  # Checks if there is a more specific finder offered by Capybara.
7
44
  #
8
45
  # @example
@@ -11,43 +48,90 @@ module RuboCop
11
48
  # find('[id=some-id]')
12
49
  # find(:css, '#some-id')
13
50
  # find(:id, 'some-id')
51
+ # find(:link, 'Home')
52
+ # find(:field, 'Name')
53
+ # find('input[placeholder="Email"]')
54
+ # find(:css, 'input[type="checkbox"]')
14
55
  #
15
56
  # # good
16
57
  # find_by_id('some-id')
58
+ # find_link('Home')
59
+ # find_field('Name')
60
+ # find_field(placeholder: 'Email')
61
+ # find_field(type: 'checkbox')
17
62
  #
18
- class SpecificFinders < ::RuboCop::Cop::Base
63
+ class SpecificFinders < RuboCop::Cop::Base # rubocop:disable Metrics/ClassLength
19
64
  extend AutoCorrector
20
65
  include RangeHelp
21
66
 
22
- MSG = 'Prefer `find_by_id` over `find`.'
67
+ MSG = 'Prefer `%<replacement>s` over `find`.'
23
68
  RESTRICT_ON_SEND = %i[find].freeze
24
69
 
25
70
  # @!method find_argument(node)
26
71
  def_node_matcher :find_argument, <<~PATTERN
27
- (send _ :find $(sym {:css :id})? (str $_) ...)
72
+ (send _ :find $(sym {:css :id :link :field})? (str $_) ...)
28
73
  PATTERN
29
74
 
30
- # @!method class_options(node)
31
- def_node_search :class_options, <<~PATTERN
32
- (pair (sym :class) $_ ...)
75
+ # @!method class_option(node)
76
+ def_node_matcher :class_option, <<~PATTERN
77
+ (send _ :find ... (hash <(pair (sym :class) $_) ...>))
33
78
  PATTERN
34
79
 
35
80
  def on_send(node)
36
81
  find_argument(node) do |sym, arg|
37
- next if CssSelector.pseudo_classes(arg).any?
38
- next if CssSelector.multiple_selectors?(arg)
39
-
40
- on_attr(node, sym, arg) if attribute?(arg)
41
- on_id(node, sym, arg) if CssSelector.id?(arg)
42
- on_sym_id(node, sym, arg) if sym.first&.value == :id
82
+ handle_find(node, sym, arg)
43
83
  end
44
84
  end
45
85
 
46
86
  private
47
87
 
88
+ def selector?(sym)
89
+ %i[link field].include?(sym.first.value)
90
+ end
91
+
92
+ def id_symbol?(sym)
93
+ sym.first&.value == :id
94
+ end
95
+
96
+ def selector_symbol?(sym)
97
+ sym.first && selector?(sym)
98
+ end
99
+
100
+ def on_sym_selector(node, sym)
101
+ replacement = "find_#{sym.first.value}"
102
+ register_selector_offense(node, replacement)
103
+ end
104
+
105
+ def register_selector_offense(node, replacement)
106
+ message = format(MSG, replacement: replacement)
107
+ add_offense(offense_range(node), message: message) do |corrector|
108
+ corrector.replace(node.loc.selector, replacement)
109
+ remove_selector_argument(corrector, node)
110
+ end
111
+ end
112
+
113
+ def remove_selector_argument(corrector, node)
114
+ range = range_between(node.first_argument.source_range.begin_pos,
115
+ node.arguments[1].source_range.begin_pos)
116
+ corrector.remove(range)
117
+ end
118
+
119
+ def handle_find(node, sym, arg)
120
+ return on_sym_id(node, sym, arg) if id_symbol?(sym)
121
+ return on_sym_selector(node, sym) if selector_symbol?(sym)
122
+ return if SpecificFindersHelp.unsupported_selector?(arg)
123
+
124
+ if SpecificFindersHelp.field_selector?(arg)
125
+ return on_field(node, sym, arg)
126
+ end
127
+ return on_attr(node, sym, arg) if attribute?(arg)
128
+
129
+ on_id(node, sym, arg) if CssSelector.id?(arg)
130
+ end
131
+
48
132
  def on_attr(node, sym, arg)
49
133
  attrs = CssSelector.attributes(arg)
50
- return unless (id = attrs['id'])
134
+ return unless (id = attrs['id']&.to_s)
51
135
  return if attrs['class']
52
136
 
53
137
  register_offense(node, sym, replaced_arguments(arg, id))
@@ -57,12 +141,29 @@ module RuboCop
57
141
  return if CssSelector.attributes(arg).any?
58
142
 
59
143
  id = CssSelector.id(arg)
60
- register_offense(node, sym, "'#{id}'",
144
+ register_offense(node, sym, ruby_literal(id.delete('\\')),
61
145
  CssSelector.classes(arg.sub("##{id}", '')))
62
146
  end
63
147
 
64
148
  def on_sym_id(node, sym, id)
65
- register_offense(node, sym, "'#{id}'")
149
+ register_offense(node, sym, ruby_literal(id))
150
+ end
151
+
152
+ def on_field(node, sym, arg)
153
+ add_offense(
154
+ offense_range(node),
155
+ message: SpecificFindersHelp.message('find_field')
156
+ ) do |corrector|
157
+ corrector.replace(node.loc.selector, 'find_field')
158
+ corrector.replace(node.first_argument, field_options(arg))
159
+ corrector.remove(deletion_range(node)) unless sym.empty?
160
+ end
161
+ end
162
+
163
+ def field_options(arg)
164
+ SpecificFindersHelp.options(CssSelector.attributes(arg)) do |value|
165
+ ruby_literal(value)
166
+ end
66
167
  end
67
168
 
68
169
  def attribute?(arg)
@@ -70,24 +171,36 @@ module RuboCop
70
171
  CapybaraHelp.common_attributes?(arg)
71
172
  end
72
173
 
73
- def register_offense(node, sym, id, classes = [])
74
- add_offense(offense_range(node)) do |corrector|
174
+ def register_offense(node, sym, replacement, classes = [])
175
+ message = format(MSG, replacement: 'find_by_id')
176
+ add_offense(offense_range(node), message: message) do |corrector|
177
+ next unless autocorrectable_classes?(node, classes)
178
+
75
179
  corrector.replace(node.loc.selector, 'find_by_id')
76
- corrector.replace(node.first_argument, id.delete('\\'))
77
- unless classes.compact.empty?
78
- autocorrect_classes(corrector, node, classes)
79
- end
180
+ corrector.replace(node.first_argument, replacement)
181
+ autocorrect_id_classes(corrector, node, classes)
80
182
  corrector.remove(deletion_range(node)) unless sym.empty?
81
183
  end
82
184
  end
83
185
 
186
+ def autocorrectable_classes?(node, classes)
187
+ return true if classes.empty? || !(options = class_option(node))
188
+
189
+ options.str_type? ||
190
+ (options.array_type? && options.values.all?(&:str_type?))
191
+ end
192
+
193
+ def autocorrect_id_classes(corrector, node, classes)
194
+ autocorrect_classes(corrector, node, classes) unless classes.empty?
195
+ end
196
+
84
197
  def deletion_range(node)
85
198
  range_between(node.first_argument.source_range.end_pos,
86
199
  node.arguments[1].source_range.end_pos)
87
200
  end
88
201
 
89
202
  def autocorrect_classes(corrector, node, classes)
90
- if (options = class_options(node).first)
203
+ if (options = class_option(node))
91
204
  append_options(classes, options)
92
205
  corrector.replace(options, classes.to_s)
93
206
  else
@@ -108,6 +221,8 @@ module RuboCop
108
221
 
109
222
  def replaced_arguments(arg, id)
110
223
  options = to_options(CssSelector.attributes(arg))
224
+ id = ruby_literal(id.delete('\\'))
225
+
111
226
  options.empty? ? id : "#{id}, #{options}"
112
227
  end
113
228
 
@@ -115,20 +230,26 @@ module RuboCop
115
230
  attrs.each.filter_map do |key, value|
116
231
  next if key == 'id'
117
232
 
118
- "#{key}: #{value}"
233
+ "#{key}: #{ruby_literal(value)}"
119
234
  end.join(', ')
120
235
  end
121
236
 
237
+ def ruby_literal(value)
238
+ case value
239
+ when String
240
+ "'#{value.gsub(/['\\]/) { |char| "\\#{char}" }}'"
241
+ when nil then 'nil'
242
+ else
243
+ value.to_s
244
+ end
245
+ end
246
+
122
247
  def offense_range(node)
123
248
  range_between(node.loc.selector.begin_pos, end_pos(node))
124
249
  end
125
250
 
126
251
  def end_pos(node)
127
- if node.loc.end
128
- node.loc.end.end_pos
129
- else
130
- node.source_range.end_pos
131
- end
252
+ node.loc.end ? node.loc.end.end_pos : node.source_range.end_pos
132
253
  end
133
254
  end
134
255
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Capybara
6
+ # Checks positional access to Capybara windows, whose order is undefined.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # popup = windows.last
11
+ # original = page.windows.first
12
+ #
13
+ # # good
14
+ # popup = window_opened_by { click_link 'Open' }
15
+ # original = current_window
16
+ #
17
+ class UnorderedWindowAccess < RuboCop::Cop::Base
18
+ MSG = 'Selecting a window by position relies on undefined order. ' \
19
+ 'Use `window_opened_by` or `current_window`.'
20
+ RESTRICT_ON_SEND = %i[first last [] at fetch].freeze
21
+
22
+ # @!method capybara_windows?(node)
23
+ def_node_matcher :capybara_windows?, <<~PATTERN
24
+ (call
25
+ {nil? self
26
+ (call {nil? self} :page)
27
+ (call (const {nil? cbase} :Capybara) :current_session)}
28
+ :windows)
29
+ PATTERN
30
+
31
+ def on_send(node)
32
+ return if node.method?(:[]) && node.first_argument&.type?(:range)
33
+
34
+ add_offense(node) if capybara_windows?(node.receiver)
35
+ end
36
+ alias on_csend on_send
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Capybara
6
+ # Checks for boolean values passed to Capybara's `visible` option.
7
+ #
8
+ # `visible: false` finds both visible and hidden elements, rather than
9
+ # only hidden elements. Use `:all`, `:hidden` or `:visible` instead.
10
+ # Only `true` is autocorrected, to `:visible`.
11
+ #
12
+ # This cop targets Capybara's built-in selectors. Set `DefaultSelector`
13
+ # to match `Capybara.default_selector`, or to `null` if it varies at
14
+ # runtime. Queries using custom or unknown selectors are skipped.
15
+ #
16
+ # @example
17
+ # # bad
18
+ # find('.menu', visible: true)
19
+ # expect(page).to have_css('.menu', visible: false)
20
+ #
21
+ # # good
22
+ # find('.menu', visible: :visible)
23
+ # find('.menu', visible: :all)
24
+ # find('.menu', visible: :hidden)
25
+ #
26
+ # @example DefaultSelector: custom
27
+ # # bad
28
+ # find(:css, '.menu', visible: true)
29
+ #
30
+ # # good
31
+ # find('.menu', visible: true)
32
+ #
33
+ class VisibilityOption < RuboCop::Cop::Base
34
+ extend AutoCorrector
35
+ include CapybaraHelp
36
+ include Visibility
37
+
38
+ RESTRICT_ON_SEND = QueryMethods.names(
39
+ :finder, :collection, :selector, :match, :action, :grouped
40
+ ).difference(CapybaraHelp::VISIBILITY_MATCHER_METHODS).freeze
41
+
42
+ # @!method visibility_options(node)
43
+ def_node_matcher :visibility_options, <<~PATTERN
44
+ (call #capybara_receiver? _ <$(hash ...) ...>)
45
+ PATTERN
46
+
47
+ # @!method boolean_visibility?(node)
48
+ def_node_matcher :boolean_visibility?, <<~PATTERN
49
+ (pair (sym :visible) boolean)
50
+ PATTERN
51
+
52
+ def on_send(node)
53
+ return unless (options = visibility_options(node))
54
+ return unless supported_visibility_query?(node, options)
55
+
56
+ options.pairs.each do |pair|
57
+ check_visibility(pair) if boolean_visibility?(pair)
58
+ end
59
+ end
60
+ alias on_csend on_send
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'capybara/rspec'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ # Cops for the `Capybara` department. The department's cops are
8
+ # registered for lazy loading and their files are loaded on demand.
9
+ module Capybara
10
+ extend LazyLoader
11
+
12
+ register_cop :AbsoluteXPathInElementScope, "#{__dir__}/capybara/absolute_x_path_in_element_scope"
13
+ register_cop :AlwaysTrueCountQuery, "#{__dir__}/capybara/always_true_count_query"
14
+ register_cop :AmbiguousClick, "#{__dir__}/capybara/ambiguous_click"
15
+ register_cop :AssertStyle, "#{__dir__}/capybara/assert_style"
16
+ register_cop :ChainedFind, "#{__dir__}/capybara/chained_find"
17
+ register_cop :FindAllFirst, "#{__dir__}/capybara/find_all_first"
18
+ register_cop :IgnoredQueryOption, "#{__dir__}/capybara/ignored_query_option"
19
+ register_cop :ModalMethodWithoutBlock, "#{__dir__}/capybara/modal_method_without_block"
20
+ register_cop :NativeAttribute, "#{__dir__}/capybara/native_attribute"
21
+ register_cop :RedundantWithinFind, "#{__dir__}/capybara/redundant_within_find"
22
+ register_cop :SpecificActions, "#{__dir__}/capybara/specific_actions"
23
+ register_cop :SpecificFinders, "#{__dir__}/capybara/specific_finders"
24
+ register_cop :UnorderedWindowAccess, "#{__dir__}/capybara/unordered_window_access"
25
+ register_cop :VisibilityOption, "#{__dir__}/capybara/visibility_option"
26
+ end
27
+ end
28
+ end
@@ -1,19 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'capybara/rspec/current_path_expectation'
4
- require_relative 'capybara/rspec/have_content'
5
- require_relative 'capybara/rspec/have_selector'
6
- require_relative 'capybara/rspec/match_style'
7
- require_relative 'capybara/rspec/negation_matcher'
8
- require_relative 'capybara/rspec/negation_matcher_after_visit'
9
- require_relative 'capybara/rspec/predicate_matcher'
10
- require_relative 'capybara/rspec/specific_matcher'
11
- require_relative 'capybara/rspec/visibility_matcher'
12
-
13
- require_relative 'capybara/ambiguous_click'
14
- require_relative 'capybara/assert_style'
15
- require_relative 'capybara/click_link_or_button_style'
16
- require_relative 'capybara/find_all_first'
17
- require_relative 'capybara/redundant_within_find'
18
- require_relative 'capybara/specific_actions'
19
- require_relative 'capybara/specific_finders'
3
+ # @deprecated This file is deprecated. Cops are registered for lazy loading in
4
+ # `rubocop/cop/capybara`; this file is kept for compatibility with code that
5
+ # requires it directly.
6
+ require_relative 'capybara'
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
- require 'yaml'
5
-
6
3
  require 'rubocop'
7
4
 
8
5
  require_relative 'rubocop/capybara/plugin'
@@ -11,13 +8,18 @@ require_relative 'rubocop/capybara/version'
11
8
  require_relative 'rubocop/cop/capybara/mixin/capybara_help'
12
9
  require_relative 'rubocop/cop/capybara/mixin/css_attributes_parser'
13
10
  require_relative 'rubocop/cop/capybara/mixin/css_selector'
11
+ require_relative 'rubocop/cop/capybara/mixin/query_methods'
12
+ require_relative 'rubocop/cop/capybara/mixin/visibility'
14
13
 
15
- require_relative 'rubocop/cop/capybara_cops'
14
+ require_relative 'rubocop/cop/capybara'
16
15
 
17
16
  RuboCop::Cop::Style::TrailingCommaInArguments.singleton_class.prepend(
18
17
  Module.new do
19
18
  def autocorrect_incompatible_with
20
- super.push(RuboCop::Cop::Capybara::RSpec::CurrentPathExpectation)
19
+ super.push(
20
+ RuboCop::Cop::Capybara::RSpec::CurrentPathExpectation,
21
+ RuboCop::Cop::Capybara::RSpec::CurrentUrlExpectation
22
+ )
21
23
  end
22
24
  end
23
25
  )
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-capybara
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.23.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yudai Takada
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '1.81'
32
+ version: '1.89'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.81'
39
+ version: '1.89'
40
40
  description: |
41
41
  Code style checking for Capybara test files (RSpec, Cucumber, Minitest).
42
42
  A plugin for the RuboCop code style enforcing & linting tool.
@@ -51,22 +51,32 @@ files:
51
51
  - MIT-LICENSE.md
52
52
  - README.md
53
53
  - config/default.yml
54
- - config/obsoletion.yml
55
54
  - lib/rubocop-capybara.rb
56
55
  - lib/rubocop/capybara/config_formatter.rb
57
56
  - lib/rubocop/capybara/cop/generator.rb
58
57
  - lib/rubocop/capybara/description_extractor.rb
59
58
  - lib/rubocop/capybara/plugin.rb
60
59
  - lib/rubocop/capybara/version.rb
60
+ - lib/rubocop/cop/capybara.rb
61
+ - lib/rubocop/cop/capybara/absolute_x_path_in_element_scope.rb
62
+ - lib/rubocop/cop/capybara/always_true_count_query.rb
61
63
  - lib/rubocop/cop/capybara/ambiguous_click.rb
62
64
  - lib/rubocop/cop/capybara/assert_style.rb
63
- - lib/rubocop/cop/capybara/click_link_or_button_style.rb
65
+ - lib/rubocop/cop/capybara/chained_find.rb
64
66
  - lib/rubocop/cop/capybara/find_all_first.rb
67
+ - lib/rubocop/cop/capybara/ignored_query_option.rb
65
68
  - lib/rubocop/cop/capybara/mixin/capybara_help.rb
66
69
  - lib/rubocop/cop/capybara/mixin/css_attributes_parser.rb
67
70
  - lib/rubocop/cop/capybara/mixin/css_selector.rb
71
+ - lib/rubocop/cop/capybara/mixin/query_methods.rb
72
+ - lib/rubocop/cop/capybara/mixin/visibility.rb
73
+ - lib/rubocop/cop/capybara/modal_method_without_block.rb
74
+ - lib/rubocop/cop/capybara/native_attribute.rb
68
75
  - lib/rubocop/cop/capybara/redundant_within_find.rb
76
+ - lib/rubocop/cop/capybara/rspec.rb
69
77
  - lib/rubocop/cop/capybara/rspec/current_path_expectation.rb
78
+ - lib/rubocop/cop/capybara/rspec/current_url_expectation.rb
79
+ - lib/rubocop/cop/capybara/rspec/find_element_value_eq.rb
70
80
  - lib/rubocop/cop/capybara/rspec/have_content.rb
71
81
  - lib/rubocop/cop/capybara/rspec/have_selector.rb
72
82
  - lib/rubocop/cop/capybara/rspec/match_style.rb
@@ -77,6 +87,8 @@ files:
77
87
  - lib/rubocop/cop/capybara/rspec/visibility_matcher.rb
78
88
  - lib/rubocop/cop/capybara/specific_actions.rb
79
89
  - lib/rubocop/cop/capybara/specific_finders.rb
90
+ - lib/rubocop/cop/capybara/unordered_window_access.rb
91
+ - lib/rubocop/cop/capybara/visibility_option.rb
80
92
  - lib/rubocop/cop/capybara_cops.rb
81
93
  homepage: https://github.com/rubocop/rubocop-capybara
82
94
  licenses:
@@ -100,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
112
  - !ruby/object:Gem::Version
101
113
  version: '0'
102
114
  requirements: []
103
- rubygems_version: 4.0.6
115
+ rubygems_version: 4.0.20
104
116
  specification_version: 4
105
117
  summary: Code style checking for Capybara test files
106
118
  test_files: []
@@ -1,18 +0,0 @@
1
- #
2
- # Configuration of obsolete/deprecated cops used by `ConfigObsoletion`.
3
- #
4
- # See: https://docs.rubocop.org/rubocop/extensions.html#config-obsoletions
5
- #
6
-
7
- renamed:
8
- Capybara/CurrentPathExpectation: Capybara/RSpec/CurrentPathExpectation
9
- Capybara/NegationMatcher: Capybara/RSpec/NegationMatcher
10
- Capybara/NegationMatcherAfterVisit: Capybara/RSpec/NegationMatcherAfterVisit
11
- Capybara/SpecificMatcher: Capybara/RSpec/SpecificMatcher
12
- Capybara/VisibilityMatcher: Capybara/RSpec/VisibilityMatcher
13
-
14
- split:
15
- Capybara/MatchStyle:
16
- alternatives:
17
- - Capybara/AssertStyle
18
- - Capybara/RSpec/MatchStyle
@@ -1,87 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Capybara
6
- # Checks for methods of button or link clicks.
7
- #
8
- # This cop is deprecated.
9
- # We plan to remove this in the next major version update to 3.0.
10
- #
11
- # The migration target is `Capybara/AmbiguousClick`.
12
- # It is only migration target when `EnforcedStyle: strict`.
13
- # If you are using this cop, please plan for migration.
14
- # There is no migration target when `EnforcedStyle: link_or_button`.
15
- #
16
- # By default, prefer to use `click_link_or_button` or `click_on`.
17
- # These methods offer a weaker coupling between the test and HTML,
18
- # allowing for a more faithful reflection of how the user behaves.
19
- #
20
- # You can set `EnforcedStyle: strict` to prefer the use of
21
- # `click_link` and `click_button`, but this is a deprecated setting.
22
- #
23
- # @example EnforcedStyle: link_or_button (default)
24
- # # bad
25
- # click_link('foo')
26
- # click_button('foo')
27
- #
28
- # # good
29
- # click_link_or_button('foo')
30
- # click_on('foo')
31
- #
32
- # @example EnforcedStyle: strict
33
- # # bad
34
- # click_link_or_button('foo')
35
- # click_on('foo')
36
- #
37
- # # good
38
- # click_link('foo')
39
- # click_button('foo')
40
- #
41
- class ClickLinkOrButtonStyle < ::RuboCop::Cop::Base
42
- include ConfigurableEnforcedStyle
43
-
44
- MSG_STRICT =
45
- 'Use `click_link` or `click_button` instead of `%<method>s`.'
46
- MSG_CLICK_LINK_OR_BUTTON =
47
- 'Use `click_link_or_button` or `click_on` instead of `%<method>s`.'
48
- STRICT_METHODS = %i[click_link click_button].freeze
49
- CLICK_LINK_OR_BUTTON = %i[click_link_or_button click_on].freeze
50
- RESTRICT_ON_SEND = (STRICT_METHODS + CLICK_LINK_OR_BUTTON).freeze
51
-
52
- def on_send(node)
53
- return unless offense?(node)
54
-
55
- add_offense(node, message: offense_message(node))
56
- end
57
-
58
- private
59
-
60
- def offense?(node)
61
- (style == :strict && !strict_method?(node)) ||
62
- (style == :link_or_button && !link_or_button_method?(node))
63
- end
64
-
65
- def offense_message(node)
66
- if style == :strict
67
- format(MSG_STRICT, method: node.method_name)
68
- elsif style == :link_or_button
69
- format(MSG_CLICK_LINK_OR_BUTTON, method: node.method_name)
70
- else
71
- # :nocov:
72
- :noop
73
- # :nocov:
74
- end
75
- end
76
-
77
- def strict_method?(node)
78
- STRICT_METHODS.include?(node.method_name)
79
- end
80
-
81
- def link_or_button_method?(node)
82
- CLICK_LINK_OR_BUTTON.include?(node.method_name)
83
- end
84
- end
85
- end
86
- end
87
- end