升级到 2.x 版本

配置文件更新

在 2.x 版本中

  • RSpec/InvalidPredicateMatcher cop 已被移除

  • RSpec/EmptyExampleGroupCustomIncludeMethods 配置选项已移除

  • cop 部门嵌套,用于部门与扩展名不匹配的 cop (CapybaraFactoryBotRails)

  • AllCops/RSpec/Patterns/AllCops/FactoryBot/Patterns 选项已移除

  • 现在,在 cop 中定义的 #on_new_investigation 中调用 super 是强制性的。

  • 在规范中,不要定义 cop

调整 RSpec/EmptyExampleGroup 的配置。

# .rubocop.yml

# Before
RSpec/EmptyExampleGroup:
  CustomIncludeMethods:
    - include_tests

# After
RSpec:
  Language:
    Includes:
      Examples:
        - include_tests

添加一个顶级 RSpec 部门。

RuboCop 扩展包含了具有冲突名称和部门的 cop,例如,rspec-railsrubocop-rspec 都有 Rails::HttpStatus cop。为了避免问题,例如无法仅禁用其中一个 cop,每个扩展现在都有自己的顶级部门。预期地,RuboCop RSpec 的顶级部门名称为 RSpec。更改仅应用于尚未将部门设置为 RSpec 的 cop,即 CapybaraFactoryBotRails

# .rubocop.yml

# Before
Capybara/CurrentPathExpectation:
  Enabled: false

FactoryBot/AttributeDefinedStatically:
  Enabled: false

# remains the same
RSpec/EmptyExampleGroup:
  Enabled: false

# After
RSpec/Capybara/CurrentPathExpectation:
  Enabled: false

RSpec/FactoryBot/AttributeDefinedStatically:
  Enabled: false

# remains the same
RSpec/EmptyExampleGroup:
  Enabled: false

使用 RuboCop 标准 Include 选项来过滤检查的文件。

Patterns 是 RuboCop RSpec 特定的选项,RuboCop 有一个标准的替代方案。

# .rubocop.yml

# Before
AllCops:
  RSpec/FactoryBot:
    Patterns:
      - spec/factories/**/*.rb
      - property/factories/**/*.rb

# After
RSpec/FactoryBot:
  Include:
    - spec/factories/**/*.rb
    - property/factories/**/*.rb
请记住,Include 的合并模式设置为覆盖默认设置,因此,如果您打算在保留默认路径的同时添加路径,则应在配置中包含默认的 Include 路径。

自定义 Cop 更新指南

由于 API 发生了重大变化,自定义 cop 可能会中断。以下是更改的摘要。

  1. cop 的基类现在是 RuboCop::Cop::RSpec::Base,而不是 RuboCop::Cop::RSpec::Cop

  2. 模块 RuboCop::Cop::RSpec::TopLevelDescribe 被更通用的 RuboCop::Cop::RSpec::TopLevelGroup 替换。

  3. RuboCop::RSpec::Language 已完全重写,以支持动态 RSpec DSL 别名和否定匹配器,以完全支持第三方库,例如 RSpec Rails、Pundit、Action Policy 等等。

  4. RuboCop RSpec 将 RuboCop 的依赖项更新到 1.0+。

以下是将自定义 cop 更新为与 rubocop-rspec 版本 2.x 兼容的必要步骤。

更改父类

将自定义 cop 的父类从 RuboCop::Cop::RSpec::Cop 更改为 RuboCop::Cop::RSpec::Base

# Before
module RuboCop
  module Cop
    module RSpec
      class FightPowerty < Cop

# After
module RuboCop
  module Cop
    module RSpec
      class FightPowerty < Base

替换 TopLevelDescribe

TopLevelDescribe 不完整,性能很差,并且没有区分示例组和共享示例组。

TopLevelGroup 提供了类似的接口,但它不是单个 on_top_level_describe 钩子,而是两个钩子,on_top_level_example_groupon_top_level_group。目前,RuboCop 核心 cop 不需要 on_top_level_shared_group,但如果您的自定义 cop 需要这样的钩子,请随时发送拉取请求。

此外,single_top_level_describe? 已被删除,没有直接的替代方案。您可以使用 top_level_groups 查询方法,例如 top_level_groups.one?

TopLevelGroup 替换 TopLevelDescribe 的示例拉取请求 [123]。

更改 Language 模块的使用方式

为了允许延迟初始化,并在类加载后加载语言配置,使用了 RuboCop AST 的函数调用功能

RuboCop::RSpec::Language 现在完全不同了。

Hooks::ALL 及其类似项,以及它们附带的助手的工作方式不同。

# Before
def_node_matcher :shared_context,
                 SharedGroups::CONTEXT.block_pattern

# After
def_node_matcher :shared_context,
                 '(block (send #rspec? #SharedGroups.context ...) ...)'
# Before
def_node_search :examples?,
                (Includes::EXAMPLES + Examples::ALL).send_pattern

# After
def_node_search :examples?,
                '(send nil? {#Includes.examples #Examples.all} ...)'
# Before
def_node_search :find_rspec_blocks,
                ExampleGroups::ALL.block_pattern

# After
def_node_search :find_rspec_blocks,
                '(block (send #rspec? #ExampleGroups.all ...) ...)'

如果您之前直接调用 Language 元素,则需要进行相同的调整。

# Before
node&.sym_type? && Hooks::Scopes::ALL.include?(node.value)

# After
node&.sym_type? && Language::HookScopes.all(node.value)

您可能会在更改中看到一个常见的模式。不过,有一个小例外。

# Before
ExampleGroups::GROUPS

# After
ExampleGroups.regular

# Before
Examples::EXAMPLES

# After
Examples.regular

在您的 cop 中始终从 on_new_investigation 调用 super

on_new_investigation 现在用于内部目的,如果您的 cop 没有从 super 调用,则存在配置未正确加载的风险,并且动态 RSpec DSL 匹配器将无法正常工作。

除非您需要,否则您不必在您的 cop 中定义 on_new_investigation
module RuboCop
  module Cop
    module RSpec
      class MultipleMemoizedHelpers < Base
        def on_new_investigation
          super # Always call `super`
          @example_group_memoized_helpers = {}
        end
      end
    end
  end
end

在 cop 规范中使用 :config RSpec 元数据

:config 元数据应添加到 cop 规范的顶级示例组中。否则,配置将不会传递给 cop,并且动态 RSpec DSL 匹配器可能无法正常工作。

# Before
RSpec.describe 'MyMightyCop' do
  let(:cop) { described_class.new }
  # ...
end

# After
RSpec.describe 'MyMightyCop', :config do
  # `cop` is defined for you by RuboCop's shared context that is included
  # to example groups with :config metadata

  # ...
end

符合 RuboCop API 更改

父项目 RuboCop 进行了 API 更改。虽然这些更改不会导致 cop 出现故障,但建议更新 cop 以使用新的 API。请按照 RuboCop v1 更新指南 调整自定义 cop 对 RuboCop 的自动更正 API 的使用。