rubocop-rspec 1.7.0 → 3.0.2
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 +5 -5
- data/CHANGELOG.md +955 -79
- data/CODE_OF_CONDUCT.md +17 -0
- data/MIT-LICENSE.md +1 -2
- data/README.md +35 -35
- data/config/default.yml +940 -52
- data/config/obsoletion.yml +30 -0
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +49 -0
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +49 -0
- data/lib/rubocop/cop/rspec/any_instance.rb +10 -13
- data/lib/rubocop/cop/rspec/around_block.rb +97 -0
- data/lib/rubocop/cop/rspec/base.rb +26 -0
- data/lib/rubocop/cop/rspec/be.rb +39 -0
- data/lib/rubocop/cop/rspec/be_empty.rb +45 -0
- data/lib/rubocop/cop/rspec/be_eq.rb +47 -0
- data/lib/rubocop/cop/rspec/be_eql.rb +18 -15
- data/lib/rubocop/cop/rspec/be_nil.rb +74 -0
- data/lib/rubocop/cop/rspec/before_after_all.rb +45 -0
- data/lib/rubocop/cop/rspec/change_by_zero.rb +184 -0
- data/lib/rubocop/cop/rspec/class_check.rb +101 -0
- data/lib/rubocop/cop/rspec/contain_exactly.rb +56 -0
- data/lib/rubocop/cop/rspec/context_method.rb +57 -0
- data/lib/rubocop/cop/rspec/context_wording.rb +117 -0
- data/lib/rubocop/cop/rspec/describe_class.rb +52 -21
- data/lib/rubocop/cop/rspec/describe_method.rb +26 -11
- data/lib/rubocop/cop/rspec/describe_symbol.rb +37 -0
- data/lib/rubocop/cop/rspec/described_class.rb +181 -34
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +38 -0
- data/lib/rubocop/cop/rspec/dialect.rb +84 -0
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +58 -0
- data/lib/rubocop/cop/rspec/empty_example_group.rb +134 -47
- data/lib/rubocop/cop/rspec/empty_hook.rb +49 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +82 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +42 -0
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +40 -0
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +82 -0
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +36 -0
- data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
- data/lib/rubocop/cop/rspec/eq.rb +47 -0
- data/lib/rubocop/cop/rspec/example_length.rb +38 -20
- data/lib/rubocop/cop/rspec/example_without_description.rb +98 -0
- data/lib/rubocop/cop/rspec/example_wording.rb +117 -27
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +110 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +46 -20
- data/lib/rubocop/cop/rspec/expect_change.rb +86 -0
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +50 -0
- data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
- data/lib/rubocop/cop/rspec/expect_output.rb +50 -0
- data/lib/rubocop/cop/rspec/focus.rb +79 -25
- data/lib/rubocop/cop/rspec/hook_argument.rb +48 -36
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +81 -0
- data/lib/rubocop/cop/rspec/identical_equality_assertion.rb +37 -0
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +68 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +100 -0
- data/lib/rubocop/cop/rspec/implicit_subject.rb +167 -0
- data/lib/rubocop/cop/rspec/indexed_let.rb +112 -0
- data/lib/rubocop/cop/rspec/instance_spy.rb +74 -0
- data/lib/rubocop/cop/rspec/instance_variable.rb +28 -14
- data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +49 -0
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +74 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +57 -29
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +127 -0
- data/lib/rubocop/cop/rspec/let_before_examples.rb +101 -0
- data/lib/rubocop/cop/rspec/let_setup.rb +32 -16
- data/lib/rubocop/cop/rspec/match_array.rb +59 -0
- data/lib/rubocop/cop/rspec/message_chain.rb +10 -15
- data/lib/rubocop/cop/rspec/message_expectation.rb +12 -9
- data/lib/rubocop/cop/rspec/message_spies.rb +88 -0
- data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +35 -0
- data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/comments_help.rb +38 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +59 -0
- data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
- data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
- data/lib/rubocop/cop/rspec/mixin/inside_example_group.rb +29 -0
- data/lib/rubocop/cop/rspec/mixin/location_help.rb +37 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +63 -0
- data/lib/rubocop/cop/rspec/mixin/namespace.rb +23 -0
- data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +39 -0
- data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/variable.rb +21 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +14 -12
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +86 -26
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +146 -0
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +97 -0
- data/lib/rubocop/cop/rspec/named_subject.rb +107 -27
- data/lib/rubocop/cop/rspec/nested_groups.rb +84 -47
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +102 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +30 -27
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +74 -0
- data/lib/rubocop/cop/rspec/pending.rb +80 -0
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +159 -0
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +341 -0
- data/lib/rubocop/cop/rspec/receive_counts.rb +89 -0
- data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
- data/lib/rubocop/cop/rspec/receive_never.rb +41 -0
- data/lib/rubocop/cop/rspec/redundant_around.rb +65 -0
- data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
- data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
- data/lib/rubocop/cop/rspec/repeated_description.rb +98 -0
- data/lib/rubocop/cop/rspec/repeated_example.rb +53 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +100 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +96 -0
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +105 -0
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +169 -0
- data/lib/rubocop/cop/rspec/scattered_let.rb +59 -0
- data/lib/rubocop/cop/rspec/scattered_setup.rb +92 -0
- data/lib/rubocop/cop/rspec/shared_context.rb +107 -0
- data/lib/rubocop/cop/rspec/shared_examples.rb +125 -0
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +93 -0
- data/lib/rubocop/cop/rspec/skip_block_inside_example.rb +46 -0
- data/lib/rubocop/cop/rspec/sort_metadata.rb +71 -0
- data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
- data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +176 -0
- data/lib/rubocop/cop/rspec/subject_declaration.rb +46 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +93 -74
- data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +67 -0
- data/lib/rubocop/cop/rspec/variable_definition.rb +77 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +68 -0
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +111 -0
- data/lib/rubocop/cop/rspec/verified_doubles.rb +28 -14
- data/lib/rubocop/cop/rspec/void_expect.rb +60 -0
- data/lib/rubocop/cop/rspec/yield.rb +82 -0
- data/lib/rubocop/cop/rspec_cops.rb +112 -0
- data/lib/rubocop/rspec/align_let_brace.rb +63 -0
- data/lib/rubocop/rspec/concept.rb +33 -0
- data/lib/rubocop/rspec/config_formatter.rb +27 -4
- data/lib/rubocop/rspec/cop/generator.rb +25 -0
- data/lib/rubocop/rspec/corrector/move_node.rb +51 -0
- data/lib/rubocop/rspec/description_extractor.rb +60 -18
- data/lib/rubocop/rspec/example.rb +37 -0
- data/lib/rubocop/rspec/example_group.rb +67 -0
- data/lib/rubocop/rspec/hook.rb +79 -0
- data/lib/rubocop/rspec/inject.rb +3 -1
- data/lib/rubocop/rspec/language.rb +184 -41
- data/lib/rubocop/rspec/node.rb +19 -0
- data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +29 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +61 -19
- data/lib/rubocop/rspec.rb +6 -2
- data/lib/rubocop-rspec.rb +45 -34
- metadata +130 -195
- data/Gemfile +0 -13
- data/Rakefile +0 -48
- data/lib/rubocop/cop/rspec/file_path.rb +0 -83
- data/lib/rubocop/rspec/language/node_pattern.rb +0 -16
- data/lib/rubocop/rspec/spec_only.rb +0 -61
- data/lib/rubocop/rspec/top_level_describe.rb +0 -61
- data/lib/rubocop/rspec/util.rb +0 -19
- data/rubocop-rspec.gemspec +0 -42
- data/spec/expect_violation/expectation_spec.rb +0 -85
- data/spec/project/changelog_spec.rb +0 -81
- data/spec/project/default_config_spec.rb +0 -52
- data/spec/project/project_requires_spec.rb +0 -8
- data/spec/rubocop/cop/rspec/any_instance_spec.rb +0 -30
- data/spec/rubocop/cop/rspec/be_eql_spec.rb +0 -59
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +0 -113
- data/spec/rubocop/cop/rspec/describe_method_spec.rb +0 -32
- data/spec/rubocop/cop/rspec/described_class_spec.rb +0 -219
- data/spec/rubocop/cop/rspec/empty_example_group_spec.rb +0 -79
- data/spec/rubocop/cop/rspec/example_length_spec.rb +0 -117
- data/spec/rubocop/cop/rspec/example_wording_spec.rb +0 -82
- data/spec/rubocop/cop/rspec/expect_actual_spec.rb +0 -136
- data/spec/rubocop/cop/rspec/file_path_spec.rb +0 -236
- data/spec/rubocop/cop/rspec/focus_spec.rb +0 -130
- data/spec/rubocop/cop/rspec/hook_argument_spec.rb +0 -189
- data/spec/rubocop/cop/rspec/instance_variable_spec.rb +0 -75
- data/spec/rubocop/cop/rspec/leading_subject_spec.rb +0 -54
- data/spec/rubocop/cop/rspec/let_setup_spec.rb +0 -66
- data/spec/rubocop/cop/rspec/message_chain_spec.rb +0 -21
- data/spec/rubocop/cop/rspec/message_expectation_spec.rb +0 -63
- data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +0 -28
- data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +0 -84
- data/spec/rubocop/cop/rspec/named_subject_spec.rb +0 -62
- data/spec/rubocop/cop/rspec/nested_groups_spec.rb +0 -55
- data/spec/rubocop/cop/rspec/not_to_not_spec.rb +0 -57
- data/spec/rubocop/cop/rspec/subject_stub_spec.rb +0 -183
- data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +0 -71
- data/spec/rubocop/rspec/config_formatter_spec.rb +0 -48
- data/spec/rubocop/rspec/description_extractor_spec.rb +0 -35
- data/spec/rubocop/rspec/language/selector_set_spec.rb +0 -29
- data/spec/rubocop/rspec/spec_only_spec.rb +0 -97
- data/spec/rubocop/rspec/util/one_spec.rb +0 -21
- data/spec/rubocop/rspec/wording_spec.rb +0 -44
- data/spec/shared/rspec_only_cop_behavior.rb +0 -68
- data/spec/spec_helper.rb +0 -41
- data/spec/support/expect_violation.rb +0 -166
@@ -5,7 +5,8 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks for nested example groups.
|
7
7
|
#
|
8
|
-
# This cop is configurable using the `
|
8
|
+
# This cop is configurable using the `Max` option
|
9
|
+
# and supports `--auto-gen-config`.
|
9
10
|
#
|
10
11
|
# @example
|
11
12
|
# # bad
|
@@ -21,7 +22,7 @@ module RuboCop
|
|
21
22
|
# let(:user_attributes) do
|
22
23
|
# {
|
23
24
|
# name: 'John',
|
24
|
-
# age: 22
|
25
|
+
# age: 22,
|
25
26
|
# role: role
|
26
27
|
# }
|
27
28
|
# end
|
@@ -35,7 +36,7 @@ module RuboCop
|
|
35
36
|
# end
|
36
37
|
# end
|
37
38
|
#
|
38
|
-
# #
|
39
|
+
# # good
|
39
40
|
# context 'using some feature as an admin' do
|
40
41
|
# let(:some) { :various }
|
41
42
|
# let(:feature) { :setup }
|
@@ -43,7 +44,7 @@ module RuboCop
|
|
43
44
|
# let(:user) do
|
44
45
|
# UserCreate.call(
|
45
46
|
# name: 'John',
|
46
|
-
# age: 22
|
47
|
+
# age: 22,
|
47
48
|
# role: 'admin'
|
48
49
|
# )
|
49
50
|
# end
|
@@ -52,72 +53,108 @@ module RuboCop
|
|
52
53
|
# it 'yada yada'
|
53
54
|
# end
|
54
55
|
#
|
55
|
-
# @example
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
# let(:some) { :various }
|
63
|
-
# let(:feature) { :setup }
|
64
|
-
#
|
65
|
-
# context 'when user is signed in' do
|
66
|
-
# let(:user) do
|
67
|
-
# UserCreate.call(user_attributes)
|
56
|
+
# @example `Max: 3` (default)
|
57
|
+
# # bad
|
58
|
+
# describe Foo do
|
59
|
+
# context 'foo' do
|
60
|
+
# context 'bar' do
|
61
|
+
# context 'baz' do # flagged by rubocop
|
62
|
+
# end
|
68
63
|
# end
|
64
|
+
# end
|
65
|
+
# end
|
69
66
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
67
|
+
# @example `Max: 2`
|
68
|
+
# # bad
|
69
|
+
# describe Foo do
|
70
|
+
# context 'foo' do
|
71
|
+
# context 'bar' do # flagged by rubocop
|
72
|
+
# context 'baz' do # flagged by rubocop
|
73
|
+
# end
|
76
74
|
# end
|
75
|
+
# end
|
76
|
+
# end
|
77
77
|
#
|
78
|
-
#
|
79
|
-
#
|
78
|
+
# @example `AllowedGroups: [] (default)`
|
79
|
+
# describe Foo do # <-- nested groups 1
|
80
|
+
# context 'foo' do # <-- nested groups 2
|
81
|
+
# context 'bar' do # <-- nested groups 3
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
# end
|
80
85
|
#
|
81
|
-
#
|
82
|
-
#
|
86
|
+
# @example `AllowedGroups: [path]`
|
87
|
+
# describe Foo do # <-- nested groups 1
|
88
|
+
# path '/foo' do # <-- nested groups 1 (not counted)
|
89
|
+
# context 'bar' do # <-- nested groups 2
|
83
90
|
# end
|
84
91
|
# end
|
85
92
|
# end
|
86
93
|
#
|
87
|
-
class NestedGroups <
|
88
|
-
include
|
89
|
-
|
90
|
-
RuboCop::RSpec::Language
|
94
|
+
class NestedGroups < Base
|
95
|
+
include ConfigurableMax
|
96
|
+
include TopLevelGroup
|
91
97
|
|
92
|
-
MSG = 'Maximum example group nesting exceeded'
|
98
|
+
MSG = 'Maximum example group nesting exceeded [%<total>d/%<max>d].'
|
93
99
|
|
94
|
-
|
95
|
-
(block (send nil {#{ExampleGroups::ALL.to_node_pattern}} ...) (args) ...)
|
96
|
-
PATTERN
|
100
|
+
DEPRECATED_MAX_KEY = 'MaxNesting'
|
97
101
|
|
98
|
-
|
99
|
-
|
100
|
-
|
102
|
+
DEPRECATION_WARNING =
|
103
|
+
"Configuration key `#{DEPRECATED_MAX_KEY}` for #{cop_name} is " \
|
104
|
+
'deprecated in favor of `Max`. Please use that instead.'
|
101
105
|
|
102
|
-
|
103
|
-
|
106
|
+
def on_top_level_group(node)
|
107
|
+
find_nested_example_groups(node) do |example_group, nesting|
|
108
|
+
self.max = nesting
|
109
|
+
add_offense(
|
110
|
+
example_group.send_node,
|
111
|
+
message: message(nesting)
|
112
|
+
)
|
104
113
|
end
|
105
114
|
end
|
106
115
|
|
107
116
|
private
|
108
117
|
|
109
|
-
def
|
110
|
-
|
111
|
-
|
118
|
+
def find_nested_example_groups(node, nesting: 1, &block)
|
119
|
+
example_group = example_group?(node)
|
120
|
+
yield node, nesting if example_group && nesting > max_nesting
|
121
|
+
|
122
|
+
next_nesting = if count_up_nesting?(node, example_group)
|
123
|
+
nesting + 1
|
124
|
+
else
|
125
|
+
nesting
|
126
|
+
end
|
112
127
|
|
113
|
-
|
114
|
-
|
115
|
-
end
|
128
|
+
node.each_child_node(:block, :begin) do |child|
|
129
|
+
find_nested_example_groups(child, nesting: next_nesting, &block)
|
116
130
|
end
|
117
131
|
end
|
118
132
|
|
133
|
+
def count_up_nesting?(node, example_group)
|
134
|
+
example_group &&
|
135
|
+
(node.block_type? &&
|
136
|
+
!allowed_groups.include?(node.method_name.to_s))
|
137
|
+
end
|
138
|
+
|
139
|
+
def message(nesting)
|
140
|
+
format(MSG, total: nesting, max: max_nesting)
|
141
|
+
end
|
142
|
+
|
119
143
|
def max_nesting
|
120
|
-
Integer(
|
144
|
+
@max_nesting ||= Integer(max_nesting_config)
|
145
|
+
end
|
146
|
+
|
147
|
+
def max_nesting_config
|
148
|
+
if cop_config.key?(DEPRECATED_MAX_KEY)
|
149
|
+
warn DEPRECATION_WARNING
|
150
|
+
cop_config.fetch(DEPRECATED_MAX_KEY)
|
151
|
+
else
|
152
|
+
cop_config.fetch('Max', 3)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def allowed_groups
|
157
|
+
@allowed_groups ||= cop_config.fetch('AllowedGroups', [])
|
121
158
|
end
|
122
159
|
end
|
123
160
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks if an example contains any expectation.
|
7
|
+
#
|
8
|
+
# All RSpec's example and expectation methods are covered by default.
|
9
|
+
# If you are using your own custom methods,
|
10
|
+
# add the following configuration:
|
11
|
+
#
|
12
|
+
# RSpec:
|
13
|
+
# Language:
|
14
|
+
# Examples:
|
15
|
+
# Regular:
|
16
|
+
# - custom_it
|
17
|
+
# Expectations:
|
18
|
+
# - custom_expect
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# # bad
|
22
|
+
# it do
|
23
|
+
# a?
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# it do
|
28
|
+
# expect(a?).to be(true)
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# This cop can be customized with an allowed expectation methods pattern
|
32
|
+
# with an `AllowedPatterns` option. ^expect_ and ^assert_ are allowed
|
33
|
+
# by default.
|
34
|
+
#
|
35
|
+
# @example `AllowedPatterns` configuration
|
36
|
+
#
|
37
|
+
# # .rubocop.yml
|
38
|
+
# # RSpec/NoExpectationExample:
|
39
|
+
# # AllowedPatterns:
|
40
|
+
# # - ^expect_
|
41
|
+
# # - ^assert_
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# # bad
|
45
|
+
# it do
|
46
|
+
# not_expect_something
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# # good
|
50
|
+
# it do
|
51
|
+
# expect_something
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# it do
|
55
|
+
# assert_something
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
class NoExpectationExample < Base
|
59
|
+
include AllowedPattern
|
60
|
+
include SkipOrPending
|
61
|
+
|
62
|
+
MSG = 'No expectation found in this example.'
|
63
|
+
|
64
|
+
# @!method regular_or_focused_example?(node)
|
65
|
+
# @param [RuboCop::AST::Node] node
|
66
|
+
# @return [Boolean]
|
67
|
+
def_node_matcher :regular_or_focused_example?, <<~PATTERN
|
68
|
+
({block numblock} (send nil? {#Examples.regular #Examples.focused} ...) ...)
|
69
|
+
PATTERN
|
70
|
+
|
71
|
+
# @!method includes_expectation?(node)
|
72
|
+
# @param [RuboCop::AST::Node] node
|
73
|
+
# @return [Boolean]
|
74
|
+
def_node_search :includes_expectation?, <<~PATTERN
|
75
|
+
{
|
76
|
+
(send nil? #Expectations.all ...)
|
77
|
+
(send nil? `#matches_allowed_pattern? ...)
|
78
|
+
}
|
79
|
+
PATTERN
|
80
|
+
|
81
|
+
# @!method includes_skip_example?(node)
|
82
|
+
# @param [RuboCop::AST::Node] node
|
83
|
+
# @return [Boolean]
|
84
|
+
def_node_search :includes_skip_example?, <<~PATTERN
|
85
|
+
(send nil? {:pending :skip} ...)
|
86
|
+
PATTERN
|
87
|
+
|
88
|
+
# @param [RuboCop::AST::BlockNode] node
|
89
|
+
def on_block(node)
|
90
|
+
return unless regular_or_focused_example?(node)
|
91
|
+
return if includes_expectation?(node)
|
92
|
+
return if includes_skip_example?(node)
|
93
|
+
return if skipped_in_metadata?(node.send_node)
|
94
|
+
|
95
|
+
add_offense(node)
|
96
|
+
end
|
97
|
+
|
98
|
+
alias on_numblock on_block
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RuboCop
|
2
4
|
module Cop
|
3
5
|
module RSpec
|
4
6
|
# Checks for consistent method usage for negating expectations.
|
5
7
|
#
|
6
|
-
# @example
|
8
|
+
# @example `EnforcedStyle: not_to` (default)
|
7
9
|
# # bad
|
8
10
|
# it '...' do
|
9
11
|
# expect(false).to_not be_true
|
@@ -13,39 +15,40 @@ module RuboCop
|
|
13
15
|
# it '...' do
|
14
16
|
# expect(false).not_to be_true
|
15
17
|
# end
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
#
|
19
|
+
# @example `EnforcedStyle: to_not`
|
20
|
+
# # bad
|
21
|
+
# it '...' do
|
22
|
+
# expect(false).not_to be_true
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# it '...' do
|
27
|
+
# expect(false).to_not be_true
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
class NotToNot < Base
|
31
|
+
extend AutoCorrector
|
32
|
+
include ConfigurableEnforcedStyle
|
19
33
|
|
20
|
-
MSG = 'Prefer
|
34
|
+
MSG = 'Prefer `%<replacement>s` over `%<original>s`.'
|
35
|
+
RESTRICT_ON_SEND = %i[not_to to_not].freeze
|
21
36
|
|
22
|
-
|
37
|
+
# @!method not_to_not_offense(node)
|
38
|
+
def_node_matcher :not_to_not_offense, '(send _ % ...)'
|
23
39
|
|
24
40
|
def on_send(node)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
return if style.equal?(method_name)
|
30
|
-
add_offense(node, :expression)
|
31
|
-
end
|
32
|
-
|
33
|
-
def message(node)
|
34
|
-
_receiver, method_name, *_args = *node
|
35
|
-
|
36
|
-
if method_name.equal?(:not_to)
|
37
|
-
format(MSG, 'to_not', 'not_to')
|
38
|
-
else
|
39
|
-
format(MSG, 'not_to', 'to_not')
|
41
|
+
not_to_not_offense(node, alternative_style) do
|
42
|
+
add_offense(node.loc.selector) do |corrector|
|
43
|
+
corrector.replace(node.loc.selector, style.to_s)
|
44
|
+
end
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
method_name.equal?(:not_to) ? 'to_not' : 'not_to')
|
48
|
-
end
|
48
|
+
private
|
49
|
+
|
50
|
+
def message(_node)
|
51
|
+
format(MSG, replacement: style, original: alternative_style)
|
49
52
|
end
|
50
53
|
end
|
51
54
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks if there is a let/subject that overwrites an existing one.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# let(:foo) { bar }
|
11
|
+
# let(:foo) { baz }
|
12
|
+
#
|
13
|
+
# subject(:foo) { bar }
|
14
|
+
# let(:foo) { baz }
|
15
|
+
#
|
16
|
+
# let(:foo) { bar }
|
17
|
+
# let!(:foo) { baz }
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# subject(:test) { something }
|
21
|
+
# let(:foo) { bar }
|
22
|
+
# let(:baz) { baz }
|
23
|
+
# let!(:other) { other }
|
24
|
+
#
|
25
|
+
class OverwritingSetup < Base
|
26
|
+
MSG = '`%<name>s` is already defined.'
|
27
|
+
|
28
|
+
# @!method setup?(node)
|
29
|
+
def_node_matcher :setup?, <<~PATTERN
|
30
|
+
(block (send nil? {#Helpers.all #Subjects.all} ...) ...)
|
31
|
+
PATTERN
|
32
|
+
|
33
|
+
# @!method first_argument_name(node)
|
34
|
+
def_node_matcher :first_argument_name, '(send _ _ ({str sym} $_))'
|
35
|
+
|
36
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
37
|
+
return unless example_group_with_body?(node)
|
38
|
+
|
39
|
+
find_duplicates(node.body) do |duplicate, name|
|
40
|
+
add_offense(
|
41
|
+
duplicate,
|
42
|
+
message: format(MSG, name: name)
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def find_duplicates(node)
|
50
|
+
setup_expressions = Set.new
|
51
|
+
node.each_child_node(:block) do |child|
|
52
|
+
next unless common_setup?(child)
|
53
|
+
|
54
|
+
name = if child.send_node.arguments?
|
55
|
+
first_argument_name(child.send_node).to_sym
|
56
|
+
else
|
57
|
+
:subject
|
58
|
+
end
|
59
|
+
|
60
|
+
yield child, name unless setup_expressions.add?(name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def common_setup?(node)
|
65
|
+
return false unless setup?(node)
|
66
|
+
|
67
|
+
# Search only for setup with basic_literal arguments (e.g. :sym, :str)
|
68
|
+
# or no arguments at all.
|
69
|
+
node.send_node.arguments.all?(&:basic_literal?)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for any pending or skipped examples.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# describe MyClass do
|
11
|
+
# it "should be true"
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# describe MyClass do
|
15
|
+
# it "should be true", skip: true do
|
16
|
+
# expect(1).to eq(2)
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# describe MyClass do
|
21
|
+
# it "should be true" do
|
22
|
+
# pending
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# describe MyClass do
|
27
|
+
# xit "should be true" do
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# # good
|
32
|
+
# describe MyClass do
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
class Pending < Base
|
36
|
+
include SkipOrPending
|
37
|
+
|
38
|
+
MSG = 'Pending spec found.'
|
39
|
+
|
40
|
+
# @!method skippable?(node)
|
41
|
+
def_node_matcher :skippable?, <<~PATTERN
|
42
|
+
{
|
43
|
+
(send #rspec? #ExampleGroups.regular ...)
|
44
|
+
#skippable_example?
|
45
|
+
}
|
46
|
+
PATTERN
|
47
|
+
|
48
|
+
# @!method skippable_example?(node)
|
49
|
+
def_node_matcher :skippable_example?, <<~PATTERN
|
50
|
+
(send nil? #Examples.regular ...)
|
51
|
+
PATTERN
|
52
|
+
|
53
|
+
# @!method pending_block?(node)
|
54
|
+
def_node_matcher :pending_block?, <<~PATTERN
|
55
|
+
{
|
56
|
+
(send #rspec? #ExampleGroups.skipped ...)
|
57
|
+
(send nil? {#Examples.skipped #Examples.pending} ...)
|
58
|
+
}
|
59
|
+
PATTERN
|
60
|
+
|
61
|
+
def on_send(node)
|
62
|
+
return unless pending_block?(node) || skipped?(node)
|
63
|
+
|
64
|
+
add_offense(node)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def skipped?(node)
|
70
|
+
(skippable?(node) && skipped_in_metadata?(node)) ||
|
71
|
+
skipped_regular_example_without_body?(node)
|
72
|
+
end
|
73
|
+
|
74
|
+
def skipped_regular_example_without_body?(node)
|
75
|
+
skippable_example?(node) && !node.block_node
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for pending or skipped examples without reason.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# pending 'does something' do
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# it 'does something', :pending do
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# it 'does something' do
|
19
|
+
# pending
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# xdescribe 'something' do
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# # bad
|
27
|
+
# skip 'does something' do
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# # bad
|
31
|
+
# it 'does something', :skip do
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# # bad
|
35
|
+
# it 'does something' do
|
36
|
+
# skip
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# # bad
|
40
|
+
# it 'does something'
|
41
|
+
#
|
42
|
+
# # good
|
43
|
+
# it 'does something' do
|
44
|
+
# pending 'reason'
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# # good
|
48
|
+
# it 'does something' do
|
49
|
+
# skip 'reason'
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# # good
|
53
|
+
# it 'does something', pending: 'reason' do
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# it 'does something', skip: 'reason' do
|
58
|
+
# end
|
59
|
+
class PendingWithoutReason < Base
|
60
|
+
MSG = 'Give the reason for pending or skip.'
|
61
|
+
|
62
|
+
# @!method skipped_in_example?(node)
|
63
|
+
def_node_matcher :skipped_in_example?, <<~PATTERN
|
64
|
+
{
|
65
|
+
(send nil? ${#Examples.skipped #Examples.pending})
|
66
|
+
(block (send nil? ${#Examples.skipped}) ...)
|
67
|
+
(numblock (send nil? ${#Examples.skipped}) ...)
|
68
|
+
}
|
69
|
+
PATTERN
|
70
|
+
|
71
|
+
# @!method skipped_by_example_method?(node)
|
72
|
+
def_node_matcher :skipped_by_example_method?, <<~PATTERN
|
73
|
+
(send nil? ${#Examples.skipped #Examples.pending})
|
74
|
+
PATTERN
|
75
|
+
|
76
|
+
# @!method skipped_by_example_method_with_block?(node)
|
77
|
+
def_node_matcher :skipped_by_example_method_with_block?, <<~PATTERN
|
78
|
+
({block numblock} (send nil? ${#Examples.skipped #Examples.pending} ...) ...)
|
79
|
+
PATTERN
|
80
|
+
|
81
|
+
# @!method metadata_without_reason?(node)
|
82
|
+
def_node_matcher :metadata_without_reason?, <<~PATTERN
|
83
|
+
(send #rspec?
|
84
|
+
{#ExampleGroups.all #Examples.all} ...
|
85
|
+
{
|
86
|
+
<(sym ${:pending :skip}) ...>
|
87
|
+
(hash <(pair (sym ${:pending :skip}) true) ...>)
|
88
|
+
}
|
89
|
+
)
|
90
|
+
PATTERN
|
91
|
+
|
92
|
+
# @!method skipped_by_example_group_method?(node)
|
93
|
+
def_node_matcher :skipped_by_example_group_method?, <<~PATTERN
|
94
|
+
(send #rspec? ${#ExampleGroups.skipped} ...)
|
95
|
+
PATTERN
|
96
|
+
|
97
|
+
# @!method pending_step_without_reason?(node)
|
98
|
+
def_node_matcher :pending_step_without_reason?, <<~PATTERN
|
99
|
+
(send nil? {:skip :pending})
|
100
|
+
PATTERN
|
101
|
+
|
102
|
+
def on_send(node)
|
103
|
+
on_pending_by_metadata(node)
|
104
|
+
return unless (parent = parent_node(node))
|
105
|
+
|
106
|
+
if spec_group?(parent) || block_node_example_group?(node)
|
107
|
+
on_skipped_by_example_method(node)
|
108
|
+
on_skipped_by_example_group_method(node)
|
109
|
+
elsif example?(parent)
|
110
|
+
on_skipped_by_in_example_method(node)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def parent_node(node)
|
117
|
+
node_or_block = node.block_node || node
|
118
|
+
return unless (parent = node_or_block.parent)
|
119
|
+
|
120
|
+
parent.begin_type? && parent.parent ? parent.parent : parent
|
121
|
+
end
|
122
|
+
|
123
|
+
def block_node_example_group?(node)
|
124
|
+
node.block_node &&
|
125
|
+
example_group?(node.block_node) &&
|
126
|
+
explicit_rspec?(node.receiver)
|
127
|
+
end
|
128
|
+
|
129
|
+
def on_skipped_by_in_example_method(node)
|
130
|
+
skipped_in_example?(node) do |pending|
|
131
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def on_pending_by_metadata(node)
|
136
|
+
metadata_without_reason?(node) do |pending|
|
137
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def on_skipped_by_example_method(node)
|
142
|
+
skipped_by_example_method?(node) do |pending|
|
143
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
144
|
+
end
|
145
|
+
|
146
|
+
skipped_by_example_method_with_block?(node.parent) do |pending|
|
147
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def on_skipped_by_example_group_method(node)
|
152
|
+
skipped_by_example_group_method?(node) do
|
153
|
+
add_offense(node, message: 'Give the reason for skip.')
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|