rubocop-rspec 2.11.1 → 2.13.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 +125 -81
- data/config/default.yml +59 -6
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +8 -9
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +8 -9
- data/lib/rubocop/cop/rspec/any_instance.rb +1 -0
- data/lib/rubocop/cop/rspec/around_block.rb +26 -3
- data/lib/rubocop/cop/rspec/be.rb +0 -1
- data/lib/rubocop/cop/rspec/be_eq.rb +0 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +0 -1
- data/lib/rubocop/cop/rspec/before_after_all.rb +1 -0
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +9 -3
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +2 -1
- data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +86 -0
- data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +158 -0
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -1
- data/lib/rubocop/cop/rspec/change_by_zero.rb +67 -7
- data/lib/rubocop/cop/rspec/class_check.rb +101 -0
- data/lib/rubocop/cop/rspec/context_method.rb +2 -1
- data/lib/rubocop/cop/rspec/context_wording.rb +49 -18
- data/lib/rubocop/cop/rspec/describe_class.rb +1 -1
- data/lib/rubocop/cop/rspec/describe_method.rb +1 -0
- data/lib/rubocop/cop/rspec/described_class.rb +5 -15
- data/lib/rubocop/cop/rspec/dialect.rb +1 -0
- data/lib/rubocop/cop/rspec/empty_example_group.rb +19 -4
- data/lib/rubocop/cop/rspec/empty_hook.rb +4 -5
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +4 -9
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +2 -1
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +32 -2
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +2 -1
- data/lib/rubocop/cop/rspec/example_length.rb +3 -2
- data/lib/rubocop/cop/rspec/example_without_description.rb +3 -2
- data/lib/rubocop/cop/rspec/example_wording.rb +2 -1
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +5 -0
- data/lib/rubocop/cop/rspec/expect_change.rb +9 -9
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +4 -1
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -0
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +2 -1
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +50 -13
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +1 -0
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +1 -1
- data/lib/rubocop/cop/rspec/file_path.rb +8 -4
- data/lib/rubocop/cop/rspec/focus.rb +20 -4
- data/lib/rubocop/cop/rspec/hook_argument.rb +10 -5
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +10 -9
- data/lib/rubocop/cop/rspec/identical_equality_assertion.rb +0 -1
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -3
- data/lib/rubocop/cop/rspec/instance_spy.rb +1 -1
- data/lib/rubocop/cop/rspec/instance_variable.rb +0 -1
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +3 -2
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +16 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +15 -15
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
- data/lib/rubocop/cop/rspec/let_before_examples.rb +7 -8
- data/lib/rubocop/cop/rspec/let_setup.rb +4 -4
- data/lib/rubocop/cop/rspec/message_chain.rb +1 -1
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/message_spies.rb +7 -1
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +2 -1
- data/lib/rubocop/cop/rspec/mixin/css_selector.rb +99 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +13 -4
- data/lib/rubocop/cop/rspec/mixin/namespace.rb +23 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -0
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +19 -3
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +1 -3
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +17 -2
- data/lib/rubocop/cop/rspec/named_subject.rb +2 -1
- data/lib/rubocop/cop/rspec/nested_groups.rb +45 -25
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +64 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +13 -1
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +2 -1
- data/lib/rubocop/cop/rspec/pending.rb +1 -0
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +2 -1
- data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +1 -2
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +47 -0
- data/lib/rubocop/cop/rspec/receive_counts.rb +14 -15
- data/lib/rubocop/cop/rspec/receive_never.rb +4 -5
- data/lib/rubocop/cop/rspec/repeated_description.rb +25 -26
- data/lib/rubocop/cop/rspec/repeated_example.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +28 -29
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +28 -29
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +32 -33
- data/lib/rubocop/cop/rspec/return_from_stub.rb +12 -12
- data/lib/rubocop/cop/rspec/scattered_let.rb +1 -5
- data/lib/rubocop/cop/rspec/scattered_setup.rb +2 -2
- data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +0 -1
- data/lib/rubocop/cop/rspec/subject_declaration.rb +0 -1
- data/lib/rubocop/cop/rspec/subject_stub.rb +2 -2
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +15 -15
- data/lib/rubocop/cop/rspec/variable_definition.rb +1 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +6 -7
- data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -0
- data/lib/rubocop/cop/rspec/void_expect.rb +2 -1
- data/lib/rubocop/cop/rspec/yield.rb +3 -2
- data/lib/rubocop/cop/rspec_cops.rb +5 -0
- data/lib/rubocop/rspec/config_formatter.rb +14 -3
- data/lib/rubocop/rspec/inject.rb +1 -3
- data/lib/rubocop/rspec/language/node_pattern.rb +4 -0
- data/lib/rubocop/rspec/language.rb +6 -1
- data/lib/rubocop/rspec/node.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +2 -2
- data/lib/rubocop/rspec.rb +14 -0
- data/lib/rubocop-rspec.rb +3 -0
- metadata +12 -88
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
# styles: "implicit", "each", and "example." All styles have
|
11
11
|
# the same behavior.
|
12
12
|
#
|
13
|
-
# @example
|
13
|
+
# @example `EnforcedStyle: implicit` (default)
|
14
14
|
# # bad
|
15
15
|
# before(:each) do
|
16
16
|
# # ...
|
@@ -26,7 +26,7 @@ module RuboCop
|
|
26
26
|
# # ...
|
27
27
|
# end
|
28
28
|
#
|
29
|
-
# @example
|
29
|
+
# @example `EnforcedStyle: each`
|
30
30
|
# # bad
|
31
31
|
# before(:example) do
|
32
32
|
# # ...
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
# # ...
|
43
43
|
# end
|
44
44
|
#
|
45
|
-
# @example
|
45
|
+
# @example `EnforcedStyle: example`
|
46
46
|
# # bad
|
47
47
|
# before(:each) do
|
48
48
|
# # ...
|
@@ -57,6 +57,7 @@ module RuboCop
|
|
57
57
|
# before(:example) do
|
58
58
|
# # ...
|
59
59
|
# end
|
60
|
+
#
|
60
61
|
class HookArgument < Base
|
61
62
|
extend AutoCorrector
|
62
63
|
include ConfigurableEnforcedStyle
|
@@ -66,11 +67,13 @@ module RuboCop
|
|
66
67
|
|
67
68
|
# @!method scoped_hook(node)
|
68
69
|
def_node_matcher :scoped_hook, <<-PATTERN
|
69
|
-
(block $(send _ #Hooks.all (sym ${:each :example})) ...)
|
70
|
+
({block numblock} $(send _ #Hooks.all (sym ${:each :example})) ...)
|
70
71
|
PATTERN
|
71
72
|
|
72
73
|
# @!method unscoped_hook(node)
|
73
|
-
def_node_matcher :unscoped_hook,
|
74
|
+
def_node_matcher :unscoped_hook, <<-PATTERN
|
75
|
+
({block numblock} $(send _ #Hooks.all) ...)
|
76
|
+
PATTERN
|
74
77
|
|
75
78
|
def on_block(node)
|
76
79
|
hook(node) do |method_send, scope_name|
|
@@ -86,6 +89,8 @@ module RuboCop
|
|
86
89
|
end
|
87
90
|
end
|
88
91
|
|
92
|
+
alias on_numblock on_block
|
93
|
+
|
89
94
|
private
|
90
95
|
|
91
96
|
def check_implicit(method_send)
|
@@ -6,8 +6,7 @@ module RuboCop
|
|
6
6
|
# Checks for before/around/after hooks that come after an example.
|
7
7
|
#
|
8
8
|
# @example
|
9
|
-
# #
|
10
|
-
#
|
9
|
+
# # bad
|
11
10
|
# it 'checks what foo does' do
|
12
11
|
# expect(foo).to be
|
13
12
|
# end
|
@@ -15,7 +14,7 @@ module RuboCop
|
|
15
14
|
# before { prepare }
|
16
15
|
# after { clean_up }
|
17
16
|
#
|
18
|
-
# #
|
17
|
+
# # good
|
19
18
|
# before { prepare }
|
20
19
|
# after { clean_up }
|
21
20
|
#
|
@@ -32,6 +31,7 @@ module RuboCop
|
|
32
31
|
def_node_matcher :example_or_group?, <<-PATTERN
|
33
32
|
{
|
34
33
|
#{block_pattern('{#ExampleGroups.all #Examples.all}')}
|
34
|
+
#{numblock_pattern('{#ExampleGroups.all #Examples.all}')}
|
35
35
|
#{send_pattern('#Includes.examples')}
|
36
36
|
}
|
37
37
|
PATTERN
|
@@ -42,6 +42,8 @@ module RuboCop
|
|
42
42
|
check_hooks(node.body) if multiline_block?(node.body)
|
43
43
|
end
|
44
44
|
|
45
|
+
alias on_numblock on_block
|
46
|
+
|
45
47
|
private
|
46
48
|
|
47
49
|
def multiline_block?(block)
|
@@ -52,13 +54,12 @@ module RuboCop
|
|
52
54
|
first_example = find_first_example(node)
|
53
55
|
return unless first_example
|
54
56
|
|
55
|
-
|
56
|
-
next
|
57
|
-
next unless hook?(child)
|
57
|
+
first_example.right_siblings.each do |sibling|
|
58
|
+
next unless hook?(sibling)
|
58
59
|
|
59
|
-
msg = format(MSG, hook:
|
60
|
-
add_offense(
|
61
|
-
autocorrect(corrector,
|
60
|
+
msg = format(MSG, hook: sibling.method_name)
|
61
|
+
add_offense(sibling, message: msg) do |corrector|
|
62
|
+
autocorrect(corrector, sibling, first_example)
|
62
63
|
end
|
63
64
|
end
|
64
65
|
end
|
@@ -16,6 +16,7 @@ module RuboCop
|
|
16
16
|
# it 'changes something to a new value' do
|
17
17
|
# expect { do_something }.to change(something).to(new_value)
|
18
18
|
# end
|
19
|
+
#
|
19
20
|
class ImplicitBlockExpectation < Base
|
20
21
|
MSG = 'Avoid implicit block expectations.'
|
21
22
|
RESTRICT_ON_SEND = %i[is_expected should should_not].freeze
|
@@ -8,8 +8,7 @@ module RuboCop
|
|
8
8
|
# This cop can be configured using the `EnforcedStyle` option
|
9
9
|
# and supports the `--auto-gen-config` flag.
|
10
10
|
#
|
11
|
-
# @example `EnforcedStyle: is_expected`
|
12
|
-
#
|
11
|
+
# @example `EnforcedStyle: is_expected` (default)
|
13
12
|
# # bad
|
14
13
|
# it { should be_truthy }
|
15
14
|
#
|
@@ -17,7 +16,6 @@ module RuboCop
|
|
17
16
|
# it { is_expected.to be_truthy }
|
18
17
|
#
|
19
18
|
# @example `EnforcedStyle: should`
|
20
|
-
#
|
21
19
|
# # bad
|
22
20
|
# it { is_expected.to be_truthy }
|
23
21
|
#
|
@@ -5,19 +5,20 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks that only one `it_behaves_like` style is used.
|
7
7
|
#
|
8
|
-
# @example
|
8
|
+
# @example `EnforcedStyle: it_behaves_like` (default)
|
9
9
|
# # bad
|
10
10
|
# it_should_behave_like 'a foo'
|
11
11
|
#
|
12
12
|
# # good
|
13
13
|
# it_behaves_like 'a foo'
|
14
14
|
#
|
15
|
-
# @example
|
15
|
+
# @example `EnforcedStyle: it_should_behave_like`
|
16
16
|
# # bad
|
17
17
|
# it_behaves_like 'a foo'
|
18
18
|
#
|
19
19
|
# # good
|
20
20
|
# it_should_behave_like 'a foo'
|
21
|
+
#
|
21
22
|
class ItBehavesLike < Base
|
22
23
|
extend AutoCorrector
|
23
24
|
include ConfigurableEnforcedStyle
|
@@ -15,6 +15,7 @@ module RuboCop
|
|
15
15
|
# it 'validates users' do
|
16
16
|
# expect([user1, user2, user3]).to all(be_valid)
|
17
17
|
# end
|
18
|
+
#
|
18
19
|
class IteratedExpectation < Base
|
19
20
|
MSG = 'Prefer using the `all` matcher instead ' \
|
20
21
|
'of iterating over an array.'
|
@@ -28,6 +29,13 @@ module RuboCop
|
|
28
29
|
)
|
29
30
|
PATTERN
|
30
31
|
|
32
|
+
# @!method each_numblock?(node)
|
33
|
+
def_node_matcher :each_numblock?, <<-PATTERN
|
34
|
+
(numblock
|
35
|
+
(send ... :each) _ $(...)
|
36
|
+
)
|
37
|
+
PATTERN
|
38
|
+
|
31
39
|
# @!method expectation?(node)
|
32
40
|
def_node_matcher :expectation?, <<-PATTERN
|
33
41
|
(send (send nil? :expect (lvar %)) :to ...)
|
@@ -41,6 +49,14 @@ module RuboCop
|
|
41
49
|
end
|
42
50
|
end
|
43
51
|
|
52
|
+
def on_numblock(node)
|
53
|
+
each_numblock?(node) do |body|
|
54
|
+
if single_expectation?(body, :_1) || only_expectations?(body, :_1)
|
55
|
+
add_offense(node.send_node)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
44
60
|
private
|
45
61
|
|
46
62
|
def single_expectation?(body, arg)
|
@@ -7,29 +7,29 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
# # bad
|
10
|
-
#
|
11
|
-
#
|
10
|
+
# let(:params) { blah }
|
11
|
+
# subject { described_class.new(params) }
|
12
12
|
#
|
13
|
-
#
|
14
|
-
#
|
13
|
+
# before { do_something }
|
14
|
+
# subject { described_class.new(params) }
|
15
15
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
16
|
+
# it { expect_something }
|
17
|
+
# subject { described_class.new(params) }
|
18
|
+
# it { expect_something_else }
|
19
19
|
#
|
20
20
|
#
|
21
21
|
# # good
|
22
|
-
#
|
23
|
-
#
|
22
|
+
# subject { described_class.new(params) }
|
23
|
+
# let(:params) { blah }
|
24
24
|
#
|
25
25
|
# # good
|
26
|
-
#
|
27
|
-
#
|
26
|
+
# subject { described_class.new(params) }
|
27
|
+
# before { do_something }
|
28
28
|
#
|
29
29
|
# # good
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
30
|
+
# subject { described_class.new(params) }
|
31
|
+
# it { expect_something }
|
32
|
+
# it { expect_something_else }
|
33
33
|
#
|
34
34
|
class LeadingSubject < Base
|
35
35
|
extend AutoCorrector
|
@@ -37,7 +37,7 @@ module RuboCop
|
|
37
37
|
|
38
38
|
MSG = 'Declare `subject` above any other `%<offending>s` declarations.'
|
39
39
|
|
40
|
-
def on_block(node)
|
40
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
41
41
|
return unless subject?(node)
|
42
42
|
return unless inside_example_group?(node)
|
43
43
|
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
#
|
11
11
|
# If several examples may define a `DummyClass`, instead of being a
|
12
12
|
# blank slate class as it will be in the first example, subsequent
|
13
|
-
# examples will be reopening it and modifying its
|
13
|
+
# examples will be reopening it and modifying its behavior in
|
14
14
|
# unpredictable ways.
|
15
15
|
# Even worse when a class that exists in the codebase is reopened.
|
16
16
|
#
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
# Checks for `let` definitions that come after an example.
|
7
7
|
#
|
8
8
|
# @example
|
9
|
-
# #
|
9
|
+
# # bad
|
10
10
|
# let(:foo) { bar }
|
11
11
|
#
|
12
12
|
# it 'checks what foo does' do
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
# expect(some).to be
|
20
20
|
# end
|
21
21
|
#
|
22
|
-
# #
|
22
|
+
# # good
|
23
23
|
# let(:foo) { bar }
|
24
24
|
# let(:some) { other }
|
25
25
|
#
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
}
|
44
44
|
PATTERN
|
45
45
|
|
46
|
-
def on_block(node)
|
46
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
47
47
|
return unless example_group_with_body?(node)
|
48
48
|
|
49
49
|
check_let_declarations(node.body) if multiline_block?(node.body)
|
@@ -59,12 +59,11 @@ module RuboCop
|
|
59
59
|
first_example = find_first_example(node)
|
60
60
|
return unless first_example
|
61
61
|
|
62
|
-
|
63
|
-
next
|
64
|
-
next unless let?(child)
|
62
|
+
first_example.right_siblings.each do |sibling|
|
63
|
+
next unless let?(sibling)
|
65
64
|
|
66
|
-
add_offense(
|
67
|
-
autocorrect(corrector,
|
65
|
+
add_offense(sibling) do |corrector|
|
66
|
+
autocorrect(corrector, sibling, first_example)
|
68
67
|
end
|
69
68
|
end
|
70
69
|
end
|
@@ -6,20 +6,20 @@ module RuboCop
|
|
6
6
|
# Checks unreferenced `let!` calls being used for test setup.
|
7
7
|
#
|
8
8
|
# @example
|
9
|
-
# #
|
9
|
+
# # bad
|
10
10
|
# let!(:my_widget) { create(:widget) }
|
11
11
|
#
|
12
12
|
# it 'counts widgets' do
|
13
13
|
# expect(Widget.count).to eq(1)
|
14
14
|
# end
|
15
15
|
#
|
16
|
-
# #
|
16
|
+
# # good
|
17
17
|
# it 'counts widgets' do
|
18
18
|
# create(:widget)
|
19
19
|
# expect(Widget.count).to eq(1)
|
20
20
|
# end
|
21
21
|
#
|
22
|
-
# #
|
22
|
+
# # good
|
23
23
|
# before { create(:widget) }
|
24
24
|
#
|
25
25
|
# it 'counts widgets' do
|
@@ -49,7 +49,7 @@ module RuboCop
|
|
49
49
|
# @!method method_called?(node)
|
50
50
|
def_node_search :method_called?, '(send nil? %)'
|
51
51
|
|
52
|
-
def on_block(node)
|
52
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
53
53
|
return unless example_or_shared_group_or_including?(node)
|
54
54
|
|
55
55
|
unused_let_bang(node) do |let|
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
# This cop can be configured in your configuration using the
|
9
9
|
# `EnforcedStyle` option and supports `--auto-gen-config`.
|
10
10
|
#
|
11
|
-
# @example `EnforcedStyle: allow`
|
11
|
+
# @example `EnforcedStyle: allow` (default)
|
12
12
|
#
|
13
13
|
# # bad
|
14
14
|
# expect(foo).to receive(:bar)
|
@@ -8,21 +8,27 @@ module RuboCop
|
|
8
8
|
# This cop can be configured in your configuration using the
|
9
9
|
# `EnforcedStyle` option and supports `--auto-gen-config`.
|
10
10
|
#
|
11
|
-
# @example `EnforcedStyle: have_received`
|
11
|
+
# @example `EnforcedStyle: have_received` (default)
|
12
12
|
#
|
13
13
|
# # bad
|
14
14
|
# expect(foo).to receive(:bar)
|
15
|
+
# do_something
|
15
16
|
#
|
16
17
|
# # good
|
18
|
+
# allow(foo).to receive(:bar) # or use instance_spy
|
19
|
+
# do_something
|
17
20
|
# expect(foo).to have_received(:bar)
|
18
21
|
#
|
19
22
|
# @example `EnforcedStyle: receive`
|
20
23
|
#
|
21
24
|
# # bad
|
25
|
+
# allow(foo).to receive(:bar)
|
26
|
+
# do_something
|
22
27
|
# expect(foo).to have_received(:bar)
|
23
28
|
#
|
24
29
|
# # good
|
25
30
|
# expect(foo).to receive(:bar)
|
31
|
+
# do_something
|
26
32
|
#
|
27
33
|
class MessageSpies < Base
|
28
34
|
include ConfigurableEnforcedStyle
|
@@ -19,10 +19,11 @@ module RuboCop
|
|
19
19
|
#
|
20
20
|
# describe "A feature example" do
|
21
21
|
# end
|
22
|
+
#
|
22
23
|
class MissingExampleGroupArgument < Base
|
23
24
|
MSG = 'The first argument to `%<method>s` should not be empty.'
|
24
25
|
|
25
|
-
def on_block(node)
|
26
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
26
27
|
return unless example_group?(node)
|
27
28
|
return if node.send_node.arguments?
|
28
29
|
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps parsing css selector.
|
7
|
+
module CssSelector
|
8
|
+
COMMON_OPTIONS = %w[
|
9
|
+
above below left_of right_of near count minimum maximum between text
|
10
|
+
id class style visible obscured exact exact_text normalize_ws match
|
11
|
+
wait filter_set focused
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
module_function
|
15
|
+
|
16
|
+
# @param selector [String]
|
17
|
+
# @return [Boolean]
|
18
|
+
# @example
|
19
|
+
# id?('#some-id') # => true
|
20
|
+
# id?('.some-class') # => false
|
21
|
+
def id?(selector)
|
22
|
+
selector.start_with?('#')
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param selector [String]
|
26
|
+
# @return [Boolean]
|
27
|
+
# @example
|
28
|
+
# attribute?('[attribute]') # => true
|
29
|
+
# attribute?('attribute') # => false
|
30
|
+
def attribute?(selector)
|
31
|
+
selector.start_with?('[')
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param selector [String]
|
35
|
+
# @return [Array<String>]
|
36
|
+
# @example
|
37
|
+
# attributes('a[foo-bar_baz]') # => {"foo-bar_baz=>true}
|
38
|
+
# attributes('button[foo][bar]') # => {"foo"=>true, "bar"=>true}
|
39
|
+
# attributes('table[foo=bar]') # => {"foo"=>"'bar'"}
|
40
|
+
def attributes(selector)
|
41
|
+
selector.scan(/\[(.*?)\]/).flatten.to_h do |attr|
|
42
|
+
key, value = attr.split('=')
|
43
|
+
[key, normalize_value(value)]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param selector [String]
|
48
|
+
# @return [Boolean]
|
49
|
+
# @example
|
50
|
+
# common_attributes?('a[focused]') # => true
|
51
|
+
# common_attributes?('button[focused][visible]') # => true
|
52
|
+
# common_attributes?('table[id=some-id]') # => true
|
53
|
+
# common_attributes?('h1[invalid]') # => false
|
54
|
+
def common_attributes?(selector)
|
55
|
+
attributes(selector).keys.difference(COMMON_OPTIONS).none?
|
56
|
+
end
|
57
|
+
|
58
|
+
# @param selector [String]
|
59
|
+
# @return [Array<String>]
|
60
|
+
# @example
|
61
|
+
# pseudo_classes('button:not([disabled])') # => ['not()']
|
62
|
+
# pseudo_classes('a:enabled:not([valid])') # => ['enabled', 'not()']
|
63
|
+
def pseudo_classes(selector)
|
64
|
+
# Attributes must be excluded or else the colon in the `href`s URL
|
65
|
+
# will also be picked up as pseudo classes.
|
66
|
+
# "a:not([href='http://example.com']):enabled" => "a:not():enabled"
|
67
|
+
ignored_attribute = selector.gsub(/\[.*?\]/, '')
|
68
|
+
# "a:not():enabled" => ["not()", "enabled"]
|
69
|
+
ignored_attribute.scan(/:([^:]*)/).flatten
|
70
|
+
end
|
71
|
+
|
72
|
+
# @param selector [String]
|
73
|
+
# @return [Boolean]
|
74
|
+
# @example
|
75
|
+
# multiple_selectors?('a.cls b#id') # => true
|
76
|
+
# multiple_selectors?('a.cls') # => false
|
77
|
+
def multiple_selectors?(selector)
|
78
|
+
selector.match?(/[ >,+]/)
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param value [String]
|
82
|
+
# @return [Boolean, String]
|
83
|
+
# @example
|
84
|
+
# normalize_value('true') # => true
|
85
|
+
# normalize_value('false') # => false
|
86
|
+
# normalize_value(nil) # => false
|
87
|
+
# normalize_value("foo") # => "'foo'"
|
88
|
+
def normalize_value(value)
|
89
|
+
case value
|
90
|
+
when 'true' then true
|
91
|
+
when 'false' then false
|
92
|
+
when nil then true
|
93
|
+
else "'#{value}'"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -4,7 +4,10 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
6
|
# Helps determine the offending location if there is not an empty line
|
7
|
-
# following the node. Allows comments to follow directly after
|
7
|
+
# following the node. Allows comments to follow directly after
|
8
|
+
# in the following cases.
|
9
|
+
# - `rubocop:enable` directive
|
10
|
+
# - followed by empty line(s)
|
8
11
|
module EmptyLineSeparation
|
9
12
|
include FinalEndLocation
|
10
13
|
include RangeHelp
|
@@ -21,13 +24,19 @@ module RuboCop
|
|
21
24
|
end
|
22
25
|
|
23
26
|
def missing_separating_line(node)
|
24
|
-
line = final_end_location(node).line
|
27
|
+
line = final_end_line = final_end_location(node).line
|
25
28
|
|
26
|
-
|
29
|
+
while comment_line?(processed_source[line])
|
30
|
+
line += 1
|
31
|
+
comment = processed_source.comment_at_line(line)
|
32
|
+
if DirectiveComment.new(comment).enabled?
|
33
|
+
enable_directive_line = line
|
34
|
+
end
|
35
|
+
end
|
27
36
|
|
28
37
|
return if processed_source[line].blank?
|
29
38
|
|
30
|
-
yield offending_loc(
|
39
|
+
yield offending_loc(enable_directive_line || final_end_line)
|
31
40
|
end
|
32
41
|
|
33
42
|
def offending_loc(last_line)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps to find namespace of the node.
|
7
|
+
module Namespace
|
8
|
+
private
|
9
|
+
|
10
|
+
# @param node [RuboCop::AST::Node]
|
11
|
+
# @return [Array<String>]
|
12
|
+
# @example
|
13
|
+
# namespace(node) # => ['A', 'B', 'C']
|
14
|
+
def namespace(node)
|
15
|
+
node
|
16
|
+
.each_ancestor(:class, :module)
|
17
|
+
.reverse_each
|
18
|
+
.flat_map { |ancestor| ancestor.defined_module_name.split('::') }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -11,7 +11,6 @@ module RuboCop
|
|
11
11
|
# and works with `--auto-gen-config`.
|
12
12
|
#
|
13
13
|
# @example
|
14
|
-
#
|
15
14
|
# # bad
|
16
15
|
# describe UserCreator do
|
17
16
|
# it 'builds a user' do
|
@@ -31,8 +30,25 @@ module RuboCop
|
|
31
30
|
# end
|
32
31
|
# end
|
33
32
|
#
|
34
|
-
# @example
|
33
|
+
# @example `aggregate_failures: true` (default)
|
34
|
+
# # good - the cop ignores when RSpec aggregates failures
|
35
|
+
# describe UserCreator do
|
36
|
+
# it 'builds a user', :aggregate_failures do
|
37
|
+
# expect(user.name).to eq("John")
|
38
|
+
# expect(user.age).to eq(22)
|
39
|
+
# end
|
40
|
+
# end
|
35
41
|
#
|
42
|
+
# @example `aggregate_failures: false`
|
43
|
+
# # Detected as an offense
|
44
|
+
# describe UserCreator do
|
45
|
+
# it 'builds a user', aggregate_failures: false do
|
46
|
+
# expect(user.name).to eq("John")
|
47
|
+
# expect(user.age).to eq(22)
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# @example configuration
|
36
52
|
# # .rubocop.yml
|
37
53
|
# # RSpec/MultipleExpectations:
|
38
54
|
# # Max: 2
|
@@ -68,7 +84,7 @@ module RuboCop
|
|
68
84
|
(block (send nil? :aggregate_failures ...) ...)
|
69
85
|
PATTERN
|
70
86
|
|
71
|
-
def on_block(node)
|
87
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
72
88
|
return unless example?(node)
|
73
89
|
|
74
90
|
return if example_with_aggregate_failures?(node)
|
@@ -56,7 +56,6 @@ module RuboCop
|
|
56
56
|
# end
|
57
57
|
#
|
58
58
|
# @example when disabling AllowSubject configuration
|
59
|
-
#
|
60
59
|
# # rubocop.yml
|
61
60
|
# # RSpec/MultipleMemoizedHelpers:
|
62
61
|
# # AllowSubject: false
|
@@ -72,7 +71,6 @@ module RuboCop
|
|
72
71
|
# end
|
73
72
|
#
|
74
73
|
# @example with Max configuration
|
75
|
-
#
|
76
74
|
# # rubocop.yml
|
77
75
|
# # RSpec/MultipleMemoizedHelpers:
|
78
76
|
# # Max: 1
|
@@ -89,7 +87,7 @@ module RuboCop
|
|
89
87
|
|
90
88
|
MSG = 'Example group has too many memoized helpers [%<count>d/%<max>d]'
|
91
89
|
|
92
|
-
def on_block(node)
|
90
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
93
91
|
return unless spec_group?(node)
|
94
92
|
|
95
93
|
count = all_helpers(node).uniq.count
|