Skip to content
代码片段 群组 项目
提交 65a380b2 编辑于 作者: David Dieulivol's avatar David Dieulivol 提交者: Doug Stull
浏览文件

Refactor cop to support more cases

* Rename Rubocop cop
* Consider `let_it_be` aliases
  * For example: `let_it_be_with_reload`
* Ensure that example group alternatives are caught
  * For example: `it_behaves_like` and `include_examples`
上级 2d7bada3
No related branches found
No related tags found
无相关合并请求
......@@ -273,6 +273,11 @@ Naming/FileName:
- XSS
- GRPC
# Check for the use of before with let_it_be when using "add_role" methods
# e.g. add_guest, add_reporter, add_developer
RSpec/BeforeAllRoleAssignment:
Enabled: true
Rails/ApplicationRecord:
Enabled: true
Exclude:
......
此差异已折叠。
# frozen_string_literal: true
require 'rubocop-rspec'
module Rubocop
module Cop
module RSpec
# Checks for let_it_be with before instead of before_all when using `add_*` methods
#
# @example
#
# # bad
# let_it_be(:project) { create(:project) }
# let_it_be(:guest) { create(:user) }
#
# before do
# project.add_guest(guest)
# end
#
# # good
# let_it_be(:project) { create(:project) }
# let_it_be(:guest) { create(:user) }
#
# before_all do
# project.add_guest(guest)
# end
class BeforeAllRoleAssignment < RuboCop::Cop::RSpec::Base
MSG = "Use `before_all` when used with `%{let_it_be}`."
ROLE_METHODS = %i[add_guest add_reporter add_developer add_maintainer add_owner add_role].to_set.freeze
RESTRICT_ON_SEND = ROLE_METHODS
# @!method matching_let_it_be(node)
def_node_matcher :matching_let_it_be, <<~PATTERN
(block (send nil? $/^let_it_be/ (sym %name)) ...)
PATTERN
# @!method before_block?(node)
def_node_matcher :before_block?, <<~PATTERN
(block (send nil? :before ...) ...)
PATTERN
def_node_matcher :object_calling_add_role_method, <<~PATTERN
(send (send nil? $_) %ROLE_METHODS ...)
PATTERN
def on_send(node)
object_calling_add_role = object_calling_add_role_method(node)
return unless object_calling_add_role
before_block = before_block_ancestor(node)
return unless before_block
each_block_node_in_ancestor(node) do |child_node|
matching_let_it_be(child_node, name: object_calling_add_role) do |let_it_be|
message = format(MSG, let_it_be: let_it_be)
add_offense(node, message: message)
end
end
end
private
def before_block_ancestor(node)
node.each_ancestor(:block).find { |block_node| before_block?(block_node) }
end
def each_block_node_in_ancestor(node, &block)
node.each_ancestor do |parent_node|
parent_node.each_child_node(:block, &block)
end
end
end
end
end
end
# frozen_string_literal: true
require 'rubocop_spec_helper'
require 'rspec-parameterized'
require_relative '../../../../rubocop/cop/rspec/before_all_role_assignment'
RSpec.describe Rubocop::Cop::RSpec::BeforeAllRoleAssignment, :rubocop_rspec, feature_category: :tooling do
context 'with `let`' do
context 'and `before_all`' do
it 'does not register an offense' do
expect_no_offenses(<<~RUBY)
context 'with something' do
let(:project) { create(:project) }
let(:guest) { create(:user) }
before_all do
project.add_guest(guest)
end
end
RUBY
end
end
context 'and `before`' do
it 'does not register an offense' do
expect_no_offenses(<<~RUBY)
context 'with something' do
let(:project) { create(:project) }
let(:guest) { create(:user) }
before do
project.add_guest(guest)
end
end
RUBY
end
end
end
shared_examples '`let_it_be` definitions' do |let_it_be|
context 'and `before_all`' do
it 'does not register an offense' do
expect_no_offenses(<<~RUBY)
context 'with something' do
#{let_it_be}(:project) { create(:project) }
#{let_it_be}(:guest) { create(:user) }
before_all do
project.add_guest(guest)
end
end
RUBY
end
end
context 'and `before`' do
context 'and without role methods' do
it 'does not register an offense' do
expect_no_offenses(<<~RUBY)
context 'with something' do
#{let_it_be}(:project) { create(:project) }
#{let_it_be}(:guest) { create(:user) }
before do
project.add_details(guest)
end
end
RUBY
end
end
context 'and role methods' do
where(:role_method) { described_class::ROLE_METHODS.to_a }
with_them do
it 'registers an offense' do
expect_offense(<<~RUBY, role_method: role_method)
context 'with something' do
#{let_it_be}(:project) { create(:project) }
#{let_it_be}(:guest) { create(:user) }
before do
project.%{role_method}(guest)
^^^^^^^^^{role_method}^^^^^^^ Use `before_all` when used with `#{let_it_be}`.
end
end
RUBY
end
end
end
context 'without nested contexts' do
it 'registers an offense' do
expect_offense(<<~RUBY)
context 'with something' do
#{let_it_be}(:project) { create(:project) }
#{let_it_be}(:guest) { create(:user) }
before do
project.add_guest(guest)
^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`.
end
end
RUBY
end
end
context 'with nested contexts' do
it 'registers an offense' do
expect_offense(<<~RUBY)
context 'when first context' do
#{let_it_be}(:guest) { create(:user) }
context 'when second context' do
#{let_it_be}(:project) { create(:project) }
context 'when third context' do
before do
project.add_guest(guest)
^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`.
end
end
end
end
RUBY
end
end
describe 'edge cases' do
context 'with unrelated `let_it_be` definition' do
it 'does not register an offense' do
expect_no_offenses(<<~RUBY)
context 'with something' do
let(:project) { create(:project) }
#{let_it_be}(:user) { create(:user) }
before do
project.add_guest(guest)
end
end
RUBY
end
end
context 'with many role method calls' do
it 'registers an offense' do
expect_offense(<<~RUBY)
context 'with something' do
let(:project) { create(:project) }
#{let_it_be}(:other_project) { create(:user) }
before do
project.add_guest(guest)
other_project.add_guest(guest)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`.
end
end
RUBY
end
end
context 'with alternative example groups' do
it 'registers an offense' do
expect_offense(<<~RUBY)
describe 'with something' do
#{let_it_be}(:project) { create(:user) }
before do
project.add_guest(guest)
^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`.
end
end
it_behaves_like 'with something' do
#{let_it_be}(:project) { create(:user) }
before do
project.add_guest(guest)
^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`.
end
end
include_examples 'with something' do
#{let_it_be}(:project) { create(:user) }
before do
project.add_guest(guest)
^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`.
end
end
RUBY
end
end
context 'with `let_it_be` outside of the ancestors chain' do
it 'does not register an offense' do
expect_no_offenses(<<~RUBY)
context 'when in main context' do
let(:project) { create(:user) }
before do
project.add_guest(guest)
end
context 'when in a separate context' do
#{let_it_be}(:project) { create(:user) }
before do
project
end
end
end
RUBY
end
end
end
end
end
context 'with `let_it_be` variants' do
before do
other_cops.tap do |config|
config.dig('RSpec', 'Language', 'Helpers')
.push('let_it_be', 'let_it_be_with_reload', 'let_it_be_with_refind')
end
end
where(:let_it_be) { %i[let_it_be let_it_be_with_reload let_it_be_with_refind] }
with_them do
include_examples '`let_it_be` definitions', params[:let_it_be]
end
end
end
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册