rubocop-rspec 1.21.0 → 1.22.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/Rakefile +19 -0
  4. data/config/default.yml +19 -0
  5. data/lib/rubocop-rspec.rb +17 -72
  6. data/lib/rubocop/cop/rspec/context_wording.rb +2 -2
  7. data/lib/rubocop/cop/rspec/describe_class.rb +1 -1
  8. data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
  9. data/lib/rubocop/cop/rspec/described_class.rb +2 -4
  10. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +6 -10
  11. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +4 -4
  12. data/lib/rubocop/cop/rspec/example_without_description.rb +89 -0
  13. data/lib/rubocop/cop/rspec/expect_change.rb +102 -0
  14. data/lib/rubocop/cop/rspec/hook_argument.rb +9 -9
  15. data/lib/rubocop/cop/rspec/instance_variable.rb +9 -0
  16. data/lib/rubocop/cop/rspec/leading_subject.rb +1 -8
  17. data/lib/rubocop/cop/rspec/let_before_examples.rb +46 -6
  18. data/lib/rubocop/cop/rspec/multiple_describes.rb +2 -2
  19. data/lib/rubocop/cop/rspec/multiple_expectations.rb +2 -4
  20. data/lib/rubocop/cop/rspec/multiple_subjects.rb +1 -2
  21. data/lib/rubocop/cop/rspec/nested_groups.rb +2 -2
  22. data/lib/rubocop/cop/rspec/overwriting_setup.rb +11 -13
  23. data/lib/rubocop/cop/rspec/return_from_stub.rb +85 -0
  24. data/lib/rubocop/cop/rspec/scattered_let.rb +9 -13
  25. data/lib/rubocop/cop/rspec/shared_context.rb +2 -2
  26. data/lib/rubocop/cop/rspec_cops.rb +59 -0
  27. data/lib/rubocop/rspec/description_extractor.rb +13 -1
  28. data/lib/rubocop/rspec/version.rb +1 -1
  29. data/rubocop-rspec.gemspec +1 -1
  30. data/spec/rubocop/cop/rspec/describe_class_spec.rb +7 -0
  31. data/spec/rubocop/cop/rspec/example_without_description_spec.rb +82 -0
  32. data/spec/rubocop/cop/rspec/expect_change_spec.rb +78 -0
  33. data/spec/rubocop/cop/rspec/instance_variable_spec.rb +18 -0
  34. data/spec/rubocop/cop/rspec/let_before_examples_spec.rb +48 -0
  35. data/spec/rubocop/cop/rspec/return_from_stub_spec.rb +65 -0
  36. data/spec/rubocop/rspec/description_extractor_spec.rb +6 -2
  37. metadata +11 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db6a354c4b2a3ba18944c5a6fc3ce076eaec380b3f84b67d3a825ab81a2f18a2
4
- data.tar.gz: c15d5bb4a019e0ff6d419058e136959aa54af22a409e302c4cbd012f06960ba6
3
+ metadata.gz: 63bb2b52f05acc607af023c9e7afa5375d5815cf026b73fda3dc10c8648806d2
4
+ data.tar.gz: c0bf3717a359f99ec9dd9519f5897c95dcc3e35f592baaad3dc037f1ae25c7d8
5
5
  SHA512:
6
- metadata.gz: cd09459ea1199299104e462a6592ffe6ecba612f6560e4f5003c13c302cf47a9b21b5da186cb7237378c2187f83c63894fb0a89780ce9c22d328b4cfb9795c81
7
- data.tar.gz: 2f24de47526a5719c96772d5c4e557fc37d2cc39472c372e0c3c6d4913a47cee1568bb06547de1d67684d1afd60b8875c7073e162b8e637e5718b4b4f8972839
6
+ metadata.gz: 4af0c95c0baf2a8dc469767c5455105276ea42f1c66ffadd09760e40eeecd0d362afcc7886b77931f0eafcc3a0785f0126ab4a3924ac4a07b1a8d94344c26d7a
7
+ data.tar.gz: 3712863da50c7d61207b76a92002432469e7021a87dcc1a4af1a8779581fc6a7b8beb9fc2e2017b8a45adace69f3e7a5dc6f9e9e2d47ca067c84df576cb8919d
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 1.22.0 (2018-01-10)
6
+
7
+ * Updates `describe_class` to account for RSpecs `:system` wrapper of rails system tests. ([@EliseFitz15][])
8
+ * Add `RSpec/ExpectChange` cop to enforce consistent usage of the change matcher. ([@Darhazer][])
9
+ * Add autocorrect support to `RSpec/LetBeforeExamples`. ([@Darhazer][])
10
+ * Fix `RSpec/InstanceVariable` flagging instance variables inside dynamically defined class. ([@Darhazer][])
11
+ * Add autocorrect support for `RSpec/ReturnFromStub` cop. ([@bquorning][])
12
+ * Add `RSpec/ExampleWithoutDescription` cop. ([@Darhazer][])
13
+
5
14
  ## 1.21.0 (2017-12-13)
6
15
 
7
16
  * Compatibility with RuboCop v0.52.0. ([@bquorning][])
@@ -280,3 +289,4 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
280
289
  [@walf443]: https://github.com/walf443
281
290
  [@pirj]: https://github.com/pirj
282
291
  [@telmofcosta]: https://github.com/telmofcosta
292
+ [@EliseFitz15]: https://github.com/EliseFitz15
data/Rakefile CHANGED
@@ -45,3 +45,22 @@ task confirm_config: :build_config do
45
45
  end
46
46
 
47
47
  task default: %i[build_config coverage internal_investigation confirm_config]
48
+
49
+ desc 'Generate a new cop template'
50
+ task :new_cop, [:cop] do |_task, args|
51
+ require 'rubocop'
52
+
53
+ cop_name = args.fetch(:cop) do
54
+ warn 'usage: bundle exec rake new_cop[Department/Name]'
55
+ exit!
56
+ end
57
+
58
+ generator = RuboCop::Cop::Generator.new(cop_name)
59
+
60
+ generator.write_source
61
+ generator.write_spec
62
+ generator.inject_require(root_file_path: 'lib/rubocop/cop/rspec_cops.rb')
63
+ generator.inject_config(config_file_path: 'config/default.yml')
64
+
65
+ puts generator.todo
66
+ end
@@ -104,6 +104,16 @@ RSpec/ExampleLength:
104
104
  Max: 5
105
105
  StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleLength
106
106
 
107
+ RSpec/ExampleWithoutDescription:
108
+ Description: Checks for examples without a description.
109
+ Enabled: true
110
+ EnforcedStyle: always_allow
111
+ SupportedStyles:
112
+ - always_allow
113
+ - single_line_only
114
+ - disallow
115
+ StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription
116
+
107
117
  RSpec/ExampleWording:
108
118
  Description: Checks for common mistakes in example descriptions.
109
119
  Enabled: true
@@ -122,6 +132,15 @@ RSpec/ExpectActual:
122
132
  - spec/routing/**/*
123
133
  StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectActual
124
134
 
135
+ RSpec/ExpectChange:
136
+ Description: Checks for consistent style of change matcher.
137
+ Enabled: true
138
+ EnforcedStyle: method_call
139
+ SupportedStyles:
140
+ - method_call
141
+ - block
142
+ StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectChange
143
+
125
144
  RSpec/ExpectInHook:
126
145
  Enabled: true
127
146
  Description: Do not use `expect` in hooks such as `before`.
@@ -3,81 +3,26 @@ require 'yaml'
3
3
 
4
4
  require 'rubocop'
5
5
 
6
- require 'rubocop/rspec'
7
- require 'rubocop/rspec/version'
8
- require 'rubocop/rspec/inject'
9
- require 'rubocop/rspec/top_level_describe'
10
- require 'rubocop/rspec/wording'
11
- require 'rubocop/rspec/util'
12
- require 'rubocop/rspec/language'
13
- require 'rubocop/rspec/language/node_pattern'
14
- require 'rubocop/rspec/concept'
15
- require 'rubocop/rspec/example_group'
16
- require 'rubocop/rspec/example'
17
- require 'rubocop/rspec/hook'
18
- require 'rubocop/cop/rspec/cop'
19
- require 'rubocop/rspec/align_let_brace'
20
- require 'rubocop/rspec/capybara'
21
- require 'rubocop/rspec/factory_bot'
6
+ require_relative 'rubocop/rspec'
7
+ require_relative 'rubocop/rspec/version'
8
+ require_relative 'rubocop/rspec/inject'
9
+ require_relative 'rubocop/rspec/top_level_describe'
10
+ require_relative 'rubocop/rspec/wording'
11
+ require_relative 'rubocop/rspec/util'
12
+ require_relative 'rubocop/rspec/language'
13
+ require_relative 'rubocop/rspec/language/node_pattern'
14
+ require_relative 'rubocop/rspec/concept'
15
+ require_relative 'rubocop/rspec/example_group'
16
+ require_relative 'rubocop/rspec/example'
17
+ require_relative 'rubocop/rspec/hook'
18
+ require_relative 'rubocop/cop/rspec/cop'
19
+ require_relative 'rubocop/rspec/align_let_brace'
20
+ require_relative 'rubocop/rspec/capybara'
21
+ require_relative 'rubocop/rspec/factory_bot'
22
22
 
23
23
  RuboCop::RSpec::Inject.defaults!
24
24
 
25
- # cops
26
- require 'rubocop/cop/rspec/align_left_let_brace'
27
- require 'rubocop/cop/rspec/align_right_let_brace'
28
- require 'rubocop/cop/rspec/any_instance'
29
- require 'rubocop/cop/rspec/around_block'
30
- require 'rubocop/cop/rspec/be_eql'
31
- require 'rubocop/cop/rspec/before_after_all'
32
- require 'rubocop/cop/rspec/capybara/current_path_expectation'
33
- require 'rubocop/cop/rspec/capybara/feature_methods'
34
- require 'rubocop/cop/rspec/context_wording'
35
- require 'rubocop/cop/rspec/describe_class'
36
- require 'rubocop/cop/rspec/describe_method'
37
- require 'rubocop/cop/rspec/describe_symbol'
38
- require 'rubocop/cop/rspec/described_class'
39
- require 'rubocop/cop/rspec/empty_example_group'
40
- require 'rubocop/cop/rspec/empty_line_after_final_let'
41
- require 'rubocop/cop/rspec/empty_line_after_subject'
42
- require 'rubocop/cop/rspec/example_length'
43
- require 'rubocop/cop/rspec/example_wording'
44
- require 'rubocop/cop/rspec/expect_actual'
45
- require 'rubocop/cop/rspec/expect_in_hook'
46
- require 'rubocop/cop/rspec/expect_output'
47
- require 'rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically'
48
- require 'rubocop/cop/rspec/file_path'
49
- require 'rubocop/cop/rspec/focus'
50
- require 'rubocop/cop/rspec/hook_argument'
51
- require 'rubocop/cop/rspec/implicit_expect'
52
- require 'rubocop/cop/rspec/instance_spy'
53
- require 'rubocop/cop/rspec/instance_variable'
54
- require 'rubocop/cop/rspec/invalid_predicate_matcher'
55
- require 'rubocop/cop/rspec/it_behaves_like'
56
- require 'rubocop/cop/rspec/iterated_expectation'
57
- require 'rubocop/cop/rspec/leading_subject'
58
- require 'rubocop/cop/rspec/let_before_examples'
59
- require 'rubocop/cop/rspec/let_setup'
60
- require 'rubocop/cop/rspec/message_chain'
61
- require 'rubocop/cop/rspec/message_expectation'
62
- require 'rubocop/cop/rspec/message_spies'
63
- require 'rubocop/cop/rspec/multiple_describes'
64
- require 'rubocop/cop/rspec/multiple_expectations'
65
- require 'rubocop/cop/rspec/multiple_subjects'
66
- require 'rubocop/cop/rspec/named_subject'
67
- require 'rubocop/cop/rspec/nested_groups'
68
- require 'rubocop/cop/rspec/not_to_not'
69
- require 'rubocop/cop/rspec/overwriting_setup'
70
- require 'rubocop/cop/rspec/repeated_description'
71
- require 'rubocop/cop/rspec/repeated_example'
72
- require 'rubocop/cop/rspec/return_from_stub'
73
- require 'rubocop/cop/rspec/scattered_let'
74
- require 'rubocop/cop/rspec/scattered_setup'
75
- require 'rubocop/cop/rspec/shared_context'
76
- require 'rubocop/cop/rspec/single_argument_message_chain'
77
- require 'rubocop/cop/rspec/subject_stub'
78
- require 'rubocop/cop/rspec/predicate_matcher'
79
- require 'rubocop/cop/rspec/verified_doubles'
80
- require 'rubocop/cop/rspec/void_expect'
25
+ require_relative 'rubocop/cop/rspec_cops'
81
26
 
82
27
  # We have to register our autocorrect incompatibilies in RuboCop's cops as well
83
28
  # so we do not hit infinite loops
@@ -19,12 +19,12 @@ module RuboCop
19
19
  # @example
20
20
  # # bad
21
21
  # context 'the display name not present' do
22
- # ...
22
+ # # ...
23
23
  # end
24
24
  #
25
25
  # # good
26
26
  # context 'when the display name is not present' do
27
- # ...
27
+ # # ...
28
28
  # end
29
29
  class ContextWording < Cop
30
30
  MSG = 'Start context description with %<prefixes>s.'.freeze
@@ -36,7 +36,7 @@ module RuboCop
36
36
  def_node_matcher :rails_metadata?, <<-PATTERN
37
37
  (pair
38
38
  (sym :type)
39
- (sym {:request :feature :routing :view}))
39
+ (sym {:request :feature :system :routing :view}))
40
40
  PATTERN
41
41
 
42
42
  def_node_matcher :shared_group?, <<-PATTERN
@@ -16,7 +16,7 @@ module RuboCop
16
16
  # ...
17
17
  # end
18
18
  #
19
- # See https://github.com/rspec/rspec-core/issues/1610
19
+ # @see https://github.com/rspec/rspec-core/issues/1610
20
20
  class DescribeSymbol < Cop
21
21
  MSG = 'Avoid describing symbols.'.freeze
22
22
 
@@ -81,10 +81,9 @@ module RuboCop
81
81
  def find_usage(node, &block)
82
82
  yield(node) if offensive?(node)
83
83
 
84
- return unless node.is_a?(Parser::AST::Node)
85
84
  return if scope_change?(node) || node.const_type?
86
85
 
87
- node.children.each do |child|
86
+ node.each_child_node do |child|
88
87
  find_usage(child, &block)
89
88
  end
90
89
  end
@@ -116,8 +115,7 @@ module RuboCop
116
115
  if style == :described_class
117
116
  node.eql?(@described_class)
118
117
  else
119
- _receiver, method_name, *_args = *node
120
- method_name == :described_class
118
+ node.method_name == :described_class
121
119
  end
122
120
  end
123
121
  end
@@ -7,19 +7,15 @@ module RuboCop
7
7
  #
8
8
  # @example
9
9
  # # bad
10
- # let(:foo) { bar }
11
- # let(:something) { other }
12
- # it do
13
- # ...
14
- # end
10
+ # let(:foo) { bar }
11
+ # let(:something) { other }
12
+ # it { does_something }
15
13
  #
16
14
  # # good
17
- # let(:foo) { bar }
18
- # let(:something) { other }
15
+ # let(:foo) { bar }
16
+ # let(:something) { other }
19
17
  #
20
- # it do
21
- # ...
22
- # end
18
+ # it { does_something }
23
19
  class EmptyLineAfterFinalLet < Cop
24
20
  MSG = 'Add an empty line after the last `let` block.'.freeze
25
21
 
@@ -7,13 +7,13 @@ module RuboCop
7
7
  #
8
8
  # @example
9
9
  # # bad
10
- # subject(:obj) { described_class }
11
- # let(:foo) { bar }
10
+ # subject(:obj) { described_class }
11
+ # let(:foo) { bar }
12
12
  #
13
13
  # # good
14
- # subject(:obj) { described_class }
14
+ # subject(:obj) { described_class }
15
15
  #
16
- # let(:foo) { bar }
16
+ # let(:foo) { bar }
17
17
  class EmptyLineAfterSubject < Cop
18
18
  MSG = 'Add empty line after `subject`.'.freeze
19
19
 
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for examples without a description.
7
+ #
8
+ # RSpec allows for auto-generated example descriptions when there is no
9
+ # description provided or the description is an empty one.
10
+ #
11
+ # This cop removes empty descriptions.
12
+ # It also defines whether auto-generated description is allowed, based
13
+ # on the configured style.
14
+ #
15
+ # This cop can be configured using the `EnforcedStyle` option
16
+ #
17
+ # @example `EnforcedStyle: always_allow`
18
+ # # bad
19
+ # it('') { is_expected.to be_good }
20
+ # it '' do
21
+ # result = service.call
22
+ # expect(result).to be(true)
23
+ # end
24
+ #
25
+ # # good
26
+ # it { is_expected.to be_good }
27
+ # it do
28
+ # result = service.call
29
+ # expect(result).to be(true)
30
+ # end
31
+ #
32
+ # @example `EnforcedStyle: single_line_only`
33
+ # # bad
34
+ # it('') { is_expected.to be_good }
35
+ # it do
36
+ # result = service.call
37
+ # expect(result).to be(true)
38
+ # end
39
+ #
40
+ # # good
41
+ # it { is_expected.to be_good }
42
+ #
43
+ # @example `EnforcedStyle: disallow`
44
+ # # bad
45
+ # it { is_expected.to be_good }
46
+ # it do
47
+ # result = service.call
48
+ # expect(result).to be(true)
49
+ # end
50
+ class ExampleWithoutDescription < Cop
51
+ include ConfigurableEnforcedStyle
52
+
53
+ MSG_DEFAULT_ARGUMENT = 'Omit the argument when you want to ' \
54
+ 'have auto-generated description.'.freeze
55
+ MSG_ADD_DESCRIPTION = 'Add a description.'.freeze
56
+
57
+ def_node_matcher :example?, Examples::ALL.send_pattern
58
+ def_node_matcher :example_description, '(send nil? _ $(str $_))'
59
+
60
+ def on_send(node)
61
+ return unless example?(node)
62
+
63
+ check_example_without_description(node)
64
+
65
+ example_description(node) do |message_node, message|
66
+ return unless message.to_s.empty?
67
+
68
+ add_offense(message_node, message: MSG_DEFAULT_ARGUMENT)
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def check_example_without_description(node)
75
+ _send, _method, arg = *node
76
+ return unless arg.nil?
77
+ return unless disallow_empty_description?(node)
78
+
79
+ add_offense(node, message: MSG_ADD_DESCRIPTION)
80
+ end
81
+
82
+ def disallow_empty_description?(node)
83
+ style == :disallow ||
84
+ (style == :single_line_only && node.parent.multiline?)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for consistent style of change matcher.
7
+ #
8
+ # Enforces either passing object and attribute as arguments to the matcher
9
+ # or passing a block that reads the attribute value.
10
+ #
11
+ # This cop can be configured using the `EnforcedStyle` option.
12
+ #
13
+ # @example `EnforcedStyle: block`
14
+ # # bad
15
+ # expect(run).to change(Foo, :bar)
16
+ #
17
+ # # good
18
+ # expect(run).to change { Foo.bar }
19
+ #
20
+ # @example `EnforcedStyle: method_call`
21
+ # # bad
22
+ # expect(run).to change { Foo.bar }
23
+ # expect(run).to change { foo.baz }
24
+ #
25
+ # # good
26
+ # expect(run).to change(Foo, :bar)
27
+ # expect(run).to change(foo, :baz)
28
+ # # also good when there are arguments or chained method calls
29
+ # expect(run).to change { Foo.bar(:count) }
30
+ # expect(run).to change { user.reload.name }
31
+ #
32
+ class ExpectChange < Cop
33
+ include ConfigurableEnforcedStyle
34
+
35
+ MSG_BLOCK = 'Prefer `change(%<obj>s, :%<attr>s)`.'.freeze
36
+ MSG_CALL = 'Prefer `change { %<obj>s.%<attr>s }`.'.freeze
37
+
38
+ def_node_matcher :expect_change_with_arguments, <<-PATTERN
39
+ (send nil? :change ({const send} nil? $_) (sym $_))
40
+ PATTERN
41
+
42
+ def_node_matcher :expect_change_with_block, <<-PATTERN
43
+ (block
44
+ (send nil? :change)
45
+ (args)
46
+ (send ({const send} nil? $_) $_)
47
+ )
48
+ PATTERN
49
+
50
+ def on_send(node)
51
+ return unless style == :block
52
+
53
+ expect_change_with_arguments(node) do |receiver, message|
54
+ add_offense(
55
+ node,
56
+ message: format(MSG_CALL, obj: receiver, attr: message)
57
+ )
58
+ end
59
+ end
60
+
61
+ def on_block(node)
62
+ return unless style == :method_call
63
+
64
+ expect_change_with_block(node) do |receiver, message|
65
+ add_offense(
66
+ node,
67
+ message: format(MSG_BLOCK, obj: receiver, attr: message)
68
+ )
69
+ end
70
+ end
71
+
72
+ def autocorrect(node)
73
+ if style == :block
74
+ autocorrect_method_call_to_block(node)
75
+ else
76
+ autocorrect_block_to_method_call(node)
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def autocorrect_method_call_to_block(node)
83
+ lambda do |corrector|
84
+ expect_change_with_arguments(node) do |receiver, message|
85
+ replacement = "change { #{receiver}.#{message} }"
86
+ corrector.replace(node.loc.expression, replacement)
87
+ end
88
+ end
89
+ end
90
+
91
+ def autocorrect_block_to_method_call(node)
92
+ lambda do |corrector|
93
+ expect_change_with_block(node) do |receiver, message|
94
+ replacement = "change(#{receiver}, :#{message})"
95
+ corrector.replace(node.loc.expression, replacement)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end