Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,4 @@ Performance/ZipWithoutBlock: {Enabled: true}

RSpec/IncludeExamples: {Enabled: true}
RSpec/LeakyLocalVariable: {Enabled: true}
RSpec/RedundantPending: {Enabled: false}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
RSpec/RedundantPending: {Enabled: false}
RSpec/RedundantPending: {Enabled: true}

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Master (Unreleased)

- Add new cop `RSpec/LeakyLocalVariable`. ([@lovro-bikic])
- Add new cop `RSpec/RedundantPending`. ([@ydah])
- Bump RuboCop requirement to +1.81. ([@ydah])
- Fix a false positive for `RSpec/LetSetup` when `let!` used in outer scope. ([@ydah])

Expand Down
6 changes: 6 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,12 @@ RSpec/RedundantAround:
VersionAdded: '2.19'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantAround

RSpec/RedundantPending:
Description: Checks for redundant `pending` or `skip` inside skipped examples.
Enabled: pending
VersionAdded: "<<next>>"
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantPending

RSpec/RedundantPredicateMatcher:
Description: Checks for redundant predicate matcher.
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
* xref:cops_rspec.adoc#rspecreceivemessages[RSpec/ReceiveMessages]
* xref:cops_rspec.adoc#rspecreceivenever[RSpec/ReceiveNever]
* xref:cops_rspec.adoc#rspecredundantaround[RSpec/RedundantAround]
* xref:cops_rspec.adoc#rspecredundantpending[RSpec/RedundantPending]
* xref:cops_rspec.adoc#rspecredundantpredicatematcher[RSpec/RedundantPredicateMatcher]
* xref:cops_rspec.adoc#rspecremoveconst[RSpec/RemoveConst]
* xref:cops_rspec.adoc#rspecrepeateddescription[RSpec/RepeatedDescription]
Expand Down
70 changes: 70 additions & 0 deletions docs/modules/ROOT/pages/cops_rspec.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5156,6 +5156,76 @@ end

* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantAround

[#rspecredundantpending]
== RSpec/RedundantPending

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| No
| <<next>>
| -
|===

Checks for redundant `pending` or `skip` inside skipped examples.

When an example is already skipped using `xit`, `xspecify`, `xexample`,
or `skip` metadata, adding `pending` or `skip` inside the example body
is redundant.

[#examples-rspecredundantpending]
=== Examples

[source,ruby]
----
# bad
xit 'does something' do
pending 'not yet implemented'
expect(something).to be_truthy
end

# bad
xspecify do
pending 'not yet implemented'
expect(something).to be_truthy
end

# bad
it 'does something', :skip do
pending 'not yet implemented'
expect(something).to be_truthy
end

# bad
it 'does something', skip: true do
skip 'not yet implemented'
expect(something).to be_truthy
end

# good
xit 'does something' do
expect(something).to be_truthy
end

# good
it 'does something', skip: 'not yet implemented' do
expect(something).to be_truthy
end

# good
it 'does something' do
pending 'not yet implemented'
expect(something).to be_truthy
end
----

[#references-rspecredundantpending]
=== References

* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantPending

[#rspecredundantpredicatematcher]
== RSpec/RedundantPredicateMatcher

Expand Down
106 changes: 106 additions & 0 deletions lib/rubocop/cop/rspec/redundant_pending.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# frozen_string_literal: true

module RuboCop
module Cop
module RSpec
# Checks for redundant `pending` or `skip` inside skipped examples.
#
# When an example is already skipped using `xit`, `xspecify`, `xexample`,
# or `skip` metadata, adding `pending` or `skip` inside the example body
# is redundant.
#
# @example
# # bad
# xit 'does something' do
# pending 'not yet implemented'
# expect(something).to be_truthy
# end
#
# # bad
# xspecify do
# pending 'not yet implemented'
# expect(something).to be_truthy
# end
#
# # bad
# it 'does something', :skip do
# pending 'not yet implemented'
# expect(something).to be_truthy
# end
#
# # bad
# it 'does something', skip: true do
# skip 'not yet implemented'
# expect(something).to be_truthy
# end
#
# # good
# xit 'does something' do
# expect(something).to be_truthy
# end
#
# # good
# it 'does something', skip: 'not yet implemented' do
# expect(something).to be_truthy
# end
#
# # good
# it 'does something' do
# pending 'not yet implemented'
# expect(something).to be_truthy
# end
#
class RedundantPending < Base
MSG = 'Redundant `%<method>s` inside already skipped example. ' \
'Remove `%<method>s` or use regular example method.'

# @!method skipped_example?(node)
def_node_matcher :skipped_example?, <<~PATTERN
{
(any_block (send _ #Examples.skipped ...) ...)
}
PATTERN

# @!method skipped_by_metadata?(node)
def_node_matcher :skipped_by_metadata?, <<~PATTERN
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reuse skipped_in_metadata? from the SkipOrPending mixin?

{
(any_block (send _ #Examples.all ... <(sym {:skip :pending}) ...>) ...)
(any_block (send _ #Examples.all ... (hash <(pair (sym {:skip :pending}) !false) ...>)) ...)
}
PATTERN

# @!method pending_or_skip_call?(node)
def_node_matcher :pending_or_skip_call?, <<~PATTERN
(send nil? ${:pending :skip} ...)
PATTERN

def on_block(node)
check_example(node)
end
alias on_numblock on_block

private

def check_example(node)
return unless skipped_example?(node) || skipped_by_metadata?(node)
return unless node.body

find_pending_or_skip(node.body) do |method_name|
message = format(MSG, method: method_name)
add_offense(node.body, message: message)
end
end

def find_pending_or_skip(body, &block)
first_statement = if body.begin_type?
body.children.first
else
body
end

pending_or_skip_call?(first_statement, &block)
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/rspec_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
require_relative 'rspec/receive_messages'
require_relative 'rspec/receive_never'
require_relative 'rspec/redundant_around'
require_relative 'rspec/redundant_pending'
require_relative 'rspec/redundant_predicate_matcher'
require_relative 'rspec/remove_const'
require_relative 'rspec/repeated_description'
Expand Down
Loading