rubocop-rspec 1.38.1 → 1.43.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 +57 -0
- data/CODE_OF_CONDUCT.md +17 -0
- data/README.md +1 -61
- data/config/default.yml +159 -19
- data/lib/rubocop-rspec.rb +5 -2
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +12 -19
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +12 -19
- data/lib/rubocop/cop/rspec/any_instance.rb +1 -1
- data/lib/rubocop/cop/rspec/around_block.rb +1 -1
- data/lib/rubocop/cop/rspec/base.rb +74 -0
- data/lib/rubocop/cop/rspec/be.rb +2 -2
- data/lib/rubocop/cop/rspec/be_eql.rb +6 -6
- data/lib/rubocop/cop/rspec/before_after_all.rb +1 -1
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +19 -17
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +14 -12
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +69 -0
- data/lib/rubocop/cop/rspec/context_method.rb +7 -9
- data/lib/rubocop/cop/rspec/context_wording.rb +3 -3
- data/lib/rubocop/cop/rspec/cop.rb +3 -87
- data/lib/rubocop/cop/rspec/describe_class.rb +29 -23
- data/lib/rubocop/cop/rspec/describe_method.rb +14 -7
- data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -2
- data/lib/rubocop/cop/rspec/described_class.rb +12 -9
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -1
- data/lib/rubocop/cop/rspec/dialect.rb +5 -12
- data/lib/rubocop/cop/rspec/empty_example_group.rb +91 -7
- data/lib/rubocop/cop/rspec/empty_hook.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +5 -7
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +5 -9
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +8 -8
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +5 -9
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +6 -6
- data/lib/rubocop/cop/rspec/example_length.rb +1 -1
- data/lib/rubocop/cop/rspec/example_without_description.rb +1 -1
- data/lib/rubocop/cop/rspec/example_wording.rb +10 -11
- data/lib/rubocop/cop/rspec/expect_actual.rb +8 -11
- data/lib/rubocop/cop/rspec/expect_change.rb +10 -35
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +3 -3
- data/lib/rubocop/cop/rspec/expect_output.rb +2 -2
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +24 -21
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +20 -22
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +7 -8
- data/lib/rubocop/cop/rspec/file_path.rb +57 -21
- data/lib/rubocop/cop/rspec/focus.rb +7 -11
- data/lib/rubocop/cop/rspec/hook_argument.rb +16 -23
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +10 -29
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_expect.rb +7 -15
- data/lib/rubocop/cop/rspec/implicit_subject.rb +16 -11
- data/lib/rubocop/cop/rspec/instance_spy.rb +18 -12
- data/lib/rubocop/cop/rspec/instance_variable.rb +4 -8
- data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +3 -6
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +5 -6
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/leading_subject.rb +22 -26
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +2 -5
- data/lib/rubocop/cop/rspec/let_before_examples.rb +10 -26
- data/lib/rubocop/cop/rspec/let_setup.rb +21 -6
- data/lib/rubocop/cop/rspec/message_chain.rb +7 -6
- data/lib/rubocop/cop/rspec/message_expectation.rb +2 -2
- data/lib/rubocop/cop/rspec/message_spies.rb +2 -3
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_describes.rb +11 -8
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +7 -11
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +148 -0
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +18 -19
- data/lib/rubocop/cop/rspec/named_subject.rb +8 -8
- data/lib/rubocop/cop/rspec/nested_groups.rb +12 -13
- data/lib/rubocop/cop/rspec/not_to_not.rb +5 -6
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/pending.rb +1 -1
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +32 -69
- data/lib/rubocop/cop/rspec/rails/http_status.rb +7 -9
- data/lib/rubocop/cop/rspec/receive_counts.rb +15 -17
- data/lib/rubocop/cop/rspec/receive_never.rb +12 -12
- data/lib/rubocop/cop/rspec/repeated_description.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example.rb +2 -2
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +12 -2
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +1 -1
- data/lib/rubocop/cop/rspec/return_from_stub.rb +12 -22
- data/lib/rubocop/cop/rspec/scattered_let.rb +12 -2
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +8 -21
- data/lib/rubocop/cop/rspec/shared_examples.rb +7 -9
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +15 -18
- data/lib/rubocop/cop/rspec/subject_stub.rb +25 -53
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +1 -1
- data/lib/rubocop/cop/rspec/variable_definition.rb +56 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +66 -0
- data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -1
- data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/yield.rb +14 -11
- data/lib/rubocop/cop/rspec_cops.rb +6 -1
- data/lib/rubocop/rspec/corrector/move_node.rb +54 -0
- data/lib/rubocop/rspec/description_extractor.rb +2 -6
- data/lib/rubocop/rspec/{blank_line_separation.rb → empty_line_separation.rb} +13 -10
- data/lib/rubocop/rspec/example_group.rb +21 -49
- data/lib/rubocop/rspec/factory_bot.rb +7 -1
- data/lib/rubocop/rspec/language.rb +13 -3
- data/lib/rubocop/rspec/language/node_pattern.rb +11 -2
- data/lib/rubocop/rspec/top_level_describe.rb +2 -2
- data/lib/rubocop/rspec/top_level_group.rb +55 -0
- data/lib/rubocop/rspec/variable.rb +16 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- metadata +36 -13
- data/lib/rubocop/rspec/util.rb +0 -19
data/lib/rubocop-rspec.rb
CHANGED
@@ -11,18 +11,21 @@ require_relative 'rubocop/rspec/inject'
|
|
11
11
|
require_relative 'rubocop/rspec/node'
|
12
12
|
require_relative 'rubocop/rspec/top_level_describe'
|
13
13
|
require_relative 'rubocop/rspec/wording'
|
14
|
-
require_relative 'rubocop/rspec/util'
|
15
14
|
require_relative 'rubocop/rspec/language'
|
16
15
|
require_relative 'rubocop/rspec/language/node_pattern'
|
16
|
+
require_relative 'rubocop/rspec/top_level_group'
|
17
17
|
require_relative 'rubocop/rspec/concept'
|
18
18
|
require_relative 'rubocop/rspec/example_group'
|
19
19
|
require_relative 'rubocop/rspec/example'
|
20
20
|
require_relative 'rubocop/rspec/hook'
|
21
|
+
require_relative 'rubocop/rspec/variable'
|
22
|
+
require_relative 'rubocop/cop/rspec/base'
|
21
23
|
require_relative 'rubocop/cop/rspec/cop'
|
22
24
|
require_relative 'rubocop/rspec/align_let_brace'
|
23
25
|
require_relative 'rubocop/rspec/factory_bot'
|
24
26
|
require_relative 'rubocop/rspec/final_end_location'
|
25
|
-
require_relative 'rubocop/rspec/
|
27
|
+
require_relative 'rubocop/rspec/empty_line_separation'
|
28
|
+
require_relative 'rubocop/rspec/corrector/move_node'
|
26
29
|
|
27
30
|
RuboCop::RSpec::Inject.defaults!
|
28
31
|
|
@@ -17,36 +17,29 @@ module RuboCop
|
|
17
17
|
# let(:baz) { bar }
|
18
18
|
# let(:a) { b }
|
19
19
|
#
|
20
|
-
class AlignLeftLetBrace <
|
20
|
+
class AlignLeftLetBrace < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
|
21
23
|
MSG = 'Align left let brace'
|
22
24
|
|
23
25
|
def self.autocorrect_incompatible_with
|
24
26
|
[Layout::ExtraSpacing]
|
25
27
|
end
|
26
28
|
|
27
|
-
def
|
29
|
+
def on_new_investigation
|
28
30
|
return if processed_source.blank?
|
29
31
|
|
30
|
-
token_aligner
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
32
|
+
token_aligner =
|
33
|
+
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin)
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
token_aligner.offending_tokens.each do |let|
|
36
|
+
add_offense(let.loc.begin) do |corrector|
|
37
|
+
corrector.insert_before(
|
38
|
+
let.loc.begin, token_aligner.indent_for(let)
|
39
|
+
)
|
40
|
+
end
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def token_aligner
|
47
|
-
@token_aligner ||=
|
48
|
-
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin)
|
49
|
-
end
|
50
43
|
end
|
51
44
|
end
|
52
45
|
end
|
@@ -17,36 +17,29 @@ module RuboCop
|
|
17
17
|
# let(:baz) { bar }
|
18
18
|
# let(:a) { b }
|
19
19
|
#
|
20
|
-
class AlignRightLetBrace <
|
20
|
+
class AlignRightLetBrace < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
|
21
23
|
MSG = 'Align right let brace'
|
22
24
|
|
23
25
|
def self.autocorrect_incompatible_with
|
24
26
|
[Layout::ExtraSpacing]
|
25
27
|
end
|
26
28
|
|
27
|
-
def
|
29
|
+
def on_new_investigation
|
28
30
|
return if processed_source.blank?
|
29
31
|
|
30
|
-
token_aligner
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
32
|
+
token_aligner =
|
33
|
+
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end)
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
token_aligner.offending_tokens.each do |let|
|
36
|
+
add_offense(let.loc.end) do |corrector|
|
37
|
+
corrector.insert_before(
|
38
|
+
let.loc.end, token_aligner.indent_for(let)
|
39
|
+
)
|
40
|
+
end
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def token_aligner
|
47
|
-
@token_aligner ||=
|
48
|
-
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end)
|
49
|
-
end
|
50
43
|
end
|
51
44
|
end
|
52
45
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# @abstract parent class to RSpec cops
|
7
|
+
#
|
8
|
+
# The criteria for whether rubocop-rspec analyzes a certain ruby file
|
9
|
+
# is configured via `AllCops/RSpec`. For example, if you want to
|
10
|
+
# customize your project to scan all files within a `test/` directory
|
11
|
+
# then you could add this to your configuration:
|
12
|
+
#
|
13
|
+
# @example configuring analyzed paths
|
14
|
+
# # .rubocop.yml
|
15
|
+
# # AllCops:
|
16
|
+
# # RSpec:
|
17
|
+
# # Patterns:
|
18
|
+
# # - '_test.rb$'
|
19
|
+
# # - '(?:^|/)test/'
|
20
|
+
class Base < ::RuboCop::Cop::Base
|
21
|
+
include RuboCop::RSpec::Language
|
22
|
+
include RuboCop::RSpec::Language::NodePattern
|
23
|
+
|
24
|
+
DEFAULT_CONFIGURATION =
|
25
|
+
RuboCop::RSpec::CONFIG.fetch('AllCops').fetch('RSpec')
|
26
|
+
|
27
|
+
DEFAULT_PATTERN_RE = Regexp.union(
|
28
|
+
DEFAULT_CONFIGURATION.fetch('Patterns')
|
29
|
+
.map(&Regexp.public_method(:new))
|
30
|
+
)
|
31
|
+
|
32
|
+
# Invoke the original inherited hook so our cops are recognized
|
33
|
+
def self.inherited(subclass) # rubocop:disable Lint/MissingSuper
|
34
|
+
RuboCop::Cop::Base.inherited(subclass)
|
35
|
+
end
|
36
|
+
|
37
|
+
def relevant_file?(file)
|
38
|
+
relevant_rubocop_rspec_file?(file) && super
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def relevant_rubocop_rspec_file?(file)
|
44
|
+
rspec_pattern.match?(file)
|
45
|
+
end
|
46
|
+
|
47
|
+
def rspec_pattern
|
48
|
+
if rspec_pattern_config?
|
49
|
+
Regexp.union(rspec_pattern_config.map(&Regexp.public_method(:new)))
|
50
|
+
else
|
51
|
+
DEFAULT_PATTERN_RE
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def all_cops_config
|
56
|
+
config
|
57
|
+
.for_all_cops
|
58
|
+
end
|
59
|
+
|
60
|
+
def rspec_pattern_config?
|
61
|
+
return unless all_cops_config.key?('RSpec')
|
62
|
+
|
63
|
+
all_cops_config.fetch('RSpec').key?('Patterns')
|
64
|
+
end
|
65
|
+
|
66
|
+
def rspec_pattern_config
|
67
|
+
all_cops_config
|
68
|
+
.fetch('RSpec', DEFAULT_CONFIGURATION)
|
69
|
+
.fetch('Patterns')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/rubocop/cop/rspec/be.rb
CHANGED
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
# expect(foo).to be 1.0
|
20
20
|
# expect(foo).to be(true)
|
21
21
|
#
|
22
|
-
class Be <
|
22
|
+
class Be < Base
|
23
23
|
MSG = 'Don\'t use `be` without an argument.'
|
24
24
|
|
25
25
|
def_node_matcher :be_without_args, <<-PATTERN
|
@@ -28,7 +28,7 @@ module RuboCop
|
|
28
28
|
|
29
29
|
def on_send(node)
|
30
30
|
be_without_args(node) do |matcher|
|
31
|
-
add_offense(matcher
|
31
|
+
add_offense(matcher.loc.selector)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -35,7 +35,9 @@ module RuboCop
|
|
35
35
|
# necessarily the same type as `b` since the `#==` operator can
|
36
36
|
# coerce objects for comparison.
|
37
37
|
#
|
38
|
-
class BeEql <
|
38
|
+
class BeEql < Base
|
39
|
+
extend AutoCorrector
|
40
|
+
|
39
41
|
MSG = 'Prefer `be` over `eql`.'
|
40
42
|
|
41
43
|
def_node_matcher :eql_type_with_identity, <<-PATTERN
|
@@ -44,13 +46,11 @@ module RuboCop
|
|
44
46
|
|
45
47
|
def on_send(node)
|
46
48
|
eql_type_with_identity(node) do |eql|
|
47
|
-
add_offense(eql
|
49
|
+
add_offense(eql.loc.selector) do |corrector|
|
50
|
+
corrector.replace(eql.loc.selector, 'be')
|
51
|
+
end
|
48
52
|
end
|
49
53
|
end
|
50
|
-
|
51
|
-
def autocorrect(node)
|
52
|
-
->(corrector) { corrector.replace(node.loc.selector, 'be') }
|
53
|
-
end
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
@@ -23,7 +23,7 @@ module RuboCop
|
|
23
23
|
# before(:each) { Widget.create }
|
24
24
|
# after(:each) { Widget.delete_all }
|
25
25
|
# end
|
26
|
-
class BeforeAfterAll <
|
26
|
+
class BeforeAfterAll < Base
|
27
27
|
MSG = 'Beware of using `%<hook>s` as it may cause state to leak '\
|
28
28
|
'between tests. If you are using `rspec-rails`, and '\
|
29
29
|
'`use_transactional_fixtures` is enabled, then records created '\
|
@@ -23,7 +23,9 @@ module RuboCop
|
|
23
23
|
# expect(page).to have_current_path("/callback")
|
24
24
|
# expect(page).to have_current_path(/widgets/)
|
25
25
|
#
|
26
|
-
class CurrentPathExpectation <
|
26
|
+
class CurrentPathExpectation < Base
|
27
|
+
extend AutoCorrector
|
28
|
+
|
27
29
|
MSG = 'Do not set an RSpec expectation on `current_path` in ' \
|
28
30
|
'Capybara feature specs - instead, use the ' \
|
29
31
|
'`have_current_path` matcher on `page`'
|
@@ -47,30 +49,30 @@ module RuboCop
|
|
47
49
|
|
48
50
|
def on_send(node)
|
49
51
|
expectation_set_on_current_path(node) do
|
50
|
-
add_offense(node
|
52
|
+
add_offense(node.loc.selector) do |corrector|
|
53
|
+
next unless node.chained?
|
54
|
+
|
55
|
+
autocorrect(corrector, node)
|
56
|
+
end
|
51
57
|
end
|
52
58
|
end
|
53
59
|
|
54
|
-
|
55
|
-
lambda do |corrector|
|
56
|
-
return unless node.chained?
|
60
|
+
private
|
57
61
|
|
58
|
-
|
59
|
-
|
60
|
-
|
62
|
+
def autocorrect(corrector, node)
|
63
|
+
as_is_matcher(node.parent) do |to_sym, matcher_node|
|
64
|
+
rewrite_expectation(corrector, node, to_sym, matcher_node)
|
65
|
+
end
|
61
66
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
67
|
+
regexp_str_matcher(node.parent) do |to_sym, matcher_node, regexp|
|
68
|
+
rewrite_expectation(corrector, node, to_sym, matcher_node)
|
69
|
+
convert_regexp_str_to_literal(corrector, matcher_node, regexp)
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
69
|
-
private
|
70
|
-
|
71
73
|
def rewrite_expectation(corrector, node, to_symbol, matcher_node)
|
72
74
|
current_path_node = node.first_argument
|
73
|
-
corrector.replace(current_path_node
|
75
|
+
corrector.replace(current_path_node, 'page')
|
74
76
|
corrector.replace(node.parent.loc.selector, 'to')
|
75
77
|
matcher_method = if to_symbol == :to
|
76
78
|
'have_current_path'
|
@@ -84,7 +86,7 @@ module RuboCop
|
|
84
86
|
def convert_regexp_str_to_literal(corrector, matcher_node, regexp_str)
|
85
87
|
str_node = matcher_node.first_argument
|
86
88
|
regexp_expr = Regexp.new(regexp_str).inspect
|
87
|
-
corrector.replace(str_node
|
89
|
+
corrector.replace(str_node, regexp_expr)
|
88
90
|
end
|
89
91
|
|
90
92
|
# `have_current_path` with no options will include the querystring
|
@@ -97,7 +99,7 @@ module RuboCop
|
|
97
99
|
return if %i[regexp str].include?(expectation_last_child.type)
|
98
100
|
|
99
101
|
corrector.insert_after(
|
100
|
-
expectation_last_child
|
102
|
+
expectation_last_child,
|
101
103
|
', ignore_query: true'
|
102
104
|
)
|
103
105
|
end
|
@@ -40,7 +40,9 @@ module RuboCop
|
|
40
40
|
# # ...
|
41
41
|
# end
|
42
42
|
# end
|
43
|
-
class FeatureMethods <
|
43
|
+
class FeatureMethods < Base
|
44
|
+
extend AutoCorrector
|
45
|
+
|
44
46
|
MSG = 'Use `%<replacement>s` instead of `%<method>s`.'
|
45
47
|
|
46
48
|
# https://git.io/v7Kwr
|
@@ -53,15 +55,18 @@ module RuboCop
|
|
53
55
|
feature: :describe
|
54
56
|
}.freeze
|
55
57
|
|
58
|
+
def_node_matcher :capybara_speak,
|
59
|
+
SelectorSet.new(MAP.keys).node_pattern_union
|
60
|
+
|
56
61
|
def_node_matcher :spec?, <<-PATTERN
|
57
62
|
(block
|
58
|
-
(send #
|
63
|
+
(send #rspec? {:describe :feature} ...)
|
59
64
|
...)
|
60
65
|
PATTERN
|
61
66
|
|
62
67
|
def_node_matcher :feature_method, <<-PATTERN
|
63
68
|
(block
|
64
|
-
$(send #
|
69
|
+
$(send #rspec? $#capybara_speak ...)
|
65
70
|
...)
|
66
71
|
PATTERN
|
67
72
|
|
@@ -71,18 +76,15 @@ module RuboCop
|
|
71
76
|
feature_method(node) do |send_node, match|
|
72
77
|
next if enabled?(match)
|
73
78
|
|
74
|
-
add_offense(
|
75
|
-
send_node,
|
76
|
-
|
77
|
-
message: format(MSG, method: match, replacement: MAP[match])
|
78
|
-
)
|
79
|
+
add_offense(send_node.loc.selector) do |corrector|
|
80
|
+
corrector.replace(send_node.loc.selector, MAP[match].to_s)
|
81
|
+
end
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
end
|
85
|
+
def message(range)
|
86
|
+
name = range.source.to_sym
|
87
|
+
format(MSG, method: name, replacement: MAP[name])
|
86
88
|
end
|
87
89
|
|
88
90
|
private
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
module Capybara
|
7
|
+
# Checks for boolean visibility in capybara finders.
|
8
|
+
#
|
9
|
+
# Capybara lets you find elements that match a certain visibility using
|
10
|
+
# the `:visible` option. `:visible` accepts both boolean and symbols as
|
11
|
+
# values, however using booleans can have unwanted effects. `visible:
|
12
|
+
# false` does not find just invisible elements, but both visible and
|
13
|
+
# invisible elements. For expressiveness and clarity, use one of the
|
14
|
+
# symbol values, `:all`, `:hidden` or `:visible`.
|
15
|
+
# (https://www.rubydoc.info/gems/capybara/Capybara%2FNode%2FFinders:all)
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# expect(page).to have_selector('.foo', visible: false)
|
21
|
+
# expect(page).to have_css('.foo', visible: true)
|
22
|
+
# expect(page).to have_link('my link', visible: false)
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# expect(page).to have_selector('.foo', visible: :visible)
|
26
|
+
# expect(page).to have_css('.foo', visible: :all)
|
27
|
+
# expect(page).to have_link('my link', visible: :hidden)
|
28
|
+
#
|
29
|
+
class VisibilityMatcher < Base
|
30
|
+
MSG_FALSE = 'Use `:all` or `:hidden` instead of `false`.'
|
31
|
+
MSG_TRUE = 'Use `:visible` instead of `true`.'
|
32
|
+
CAPYBARA_MATCHER_METHODS = %i[
|
33
|
+
have_selector
|
34
|
+
have_css
|
35
|
+
have_xpath
|
36
|
+
have_link
|
37
|
+
have_button
|
38
|
+
have_field
|
39
|
+
have_select
|
40
|
+
have_table
|
41
|
+
have_checked_field
|
42
|
+
have_unchecked_field
|
43
|
+
have_text
|
44
|
+
have_content
|
45
|
+
].freeze
|
46
|
+
|
47
|
+
def_node_matcher :visible_true?, <<~PATTERN
|
48
|
+
(send nil? #capybara_matcher? ... (hash <$(pair (sym :visible) true) ...>))
|
49
|
+
PATTERN
|
50
|
+
|
51
|
+
def_node_matcher :visible_false?, <<~PATTERN
|
52
|
+
(send nil? #capybara_matcher? ... (hash <$(pair (sym :visible) false) ...>))
|
53
|
+
PATTERN
|
54
|
+
|
55
|
+
def on_send(node)
|
56
|
+
visible_false?(node) { |arg| add_offense(arg, message: MSG_FALSE) }
|
57
|
+
visible_true?(node) { |arg| add_offense(arg, message: MSG_TRUE) }
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def capybara_matcher?(method_name)
|
63
|
+
CAPYBARA_MATCHER_METHODS.include? method_name
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|