代码之家  ›  专栏  ›  技术社区  ›  jamesc

在Rails引擎中,Rspec有可能利用另一个引擎的Rspec支持系统助手吗?

  •  1
  • jamesc  · 技术社区  · 4 年前

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

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

    到目前为止,我已经在虚拟应用程序中安装了引擎 我需要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_to/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路径更改为

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

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

    0 回复  |  直到 4 年前
        1
  •  3
  •   Alex    4 年前

    当你 require 一个文件,ruby相对于中的路径进行搜索 $LOAD_PATH ;规范/或测试/不是其中的一部分。

    app 目录是rails中的一个特殊目录,任何子目录都会自动成为 autoload_paths 。此处可以看到自动加载路径 ActiveSupport::Dependencies.autoload_paths 。

    内部定义的任何类/模块 app/* 目录可以在不需要相应文件的情况下使用。Rails v7使用 zeitwerk 通过依赖“文件名”与“常量名”的关系自动加载/重新加载文件。这就是为什么文件夹映射到名称空间,文件映射到类/模块。

    要解决您的问题,请将任何共享代码放在可以获取的位置 要求 类型 $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目录中。既然我们在外面 应用程序 目录,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 }