rubocop-rspec 2.6.0 → 2.9.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 +21 -0
- data/config/default.yml +137 -92
- data/lib/rubocop/cop/rspec/be_eq.rb +45 -0
- data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
- data/lib/rubocop/cop/rspec/be_nil.rb +40 -0
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +7 -7
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +2 -23
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +3 -2
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +3 -9
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +4 -3
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +107 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +3 -7
- data/lib/rubocop/cop/rspec/mixin/inside_example_group.rb +29 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +44 -18
- data/lib/rubocop/cop/rspec/yield.rb +1 -1
- data/lib/rubocop/cop/rspec_cops.rb +3 -0
- data/lib/rubocop/rspec/config_formatter.rb +3 -4
- data/lib/rubocop/rspec/factory_bot/language.rb +17 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop-rspec.rb +5 -2
- metadata +9 -3
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Check for expectations where `be(...)` can replace `eq(...)`.
|
7
|
+
#
|
8
|
+
# The `be` matcher compares by identity while the `eq` matcher compares
|
9
|
+
# using `==`. Booleans and nil can be compared by identity and therefore
|
10
|
+
# the `be` matcher is preferable as it is a more strict test.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# expect(foo).to eq(true)
|
16
|
+
# expect(foo).to eq(false)
|
17
|
+
# expect(foo).to eq(nil)
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# expect(foo).to be(true)
|
21
|
+
# expect(foo).to be(false)
|
22
|
+
# expect(foo).to be(nil)
|
23
|
+
#
|
24
|
+
class BeEq < Base
|
25
|
+
extend AutoCorrector
|
26
|
+
|
27
|
+
MSG = 'Prefer `be` over `eq`.'
|
28
|
+
RESTRICT_ON_SEND = %i[eq].freeze
|
29
|
+
|
30
|
+
# @!method eq_type_with_identity?(node)
|
31
|
+
def_node_matcher :eq_type_with_identity?, <<-PATTERN
|
32
|
+
(send nil? :eq {true false nil})
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def on_send(node)
|
36
|
+
return unless eq_type_with_identity?(node)
|
37
|
+
|
38
|
+
add_offense(node.loc.selector) do |corrector|
|
39
|
+
corrector.replace(node.loc.selector, 'be')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
|
44
44
|
# @!method eql_type_with_identity(node)
|
45
45
|
def_node_matcher :eql_type_with_identity, <<-PATTERN
|
46
|
-
(send _ :to $(send nil? :eql {true false int float sym
|
46
|
+
(send _ :to $(send nil? :eql {true false int float sym nil}))
|
47
47
|
PATTERN
|
48
48
|
|
49
49
|
def on_send(node)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Check that `be_nil` is used instead of `be(nil)`.
|
7
|
+
#
|
8
|
+
# RSpec has a built-in `be_nil` matcher specifically for expecting `nil`.
|
9
|
+
# For consistent specs, we recommend using that instead of `be(nil)`.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# expect(foo).to be(nil)
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# expect(foo).to be_nil
|
18
|
+
#
|
19
|
+
class BeNil < Base
|
20
|
+
extend AutoCorrector
|
21
|
+
|
22
|
+
MSG = 'Prefer `be_nil` over `be(nil)`.'
|
23
|
+
RESTRICT_ON_SEND = %i[be].freeze
|
24
|
+
|
25
|
+
# @!method nil_value_expectation?(node)
|
26
|
+
def_node_matcher :nil_value_expectation?, <<-PATTERN
|
27
|
+
(send nil? :be nil)
|
28
|
+
PATTERN
|
29
|
+
|
30
|
+
def on_send(node)
|
31
|
+
return unless nil_value_expectation?(node)
|
32
|
+
|
33
|
+
add_offense(node) do |corrector|
|
34
|
+
corrector.replace(node.loc.expression, 'be_nil')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -6,13 +6,13 @@ module RuboCop
|
|
6
6
|
module Capybara
|
7
7
|
# Checks that no expectations are set on Capybara's `current_path`.
|
8
8
|
#
|
9
|
-
# The
|
10
|
-
# teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path-
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
9
|
+
# The
|
10
|
+
# https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path-instance_method[`have_current_path` matcher]
|
11
|
+
# should be used on `page` to set expectations on Capybara's
|
12
|
+
# current path, since it uses
|
13
|
+
# https://github.com/teamcapybara/capybara/blob/master/README.md#asynchronous-javascript-ajax-and-friends[Capybara's waiting functionality]
|
14
|
+
# which ensures that preceding actions (like `click_link`) have
|
15
|
+
# completed.
|
16
16
|
#
|
17
17
|
# @example
|
18
18
|
# # bad
|
@@ -42,6 +42,7 @@ module RuboCop
|
|
42
42
|
# end
|
43
43
|
class FeatureMethods < Base
|
44
44
|
extend AutoCorrector
|
45
|
+
include InsideExampleGroup
|
45
46
|
|
46
47
|
MSG = 'Use `%<replacement>s` instead of `%<method>s`.'
|
47
48
|
|
@@ -60,13 +61,6 @@ module RuboCop
|
|
60
61
|
{#{MAP.keys.map(&:inspect).join(' ')}}
|
61
62
|
PATTERN
|
62
63
|
|
63
|
-
# @!method spec?(node)
|
64
|
-
def_node_matcher :spec?, <<-PATTERN
|
65
|
-
(block
|
66
|
-
(send #rspec? {:describe :feature} ...)
|
67
|
-
...)
|
68
|
-
PATTERN
|
69
|
-
|
70
64
|
# @!method feature_method(node)
|
71
65
|
def_node_matcher :feature_method, <<-PATTERN
|
72
66
|
(block
|
@@ -75,7 +69,7 @@ module RuboCop
|
|
75
69
|
PATTERN
|
76
70
|
|
77
71
|
def on_block(node)
|
78
|
-
return unless
|
72
|
+
return unless inside_example_group?(node)
|
79
73
|
|
80
74
|
feature_method(node) do |send_node, match|
|
81
75
|
next if enabled?(match)
|
@@ -93,21 +87,6 @@ module RuboCop
|
|
93
87
|
|
94
88
|
private
|
95
89
|
|
96
|
-
def inside_spec?(node)
|
97
|
-
return spec?(node) if root_node?(node)
|
98
|
-
|
99
|
-
root = node.ancestors.find { |parent| root_node?(parent) }
|
100
|
-
spec?(root)
|
101
|
-
end
|
102
|
-
|
103
|
-
def root_node?(node)
|
104
|
-
node.parent.nil? || root_with_siblings?(node.parent)
|
105
|
-
end
|
106
|
-
|
107
|
-
def root_with_siblings?(node)
|
108
|
-
node.begin_type? && node.parent.nil?
|
109
|
-
end
|
110
|
-
|
111
90
|
def enabled?(method_name)
|
112
91
|
enabled_methods.include?(method_name)
|
113
92
|
end
|
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
6
|
module Capybara
|
7
|
-
# Checks for boolean visibility in
|
7
|
+
# Checks for boolean visibility in Capybara finders.
|
8
8
|
#
|
9
9
|
# Capybara lets you find elements that match a certain visibility using
|
10
10
|
# the `:visible` option. `:visible` accepts both boolean and symbols as
|
@@ -12,7 +12,8 @@ module RuboCop
|
|
12
12
|
# false` does not find just invisible elements, but both visible and
|
13
13
|
# invisible elements. For expressiveness and clarity, use one of the
|
14
14
|
# symbol values, `:all`, `:hidden` or `:visible`.
|
15
|
-
#
|
15
|
+
# Read more in
|
16
|
+
# https://www.rubydoc.info/gems/capybara/Capybara%2FNode%2FFinders:all[the documentation].
|
16
17
|
#
|
17
18
|
# @example
|
18
19
|
#
|
@@ -17,24 +17,18 @@ module RuboCop
|
|
17
17
|
class EmptyLineAfterSubject < Base
|
18
18
|
extend AutoCorrector
|
19
19
|
include EmptyLineSeparation
|
20
|
+
include InsideExampleGroup
|
20
21
|
|
21
22
|
MSG = 'Add an empty line after `%<subject>s`.'
|
22
23
|
|
23
24
|
def on_block(node)
|
24
|
-
return unless subject?(node)
|
25
|
+
return unless subject?(node)
|
26
|
+
return unless inside_example_group?(node)
|
25
27
|
|
26
28
|
missing_separating_line_offense(node) do |method|
|
27
29
|
format(MSG, subject: method)
|
28
30
|
end
|
29
31
|
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def in_spec_block?(node)
|
34
|
-
node.each_ancestor(:block).any? do |ancestor|
|
35
|
-
Examples.all(ancestor.method_name)
|
36
|
-
end
|
37
|
-
end
|
38
32
|
end
|
39
33
|
end
|
40
34
|
end
|
@@ -27,6 +27,7 @@ module RuboCop
|
|
27
27
|
class CreateList < Base
|
28
28
|
extend AutoCorrector
|
29
29
|
include ConfigurableEnforcedStyle
|
30
|
+
include RuboCop::RSpec::FactoryBot::Language
|
30
31
|
|
31
32
|
MSG_CREATE_LIST = 'Prefer create_list.'
|
32
33
|
MSG_N_TIMES = 'Prefer %<number>s.times.'
|
@@ -43,12 +44,12 @@ module RuboCop
|
|
43
44
|
|
44
45
|
# @!method factory_call(node)
|
45
46
|
def_node_matcher :factory_call, <<-PATTERN
|
46
|
-
(send ${
|
47
|
+
(send ${nil? #factory_bot?} :create (sym $_) $...)
|
47
48
|
PATTERN
|
48
49
|
|
49
50
|
# @!method factory_list_call(node)
|
50
51
|
def_node_matcher :factory_list_call, <<-PATTERN
|
51
|
-
(send {
|
52
|
+
(send {nil? #factory_bot?} :create_list (sym _) (int $_) ...)
|
52
53
|
PATTERN
|
53
54
|
|
54
55
|
def on_block(node)
|
@@ -160,7 +161,7 @@ module RuboCop
|
|
160
161
|
def call_with_block_replacement(node)
|
161
162
|
block = node.body
|
162
163
|
arguments = build_arguments(block, node.receiver.source)
|
163
|
-
replacement = format_receiver(block.
|
164
|
+
replacement = format_receiver(block.receiver)
|
164
165
|
replacement += format_method_call(block, 'create_list', arguments)
|
165
166
|
replacement += format_block(block)
|
166
167
|
replacement
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
module FactoryBot
|
7
|
+
# Use shorthands from `FactoryBot::Syntax::Methods` in your specs.
|
8
|
+
#
|
9
|
+
# @safety
|
10
|
+
# The auto-correction is marked as unsafe because the cop
|
11
|
+
# cannot verify whether you already include
|
12
|
+
# `FactoryBot::Syntax::Methods` in your test suite.
|
13
|
+
#
|
14
|
+
# If you're using Rails, add the following configuration to
|
15
|
+
# `spec/support/factory_bot.rb` and be sure to require that file in
|
16
|
+
# `rails_helper.rb`:
|
17
|
+
#
|
18
|
+
# [source,ruby]
|
19
|
+
# ----
|
20
|
+
# RSpec.configure do |config|
|
21
|
+
# config.include FactoryBot::Syntax::Methods
|
22
|
+
# end
|
23
|
+
# ----
|
24
|
+
#
|
25
|
+
# If you're not using Rails:
|
26
|
+
#
|
27
|
+
# [source,ruby]
|
28
|
+
# ----
|
29
|
+
# RSpec.configure do |config|
|
30
|
+
# config.include FactoryBot::Syntax::Methods
|
31
|
+
#
|
32
|
+
# config.before(:suite) do
|
33
|
+
# FactoryBot.find_definitions
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
# ----
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
# # bad
|
40
|
+
# FactoryBot.create(:bar)
|
41
|
+
# FactoryBot.build(:bar)
|
42
|
+
# FactoryBot.attributes_for(:bar)
|
43
|
+
#
|
44
|
+
# # good
|
45
|
+
# create(:bar)
|
46
|
+
# build(:bar)
|
47
|
+
# attributes_for(:bar)
|
48
|
+
#
|
49
|
+
class SyntaxMethods < Base
|
50
|
+
extend AutoCorrector
|
51
|
+
include InsideExampleGroup
|
52
|
+
include RangeHelp
|
53
|
+
include RuboCop::RSpec::FactoryBot::Language
|
54
|
+
|
55
|
+
MSG = 'Use `%<method>s` from `FactoryBot::Syntax::Methods`.'
|
56
|
+
|
57
|
+
RESTRICT_ON_SEND = %i[
|
58
|
+
attributes_for
|
59
|
+
attributes_for_list
|
60
|
+
attributes_for_pair
|
61
|
+
build
|
62
|
+
build_list
|
63
|
+
build_pair
|
64
|
+
build_stubbed
|
65
|
+
build_stubbed_list
|
66
|
+
build_stubbed_pair
|
67
|
+
create
|
68
|
+
create_list
|
69
|
+
create_pair
|
70
|
+
generate
|
71
|
+
generate_list
|
72
|
+
null
|
73
|
+
null_list
|
74
|
+
null_pair
|
75
|
+
].to_set.freeze
|
76
|
+
|
77
|
+
def on_send(node)
|
78
|
+
return unless factory_bot?(node.receiver)
|
79
|
+
return unless inside_example_group?(node)
|
80
|
+
|
81
|
+
message = format(MSG, method: node.method_name)
|
82
|
+
|
83
|
+
add_offense(crime_scene(node), message: message) do |corrector|
|
84
|
+
corrector.remove(offense(node))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def crime_scene(node)
|
91
|
+
range_between(
|
92
|
+
node.loc.expression.begin_pos,
|
93
|
+
node.loc.selector.end_pos
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
def offense(node)
|
98
|
+
range_between(
|
99
|
+
node.loc.expression.begin_pos,
|
100
|
+
node.loc.selector.begin_pos
|
101
|
+
)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -33,11 +33,13 @@ module RuboCop
|
|
33
33
|
#
|
34
34
|
class LeadingSubject < Base
|
35
35
|
extend AutoCorrector
|
36
|
+
include InsideExampleGroup
|
36
37
|
|
37
38
|
MSG = 'Declare `subject` above any other `%<offending>s` declarations.'
|
38
39
|
|
39
40
|
def on_block(node)
|
40
|
-
return unless subject?(node)
|
41
|
+
return unless subject?(node)
|
42
|
+
return unless inside_example_group?(node)
|
41
43
|
|
42
44
|
check_previous_nodes(node)
|
43
45
|
end
|
@@ -78,12 +80,6 @@ module RuboCop
|
|
78
80
|
spec_group?(node) ||
|
79
81
|
include?(node)
|
80
82
|
end
|
81
|
-
|
82
|
-
def in_spec_block?(node)
|
83
|
-
node.each_ancestor(:block).any? do |ancestor|
|
84
|
-
example?(ancestor)
|
85
|
-
end
|
86
|
-
end
|
87
83
|
end
|
88
84
|
end
|
89
85
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps you identify whether a given node
|
7
|
+
# is within an example group or not.
|
8
|
+
module InsideExampleGroup
|
9
|
+
private
|
10
|
+
|
11
|
+
def inside_example_group?(node)
|
12
|
+
return spec_group?(node) if example_group_root?(node)
|
13
|
+
|
14
|
+
root = node.ancestors.find { |parent| example_group_root?(parent) }
|
15
|
+
|
16
|
+
spec_group?(root)
|
17
|
+
end
|
18
|
+
|
19
|
+
def example_group_root?(node)
|
20
|
+
node.parent.nil? || example_group_root_with_siblings?(node.parent)
|
21
|
+
end
|
22
|
+
|
23
|
+
def example_group_root_with_siblings?(node)
|
24
|
+
node.begin_type? && node.parent.nil?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
module RSpec
|
8
8
|
# Checks for stubbed test subjects.
|
9
9
|
#
|
10
|
+
# Checks nested subject stubs for innermost subject definition
|
11
|
+
# when subject is also defined in parent example groups.
|
12
|
+
#
|
10
13
|
# @see https://robots.thoughtbot.com/don-t-stub-the-system-under-test
|
11
14
|
# @see https://samphippen.com/introducing-rspec-smells-and-where-to-find-them#smell-1-stubject
|
12
15
|
# @see https://github.com/rubocop-hq/rspec-style-guide#dont-stub-subject
|
@@ -22,6 +25,20 @@ module RuboCop
|
|
22
25
|
# end
|
23
26
|
# end
|
24
27
|
#
|
28
|
+
# # bad
|
29
|
+
# describe Article do
|
30
|
+
# subject(:foo) { Article.new }
|
31
|
+
#
|
32
|
+
# context 'nested subject' do
|
33
|
+
# subject(:article) { Article.new }
|
34
|
+
#
|
35
|
+
# it 'indicates that the author is unknown' do
|
36
|
+
# allow(article).to receive(:author).and_return(nil)
|
37
|
+
# expect(article.description).to include('by an unknown author')
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
#
|
25
42
|
# # good
|
26
43
|
# describe Article do
|
27
44
|
# subject(:article) { Article.new(author: nil) }
|
@@ -36,27 +53,35 @@ module RuboCop
|
|
36
53
|
|
37
54
|
MSG = 'Do not stub methods of the object under test.'
|
38
55
|
|
39
|
-
# @!method subject(node)
|
56
|
+
# @!method subject?(node)
|
40
57
|
# Find a named or unnamed subject definition
|
41
58
|
#
|
42
59
|
# @example anonymous subject
|
43
|
-
# subject(parse('subject { foo }').ast) do |name|
|
60
|
+
# subject?(parse('subject { foo }').ast) do |name|
|
44
61
|
# name # => :subject
|
45
62
|
# end
|
46
63
|
#
|
47
64
|
# @example named subject
|
48
|
-
# subject(parse('subject(:thing) { foo }').ast) do |name|
|
65
|
+
# subject?(parse('subject(:thing) { foo }').ast) do |name|
|
49
66
|
# name # => :thing
|
50
67
|
# end
|
51
68
|
#
|
52
69
|
# @param node [RuboCop::AST::Node]
|
53
70
|
#
|
54
71
|
# @yield [Symbol] subject name
|
55
|
-
def_node_matcher :subject
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
72
|
+
def_node_matcher :subject?, <<-PATTERN
|
73
|
+
(block
|
74
|
+
(send nil?
|
75
|
+
{:subject (sym $_) | $:subject}
|
76
|
+
) args ...)
|
77
|
+
PATTERN
|
78
|
+
|
79
|
+
# @!method let?(node)
|
80
|
+
# Find a memoized helper
|
81
|
+
def_node_matcher :let?, <<-PATTERN
|
82
|
+
(block
|
83
|
+
(send nil? :let (sym $_)
|
84
|
+
) args ...)
|
60
85
|
PATTERN
|
61
86
|
|
62
87
|
# @!method message_expectation?(node, method_name)
|
@@ -73,7 +98,7 @@ module RuboCop
|
|
73
98
|
def_node_matcher :message_expectation?, <<-PATTERN
|
74
99
|
(send
|
75
100
|
{
|
76
|
-
(send nil? { :expect :allow } (send nil?
|
101
|
+
(send nil? { :expect :allow } (send nil? %))
|
77
102
|
(send nil? :is_expected)
|
78
103
|
}
|
79
104
|
#Runners.all
|
@@ -89,7 +114,8 @@ module RuboCop
|
|
89
114
|
PATTERN
|
90
115
|
|
91
116
|
def on_top_level_group(node)
|
92
|
-
@explicit_subjects =
|
117
|
+
@explicit_subjects = find_all_explicit(node, &method(:subject?))
|
118
|
+
@subject_overrides = find_all_explicit(node, &method(:let?))
|
93
119
|
|
94
120
|
find_subject_expectations(node) do |stub|
|
95
121
|
add_offense(stub)
|
@@ -98,12 +124,12 @@ module RuboCop
|
|
98
124
|
|
99
125
|
private
|
100
126
|
|
101
|
-
def
|
127
|
+
def find_all_explicit(node)
|
102
128
|
node.each_descendant(:block).with_object({}) do |child, h|
|
103
|
-
name =
|
129
|
+
name = yield(child)
|
104
130
|
next unless name
|
105
131
|
|
106
|
-
outer_example_group = child.each_ancestor.find do |a|
|
132
|
+
outer_example_group = child.each_ancestor(:block).find do |a|
|
107
133
|
example_group?(a)
|
108
134
|
end
|
109
135
|
|
@@ -113,14 +139,14 @@ module RuboCop
|
|
113
139
|
end
|
114
140
|
|
115
141
|
def find_subject_expectations(node, subject_names = [], &block)
|
116
|
-
subject_names =
|
142
|
+
subject_names = [*subject_names, *@explicit_subjects[node]]
|
143
|
+
subject_names -= @subject_overrides[node] if @subject_overrides[node]
|
117
144
|
|
118
|
-
|
119
|
-
|
120
|
-
end
|
145
|
+
names = Set[*subject_names, :subject]
|
146
|
+
expectation_detected = message_expectation?(node, names)
|
121
147
|
return yield(node) if expectation_detected
|
122
148
|
|
123
|
-
node.each_child_node do |child|
|
149
|
+
node.each_child_node(:send, :def, :block, :begin) do |child|
|
124
150
|
find_subject_expectations(child, subject_names, &block)
|
125
151
|
end
|
126
152
|
end
|
@@ -7,6 +7,7 @@ require_relative 'rspec/capybara/visibility_matcher'
|
|
7
7
|
require_relative 'rspec/factory_bot/attribute_defined_statically'
|
8
8
|
require_relative 'rspec/factory_bot/create_list'
|
9
9
|
require_relative 'rspec/factory_bot/factory_class_name'
|
10
|
+
require_relative 'rspec/factory_bot/syntax_methods'
|
10
11
|
|
11
12
|
require_relative 'rspec/rails/avoid_setup_hook'
|
12
13
|
begin
|
@@ -20,7 +21,9 @@ require_relative 'rspec/align_right_let_brace'
|
|
20
21
|
require_relative 'rspec/any_instance'
|
21
22
|
require_relative 'rspec/around_block'
|
22
23
|
require_relative 'rspec/be'
|
24
|
+
require_relative 'rspec/be_eq'
|
23
25
|
require_relative 'rspec/be_eql'
|
26
|
+
require_relative 'rspec/be_nil'
|
24
27
|
require_relative 'rspec/before_after_all'
|
25
28
|
require_relative 'rspec/context_method'
|
26
29
|
require_relative 'rspec/context_wording'
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
class ConfigFormatter
|
9
9
|
EXTENSION_ROOT_DEPARTMENT = %r{^(RSpec/)}.freeze
|
10
10
|
SUBDEPARTMENTS = %(RSpec/Capybara RSpec/FactoryBot RSpec/Rails)
|
11
|
-
|
11
|
+
COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/'
|
12
12
|
|
13
13
|
def initialize(config, descriptions)
|
14
14
|
@config = config
|
@@ -27,9 +27,8 @@ module RuboCop
|
|
27
27
|
cops.each_with_object(config.dup) do |cop, unified|
|
28
28
|
next if SUBDEPARTMENTS.include?(cop)
|
29
29
|
|
30
|
-
unified[cop]
|
31
|
-
|
32
|
-
.merge('StyleGuide' => STYLE_GUIDE_BASE_URL + cop.sub('RSpec/', ''))
|
30
|
+
unified[cop].merge!(descriptions.fetch(cop))
|
31
|
+
unified[cop]['Reference'] = COP_DOC_BASE_URL + cop.sub('RSpec/', '')
|
33
32
|
end
|
34
33
|
end
|
35
34
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
module FactoryBot
|
6
|
+
# Contains node matchers for common FactoryBot DSL.
|
7
|
+
module Language
|
8
|
+
extend RuboCop::NodePattern::Macros
|
9
|
+
|
10
|
+
# @!method factory_bot?(node)
|
11
|
+
def_node_matcher :factory_bot?, <<~PATTERN
|
12
|
+
(const {nil? cbase} {:FactoryGirl :FactoryBot})
|
13
|
+
PATTERN
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/rubocop-rspec.rb
CHANGED
@@ -12,11 +12,14 @@ require_relative 'rubocop/rspec/wording'
|
|
12
12
|
require_relative 'rubocop/rspec/language/node_pattern'
|
13
13
|
require_relative 'rubocop/rspec/language'
|
14
14
|
|
15
|
+
require_relative 'rubocop/rspec/factory_bot/language'
|
16
|
+
|
15
17
|
require_relative 'rubocop/cop/rspec/mixin/top_level_group'
|
16
18
|
require_relative 'rubocop/cop/rspec/mixin/variable'
|
17
19
|
require_relative 'rubocop/cop/rspec/mixin/final_end_location'
|
18
20
|
require_relative 'rubocop/cop/rspec/mixin/comments_help'
|
19
21
|
require_relative 'rubocop/cop/rspec/mixin/empty_line_separation'
|
22
|
+
require_relative 'rubocop/cop/rspec/mixin/inside_example_group'
|
20
23
|
|
21
24
|
require_relative 'rubocop/rspec/concept'
|
22
25
|
require_relative 'rubocop/rspec/example_group'
|
@@ -31,8 +34,8 @@ RuboCop::RSpec::Inject.defaults!
|
|
31
34
|
|
32
35
|
require_relative 'rubocop/cop/rspec_cops'
|
33
36
|
|
34
|
-
# We have to register our autocorrect
|
35
|
-
# so we do not hit infinite loops
|
37
|
+
# We have to register our autocorrect incompatibilities in RuboCop's cops
|
38
|
+
# as well so we do not hit infinite loops
|
36
39
|
|
37
40
|
module RuboCop
|
38
41
|
module Cop
|