rubocop-rspec 1.8.0 → 1.9.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 +8 -0
- data/Gemfile +2 -1
- data/Rakefile +3 -1
- data/config/default.yml +16 -0
- data/lib/rubocop-rspec.rb +6 -1
- data/lib/rubocop/cop/rspec/any_instance.rb +0 -2
- data/lib/rubocop/cop/rspec/be_eql.rb +1 -2
- data/lib/rubocop/cop/rspec/cop.rb +66 -0
- data/lib/rubocop/cop/rspec/describe_class.rb +6 -1
- data/lib/rubocop/cop/rspec/describe_method.rb +1 -2
- data/lib/rubocop/cop/rspec/described_class.rb +3 -6
- data/lib/rubocop/cop/rspec/empty_example_group.rb +1 -11
- data/lib/rubocop/cop/rspec/example_length.rb +1 -1
- data/lib/rubocop/cop/rspec/example_wording.rb +0 -2
- data/lib/rubocop/cop/rspec/expect_actual.rb +0 -2
- data/lib/rubocop/cop/rspec/file_path.rb +1 -1
- data/lib/rubocop/cop/rspec/focus.rb +4 -9
- data/lib/rubocop/cop/rspec/hook_argument.rb +3 -5
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/instance_variable.rb +1 -5
- data/lib/rubocop/cop/rspec/leading_subject.rb +0 -2
- data/lib/rubocop/cop/rspec/let_setup.rb +1 -4
- data/lib/rubocop/cop/rspec/message_chain.rb +1 -8
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/message_spies.rb +79 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -2
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +2 -6
- data/lib/rubocop/cop/rspec/named_subject.rb +0 -2
- data/lib/rubocop/cop/rspec/nested_groups.rb +2 -6
- data/lib/rubocop/cop/rspec/not_to_not.rb +1 -2
- data/lib/rubocop/cop/rspec/repeated_description.rb +59 -0
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +48 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +1 -4
- data/lib/rubocop/cop/rspec/verified_doubles.rb +0 -2
- data/lib/rubocop/rspec.rb +1 -1
- data/lib/rubocop/rspec/description_extractor.rb +55 -18
- data/lib/rubocop/rspec/example.rb +56 -0
- data/lib/rubocop/rspec/example_group.rb +57 -0
- data/lib/rubocop/rspec/language.rb +28 -1
- data/lib/rubocop/rspec/language/node_pattern.rb +1 -3
- data/lib/rubocop/rspec/top_level_describe.rb +6 -10
- data/lib/rubocop/rspec/version.rb +1 -1
- data/spec/project/default_config_spec.rb +8 -5
- data/spec/project/project_requires_spec.rb +1 -1
- data/spec/rubocop/{rspec/spec_only_spec.rb → cop/rspec/cop_spec.rb} +2 -4
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +36 -0
- data/spec/rubocop/cop/rspec/described_class_spec.rb +2 -2
- data/spec/rubocop/cop/rspec/example_length_spec.rb +48 -60
- data/spec/rubocop/cop/rspec/implicit_expect_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/message_spies_spec.rb +93 -0
- data/spec/rubocop/cop/rspec/repeated_description_spec.rb +76 -0
- data/spec/rubocop/cop/rspec/single_argument_message_chain_spec.rb +75 -0
- data/spec/rubocop/rspec/description_extractor_spec.rb +46 -24
- data/spec/rubocop/rspec/example_group_spec.rb +44 -0
- data/spec/rubocop/rspec/example_spec.rb +62 -0
- data/spec/rubocop/rspec/language/selector_set_spec.rb +22 -2
- data/spec/spec_helper.rb +2 -9
- data/spec/support/expect_violation.rb +4 -2
- metadata +21 -8
- data/lib/rubocop/rspec/spec_only.rb +0 -61
- data/spec/shared/rspec_only_cop_behavior.rb +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d160e862b58dbfd9bcd2ae0966bd185d1ed13d25
|
4
|
+
data.tar.gz: 3b32f0c16a19b8f110e40d79f4a87d510e3c9226
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b429eb8553d36a1aec8613f57a4f3356518acb89ade8e41f96093dc6ba430b592b3a35899dcefe8df5833a1c0ceb7afa8d3bf1431ad554ffaeb057b2775df622
|
7
|
+
data.tar.gz: 4bc98868826de4ba820c107b5507beb1b57259d147199cec394054c5ac6887786ba1db1ce396bfcfe8ed345387b736b73b18c8b0e1bf0f3b3841f665e7f23064
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
## Master (unreleased)
|
4
4
|
|
5
|
+
## 1.9.0 (2016-12-29)
|
6
|
+
|
7
|
+
* Add `MessageSpies` cop for enforcing consistent style of either `expect(...).to have_received` or `expect(...).to receive`, intended as a replacement for the `MessageExpectation` cop. ([@bquorning][])
|
8
|
+
* Fix `DescribeClass` to not flag `describe` at the top of a block of shared examples. ([@clupprich][])
|
9
|
+
* Add `SingleArgumentMessageChain` cop for recommending use of `receive` instead of `receive_message_chain` where possible. ([@bquorning][])
|
10
|
+
* Add `RepeatedDescription` cop for detecting repeated example descriptions within example groups. ([@backus][])
|
11
|
+
|
5
12
|
## 1.8.0 (2016-10-27)
|
6
13
|
|
7
14
|
* Optionally ignore method names in the `describe` argument when running the `FilePath` cop. ([@bquorning][])
|
@@ -148,3 +155,4 @@
|
|
148
155
|
[@jaredmoody]: https://github.com/jaredmoody
|
149
156
|
[@baberthal]: https://github.com/baberthal
|
150
157
|
[@jeffreyc]: https://github.com/jeffreyc
|
158
|
+
[@clupprich]: https://github.com/clupprich
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -20,6 +20,8 @@ desc 'Run RSpec with code coverage'
|
|
20
20
|
task :coverage do
|
21
21
|
ENV['COVERAGE'] = 'true'
|
22
22
|
Rake::Task['spec'].execute
|
23
|
+
|
24
|
+
sh('codeclimate-test-reporter') if ENV['CI']
|
23
25
|
end
|
24
26
|
|
25
27
|
desc 'Run RuboCop over this gem'
|
@@ -42,4 +44,4 @@ task confirm_config: :build_config do
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
|
-
task default:
|
47
|
+
task default: %i(build_config coverage internal_investigation confirm_config)
|
data/config/default.yml
CHANGED
@@ -103,6 +103,14 @@ RSpec/MessageExpectation:
|
|
103
103
|
- allow
|
104
104
|
- expect
|
105
105
|
|
106
|
+
RSpec/MessageSpies:
|
107
|
+
Description: Checks that message expectations are set using spies.
|
108
|
+
Enabled: true
|
109
|
+
EnforcedStyle: have_received
|
110
|
+
SupportedStyles:
|
111
|
+
- have_received
|
112
|
+
- receive
|
113
|
+
|
106
114
|
RSpec/MultipleDescribes:
|
107
115
|
Description: Checks for multiple top level describes.
|
108
116
|
Enabled: true
|
@@ -129,6 +137,14 @@ RSpec/NotToNot:
|
|
129
137
|
- to_not
|
130
138
|
Enabled: true
|
131
139
|
|
140
|
+
RSpec/RepeatedDescription:
|
141
|
+
Enabled: true
|
142
|
+
Description: Check for repeated description strings in example groups.
|
143
|
+
|
144
|
+
RSpec/SingleArgumentMessageChain:
|
145
|
+
Description: Checks that chains of messages contain more than one element.
|
146
|
+
Enabled: true
|
147
|
+
|
132
148
|
RSpec/SubjectStub:
|
133
149
|
Description: Checks for stubbed test subjects.
|
134
150
|
Enabled: true
|
data/lib/rubocop-rspec.rb
CHANGED
@@ -11,7 +11,9 @@ require 'rubocop/rspec/wording'
|
|
11
11
|
require 'rubocop/rspec/util'
|
12
12
|
require 'rubocop/rspec/language'
|
13
13
|
require 'rubocop/rspec/language/node_pattern'
|
14
|
-
require 'rubocop/rspec/
|
14
|
+
require 'rubocop/rspec/example_group'
|
15
|
+
require 'rubocop/rspec/example'
|
16
|
+
require 'rubocop/cop/rspec/cop'
|
15
17
|
|
16
18
|
RuboCop::RSpec::Inject.defaults!
|
17
19
|
|
@@ -34,10 +36,13 @@ require 'rubocop/cop/rspec/leading_subject'
|
|
34
36
|
require 'rubocop/cop/rspec/let_setup'
|
35
37
|
require 'rubocop/cop/rspec/message_chain'
|
36
38
|
require 'rubocop/cop/rspec/message_expectation'
|
39
|
+
require 'rubocop/cop/rspec/message_spies'
|
37
40
|
require 'rubocop/cop/rspec/multiple_describes'
|
38
41
|
require 'rubocop/cop/rspec/multiple_expectations'
|
39
42
|
require 'rubocop/cop/rspec/named_subject'
|
40
43
|
require 'rubocop/cop/rspec/nested_groups'
|
41
44
|
require 'rubocop/cop/rspec/not_to_not'
|
45
|
+
require 'rubocop/cop/rspec/repeated_description'
|
46
|
+
require 'rubocop/cop/rspec/single_argument_message_chain'
|
42
47
|
require 'rubocop/cop/rspec/subject_stub'
|
43
48
|
require 'rubocop/cop/rspec/verified_doubles'
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop # rubocop:disable Style/Documentation
|
3
|
+
WorkaroundCop = Cop.dup
|
4
|
+
|
5
|
+
# Clone of the the normal RuboCop::Cop::Cop class so we can rewrite
|
6
|
+
# the inherited method without breaking functionality
|
7
|
+
class WorkaroundCop
|
8
|
+
# Overwrite the cop inherited method to be a noop. Our RSpec::Cop
|
9
|
+
# class will invoke the inherited hook instead
|
10
|
+
def self.inherited(*)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Special case `Module#<` so that the rspec support rubocop exports
|
14
|
+
# is compatible with our subclass
|
15
|
+
def self.<(other)
|
16
|
+
other.equal?(RuboCop::Cop::Cop) || super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
private_constant(:WorkaroundCop)
|
20
|
+
|
21
|
+
module RSpec
|
22
|
+
# @abstract parent class to rspec cops
|
23
|
+
#
|
24
|
+
# The criteria for whether rubocop-rspec analyzes a certain ruby file
|
25
|
+
# is configured via `AllCops/RSpec`. For example, if you want to
|
26
|
+
# customize your project to scan all files within a `test/` directory
|
27
|
+
# then you could add this to your configuration:
|
28
|
+
#
|
29
|
+
# @example configuring analyzed paths
|
30
|
+
#
|
31
|
+
# AllCops:
|
32
|
+
# RSpec:
|
33
|
+
# Patterns:
|
34
|
+
# - '_test.rb$'
|
35
|
+
# - '(?:^|/)test/'
|
36
|
+
class Cop < WorkaroundCop
|
37
|
+
DEFAULT_CONFIGURATION =
|
38
|
+
RuboCop::RSpec::CONFIG.fetch('AllCops').fetch('RSpec')
|
39
|
+
|
40
|
+
include RuboCop::RSpec::Language, RuboCop::RSpec::Language::NodePattern
|
41
|
+
|
42
|
+
# Invoke the original inherited hook so our cops are recognized
|
43
|
+
def self.inherited(subclass)
|
44
|
+
RuboCop::Cop::Cop.inherited(subclass)
|
45
|
+
end
|
46
|
+
|
47
|
+
def relevant_file?(file)
|
48
|
+
rspec_pattern =~ file && super
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def rspec_pattern
|
54
|
+
Regexp.union(rspec_pattern_config.map(&Regexp.public_method(:new)))
|
55
|
+
end
|
56
|
+
|
57
|
+
def rspec_pattern_config
|
58
|
+
config
|
59
|
+
.for_all_cops
|
60
|
+
.fetch('RSpec', DEFAULT_CONFIGURATION)
|
61
|
+
.fetch('Patterns')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -17,7 +17,7 @@ module RuboCop
|
|
17
17
|
# describe "A feature example", type: :feature do
|
18
18
|
# end
|
19
19
|
class DescribeClass < Cop
|
20
|
-
include RuboCop::RSpec::
|
20
|
+
include RuboCop::RSpec::TopLevelDescribe
|
21
21
|
|
22
22
|
MSG = 'The first argument to describe should be '\
|
23
23
|
'the class or module being tested.'.freeze
|
@@ -39,7 +39,12 @@ module RuboCop
|
|
39
39
|
(sym {:request :feature :routing :view}))
|
40
40
|
PATTERN
|
41
41
|
|
42
|
+
def_node_matcher :shared_group?, <<-PATTERN
|
43
|
+
(block (send {(const nil :RSpec) nil} #{SharedGroups::ALL.node_pattern_union} ...) ...)
|
44
|
+
PATTERN
|
45
|
+
|
42
46
|
def on_top_level_describe(node, args)
|
47
|
+
return if shared_group?(root_node)
|
43
48
|
return if valid_describe?(node)
|
44
49
|
|
45
50
|
describe_with_metadata(node) do |pairs|
|
@@ -17,8 +17,7 @@ module RuboCop
|
|
17
17
|
# describe MyClass, '.my_class_method' do
|
18
18
|
# end
|
19
19
|
class DescribeMethod < Cop
|
20
|
-
include RuboCop::RSpec::
|
21
|
-
RuboCop::RSpec::TopLevelDescribe,
|
20
|
+
include RuboCop::RSpec::TopLevelDescribe,
|
22
21
|
RuboCop::RSpec::Util
|
23
22
|
|
24
23
|
MESSAGE = 'The second argument to describe should be the method ' \
|
@@ -20,20 +20,17 @@ module RuboCop
|
|
20
20
|
# subject { described_class.do_something }
|
21
21
|
# end
|
22
22
|
class DescribedClass < Cop
|
23
|
-
include RuboCop::RSpec::
|
23
|
+
include RuboCop::RSpec::TopLevelDescribe
|
24
24
|
|
25
25
|
DESCRIBED_CLASS = 'described_class'.freeze
|
26
26
|
MSG = "Use `#{DESCRIBED_CLASS}` instead of `%s`".freeze
|
27
27
|
|
28
|
-
RSPEC_BLOCK_METHODS = RuboCop::RSpec::Language::ALL.to_node_pattern
|
29
|
-
|
30
28
|
def_node_matcher :common_instance_exec_closure?, <<-PATTERN
|
31
29
|
(block (send (const nil {:Class :Module}) :new ...) ...)
|
32
30
|
PATTERN
|
33
31
|
|
34
|
-
def_node_matcher :rspec_block?,
|
35
|
-
|
36
|
-
PATTERN
|
32
|
+
def_node_matcher :rspec_block?,
|
33
|
+
RuboCop::RSpec::Language::ALL.block_pattern
|
37
34
|
|
38
35
|
def_node_matcher :scope_changing_syntax?, '{def class module}'
|
39
36
|
|
@@ -58,21 +58,11 @@ module RuboCop
|
|
58
58
|
# end
|
59
59
|
#
|
60
60
|
class EmptyExampleGroup < Cop
|
61
|
-
include RuboCop::RSpec::SpecOnly,
|
62
|
-
RuboCop::RSpec::Language,
|
63
|
-
RuboCop::RSpec::Language::NodePattern
|
64
|
-
|
65
61
|
MSG = 'Empty example group detected.'.freeze
|
66
62
|
|
67
63
|
def_node_search :contains_example?, <<-PATTERN
|
68
64
|
{
|
69
|
-
(
|
70
|
-
#{Examples::ALL.to_node_pattern}
|
71
|
-
:it_behaves_like
|
72
|
-
:it_should_behave_like
|
73
|
-
:include_context
|
74
|
-
:include_examples
|
75
|
-
} ...)
|
65
|
+
#{(Examples::ALL + Includes::ALL).send_pattern}
|
76
66
|
(send _ #custom_include? ...)
|
77
67
|
}
|
78
68
|
PATTERN
|
@@ -19,8 +19,6 @@ module RuboCop
|
|
19
19
|
# it 'finds nothing' do
|
20
20
|
# end
|
21
21
|
class ExampleWording < Cop
|
22
|
-
include RuboCop::RSpec::SpecOnly
|
23
|
-
|
24
22
|
MSG = 'Do not use should when describing your tests.'.freeze
|
25
23
|
|
26
24
|
def on_block(node) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/LineLength
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
# my_class_spec.rb # describe MyClass, '#method'
|
43
43
|
#
|
44
44
|
class FilePath < Cop
|
45
|
-
include RuboCop::RSpec::
|
45
|
+
include RuboCop::RSpec::TopLevelDescribe
|
46
46
|
|
47
47
|
MESSAGE = 'Spec path should end with `%s`'.freeze
|
48
48
|
ROUTING_PAIR = s(:pair, s(:sym, :type), s(:sym, :routing))
|
@@ -20,8 +20,6 @@ module RuboCop
|
|
20
20
|
# describe MyClass do
|
21
21
|
# end
|
22
22
|
class Focus < Cop
|
23
|
-
include RuboCop::RSpec::SpecOnly, RuboCop::RSpec::Language
|
24
|
-
|
25
23
|
MSG = 'Focused spec found.'.freeze
|
26
24
|
|
27
25
|
focusable =
|
@@ -32,20 +30,17 @@ module RuboCop
|
|
32
30
|
|
33
31
|
focused = ExampleGroups::FOCUSED + Examples::FOCUSED
|
34
32
|
|
35
|
-
FOCUSABLE_SELECTORS = focusable.
|
36
|
-
FOCUSING_SELECTORS = focused.to_node_pattern
|
33
|
+
FOCUSABLE_SELECTORS = focusable.node_pattern_union
|
37
34
|
|
38
35
|
FOCUS_SYMBOL = s(:sym, :focus)
|
39
36
|
FOCUS_TRUE = s(:pair, FOCUS_SYMBOL, s(:true))
|
40
37
|
|
41
38
|
def_node_matcher :metadata, <<-PATTERN
|
42
|
-
{(send nil
|
43
|
-
(send nil
|
39
|
+
{(send nil #{FOCUSABLE_SELECTORS} ... (hash $...))
|
40
|
+
(send nil #{FOCUSABLE_SELECTORS} $...)}
|
44
41
|
PATTERN
|
45
42
|
|
46
|
-
def_node_matcher :focused_block?,
|
47
|
-
(send nil {#{FOCUSING_SELECTORS}} ...)
|
48
|
-
PATTERN
|
43
|
+
def_node_matcher :focused_block?, focused.send_pattern
|
49
44
|
|
50
45
|
def on_send(node)
|
51
46
|
focus_metadata(node) do |focus|
|
@@ -57,15 +57,13 @@ module RuboCop
|
|
57
57
|
# before(:example) do
|
58
58
|
# ...
|
59
59
|
# end
|
60
|
-
class HookArgument <
|
61
|
-
include
|
62
|
-
RuboCop::RSpec::SpecOnly,
|
63
|
-
ConfigurableEnforcedStyle
|
60
|
+
class HookArgument < Cop
|
61
|
+
include ConfigurableEnforcedStyle
|
64
62
|
|
65
63
|
IMPLICIT_MSG = 'Omit the default `%p` argument for RSpec hooks.'.freeze
|
66
64
|
EXPLICIT_MSG = 'Use `%p` for RSpec hooks.'.freeze
|
67
65
|
|
68
|
-
HOOKS =
|
66
|
+
HOOKS = Hooks::ALL.node_pattern_union.freeze
|
69
67
|
|
70
68
|
def_node_matcher :scoped_hook, <<-PATTERN
|
71
69
|
(block $(send nil #{HOOKS} (sym ${:each :example})) ...)
|
@@ -47,15 +47,11 @@ module RuboCop
|
|
47
47
|
# end
|
48
48
|
#
|
49
49
|
class InstanceVariable < Cop
|
50
|
-
include RuboCop::RSpec::SpecOnly, RuboCop::RSpec::Language
|
51
|
-
|
52
50
|
MESSAGE = 'Use `let` instead of an instance variable'.freeze
|
53
51
|
|
54
52
|
EXAMPLE_GROUP_METHODS = ExampleGroups::ALL + SharedGroups::ALL
|
55
53
|
|
56
|
-
def_node_matcher :spec_group?,
|
57
|
-
(block (send _ {#{EXAMPLE_GROUP_METHODS.to_node_pattern}} ...) ...)
|
58
|
-
PATTERN
|
54
|
+
def_node_matcher :spec_group?, EXAMPLE_GROUP_METHODS.block_pattern
|
59
55
|
|
60
56
|
def_node_search :ivar_usage, '$(ivar $_)'
|
61
57
|
|
@@ -27,8 +27,6 @@ module RuboCop
|
|
27
27
|
# end
|
28
28
|
# end
|
29
29
|
class LeadingSubject < Cop
|
30
|
-
include RuboCop::RSpec::SpecOnly, RuboCop::RSpec::Language
|
31
|
-
|
32
30
|
MSG = 'Declare `subject` above any other `let` declarations'.freeze
|
33
31
|
|
34
32
|
def_node_matcher :subject?, '(block $(send nil :subject ...) args ...)'
|
@@ -26,10 +26,7 @@ module RuboCop
|
|
26
26
|
# expect(Widget.count).to eq(1)
|
27
27
|
# end
|
28
28
|
class LetSetup < Cop
|
29
|
-
include RuboCop::RSpec::
|
30
|
-
RuboCop::RSpec::TopLevelDescribe,
|
31
|
-
RuboCop::RSpec::Language,
|
32
|
-
RuboCop::RSpec::Language::NodePattern
|
29
|
+
include RuboCop::RSpec::TopLevelDescribe
|
33
30
|
|
34
31
|
MSG = 'Do not use `let!` for test setup.'.freeze
|
35
32
|
|
@@ -12,18 +12,11 @@ module RuboCop
|
|
12
12
|
# allow(foo).to receive(bar: thing)
|
13
13
|
#
|
14
14
|
class MessageChain < Cop
|
15
|
-
include RuboCop::RSpec::SpecOnly
|
16
|
-
|
17
15
|
MESSAGE = 'Avoid stubbing using `%<method>s`'.freeze
|
18
16
|
|
19
|
-
MESSAGE_CHAIN_METHODS = [
|
20
|
-
:receive_message_chain,
|
21
|
-
:stub_chain
|
22
|
-
].freeze
|
23
|
-
|
24
17
|
def on_send(node)
|
25
18
|
_receiver, method_name, *_args = *node
|
26
|
-
return unless
|
19
|
+
return unless Matchers::MESSAGE_CHAIN.include?(method_name)
|
27
20
|
|
28
21
|
add_offense(node, :selector, MESSAGE % { method: method_name })
|
29
22
|
end
|