在Rails引擎中,是否可以让Rspec使用另一个引擎中的Rspec支持系统帮助程序?

4

假设有一个Rails引擎engine_one,它具有一个spec支持文件engine_one/spec/support/system/order_functions.rb,其中包含用于支持测试各种订单系统测试的功能,例如模拟已登录用户、向订单添加产品等,并包含一些方法,如log_visitor_in,在测试订单处理时被广泛使用。

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

到目前为止,我已经在dummy应用程序中安装了这两个引擎,已经在engine_two/lib/engine.rb中要求engine_one,也已经在相关测试中要求了support文件,但是找不到它,同时我已经将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引擎。

1个回答

3

当你调用require方法加载文件时,Ruby会在$LOAD_PATH路径下寻找文件,而其中不包括spec/或test/目录。

app目录在Rails中是一个特殊的目录,任何子目录都会自动成为autoload_paths的一部分,可以通过ActiveSupport::Dependencies.autoload_paths查看autoload路径。

定义在app/*目录下的任何类/模块都可以在不需要手动调用require的情况下使用。Rails v7使用zeitwerk实现自动加载/重载文件,它基于“文件名”到“常量名”的映射关系,因此文件夹对应命名空间,文件对应类/模块。

如果要解决问题,请将任何共享代码放置在可以使用require方法获取的地方。在控制台中键入$LOAD_PATH即可。

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

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

 "/home/alex/code/stackoverflow/engines/question/app/components",
 "/home/alex/code/stackoverflow/engines/question/app/controllers",
 "/home/alex/code/stackoverflow/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 }

1
再次感谢Alex的帮助,我现在对路径和引擎有了大致的理解。 - jamesc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接