在 Rails 引擎中 Rspec 是否可以使用来自另一个引擎的 Rspec 支持系统助手?

In a Rails engine Is it possible for Rspec to make use of Rspec support system helpers from another engine?

假设 Rails engine_one 具有规范支持文件 engine_one/spec/support/system/order_functions.rb,包含支持各种订单系统测试的功能,例如模拟登录用户、添加产品到订单等,并包含在测试订单处理等时广泛使用的 log_visitor_in 等方法...

所以现在 engine_two 扩展了 engine_one 的一些订购功能,我希望添加一个新的系统测试,首先必须让访问者登录。那么我如何利用该支持来自 engine_one?

的方法

到目前为止,我已经在虚拟应用程序中安装了引擎 我在 engine_two/lib/engine.rb 中要求 engine_one 我在相关测试中需要支持文件,但找不到,显然我已经将 engine_one 添加到 engine_two.gemspec

engine_two/spec/rails_helper.rb

require 'engine_one' # and any other gems you need

engine_two/lib/engine_two/engine.rb

require 'engine_one'

在相关系统测试中我有以下

engine_two/spec/system/new_payment_methods_spec.rb

require 'rails_helper'
include EngineOne::System

    RSpec.describe "order_payment_feature", type: :system do
      before do
        driven_by(:rack_test)
      end
    
      it "has order payment options" do
        log_visitor_in
      end
    end

这会导致以下错误

Failure/Error: include EngineOne::System

NameError:
  uninitialized constant EngineOne::System
  Did you mean?  SystemExit

还有帮手

module System
  def log_visitor_in()
    administrator = create(:visitor)
    visit ccs_cms.login_url
    fill_in 'login_name', with: visitor.login_name
    fill_in 'Password', with: visitor.password
    click_button 'Login'
  end

end

我尝试使用 require 而不是 include,但这会导致文件未找到错误 另外,我尝试将包含路径更改为

include EngineOne::Spec::Support::System 导致同样的错误

所以我想我正在寻找正确的路径,但我被卡住了或错过了一些其他方式来包含帮助程序。 这些是 Rails 7 个引擎。

当您 require 一个文件时,ruby 会根据 $LOAD_PATH 中的路径搜索它; spec/ 或 test/ 不是其中的一部分。

app目录是rails中的特殊目录,任何子目录自动成为autoload_paths的一部分。可以在这里看到自动加载路径 ActiveSupport::Dependencies.autoload_paths.

app/* 目录中定义的任何 classes/modules 都可以使用,不需要相应的文件。 Rails v7 使用 zeitwerk 依靠 'file name' 到 'constant name' 的关系自动 load/reload 文件。这就是文件夹映射到命名空间而文件映射到 classes/modules.

的原因

要解决您的问题,请将任何共享代码放在可以用 require 获取的地方。在控制台输入$LOAD_PATH

>> $LOAD_PATH
=> 
["/home/alex/code/Whosebug/lib",
 "/home/alex/code/Whosebug/vendor",
 "/home/alex/code/Whosebug/app/channels",
 "/home/alex/code/Whosebug/app/controllers",
 "/home/alex/code/Whosebug/app/controllers/concerns",
 "/home/alex/code/Whosebug/app/helpers",
 "/home/alex/code/Whosebug/app/jobs",
 "/home/alex/code/Whosebug/app/mailers",
 "/home/alex/code/Whosebug/app/models",
 "/home/alex/code/Whosebug/app/models/concerns",

 "/home/alex/code/Whosebug/engines/question/lib",   # <= engine's lib looks good

 "/home/alex/code/Whosebug/engines/question/app/components",
 "/home/alex/code/Whosebug/engines/question/app/controllers",
 "/home/alex/code/Whosebug/engines/question/app/controllers/concerns",
 ...

将共享文件放在引擎的lib目录下。由于我们在 app 目录之外,rails 不再是老板,任何路径和文件名组合都可以。

# question/lib/testing_support/blah.rb                   # <= note the filename
module System
  def log_visitor_in
    administrator = create(:visitor)
    visit ccs_cms.login_url
    fill_in 'login_name', with: visitor.login_name
    fill_in 'Password', with: visitor.password
    click_button 'Login'
  end
end

现在可以需要该文件了

# test/test_helper.rb or spec/rails_helper.rb 
# after environment and rails requires

require "testing_support/blah"                           # => loads System module

# ...

就是这样,在您的规范中使用它

require 'rails_helper'
RSpec.describe "order_payment_feature", type: :system do
  include System # include is for modules; now we have its functions in this spec

  before { log_visitor_in }

  it 'should accept this answer' do
    visit 'questions/71362333'
    expect(page).to have_content('accepted')
  end
end

此外,无论 $LOAD_PATH.

是什么,您都可以使用绝对路径以任何方式要求您的文件
require EngineOne::Engine.root + 'spec/support/system/order_functions.rb'

# or something else
Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |f| require f }