Ruby on rails 未在Rails 5.2集成测试中持久化的会话

Ruby on rails 未在Rails 5.2集成测试中持久化的会话,ruby-on-rails,devise,integration-testing,minitest,warden,Ruby On Rails,Devise,Integration Testing,Minitest,Warden,我有一个多租户应用程序,它使用Platform for postgreSQL模式,并设计用于用户身份验证。在我尝试编写一些集成测试之前,一切都很顺利 以下是我到目前为止所拥有的内容的精简版本(请随意询问更多信息): 并确认warden.authenticated?在随后尝试导航到新文章路径时,返回了articles\u路径的true,但false 我在集成测试类型、控制器和系统中都注意到了这种行为。但是,在开发环境中使用此应用程序时,这不是问题 最令人沮丧的是,我有一个不同的应用程序,似乎有一个

我有一个多租户应用程序,它使用Platform for postgreSQL模式,并设计用于用户身份验证。在我尝试编写一些集成测试之前,一切都很顺利

以下是我到目前为止所拥有的内容的精简版本(请随意询问更多信息):

并确认
warden.authenticated?
在随后尝试导航到
新文章路径时,返回了
articles\u路径的
true
,但
false

我在集成测试类型、控制器和系统中都注意到了这种行为。但是,在开发环境中使用此应用程序时,这不是问题

最令人沮丧的是,我有一个不同的应用程序,似乎有一个相同的设置,这个应用程序,但这个认证问题并没有发生在测试

如何调试此问题

系统

  • 轨道:5.2.2
  • 设计:4.5.0
  • 水豚:3.13.2

更新1(2019年2月4日)

这是@BKSpurgeon请求的物品控制器

# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  before_action :set_article, only: [:show, :edit, :update, :archive]

  def index
    @articles = Article.where(archived: false)
  end

  def show
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article, notice: 'Your article was successfully created.'
    else
      flash[:error] = @article.errors.full_messages.to_sentence
      render :new
    end
  end

  def edit
  end

  def update
    if @article.update(article_params)
      redirect_to articles_path, notice: 'Your article was successfully updated.'
    else
      flash[:error] = @article.errors.full_messages.to_sentence
      render :edit
    end
  end

  def archive
    if @article.archive!
      redirect_to articles_path, notice: 'Your article was successfully archived.'
    else
      render :edit
    end
  end

  private
    def set_article
      @article = Article.find(params[:id])
    end

    def article_params
      params.require(:article).permit(:name, :content, :archived)
    end
end
#app/controllers/articles_controller.rb
类ArticlesController<应用程序控制器
在\u操作之前:设置\u文章,仅:[:显示,:编辑,:更新,:存档]
def索引
@articles=Article.where(存档:false)
结束
def秀
结束
def新
@article=article.new
结束
def创建
@article=article.new(article_参数)
如果@article.save
将_重定向到@article,注意:“您的文章已成功创建。”
其他的
flash[:error]=@article.errors.full_messages.to_句子
渲染:新
结束
结束
定义编辑
结束
def更新
if@article.update(article_参数)
重定向到文章路径,注意:“您的文章已成功更新。”
其他的
flash[:error]=@article.errors.full_messages.to_句子
渲染:编辑
结束
结束
def档案
如果@article.archive!
重定向到文章路径,注意:“您的文章已成功存档。”
其他的
渲染:编辑
结束
结束
私有的
def set_文章
@article=article.find(参数[:id])
结束
定义项目参数
参数require(:article).permit(:名称,:内容,:存档)
结束
结束

更新2(2019年2月4日)

我编写了简单的中间件,并将其放在Warden面前进行调试:

# lib/debug_warden_middleware.rb
class DebugWardenMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    @status, @headers, @response = @app.call(env)
    if env['warden'].present?
      puts "User (#{env['warden'].user.present?}), Class: #{@response.class.name}"
    end
    return [@status, @headers, @response]
  end
end

# config/application.rb
#...
module AppName
  class Application < Rails::Application
    # ...

    config.middleware.insert_before Warden::Manager, DebugWardenMiddleware
  end
end
#lib/debug_warden_middleware.rb
类DebugWarden中间件
def初始化(应用程序)
@app=app
结束
def呼叫(环境)
@状态,@headers,@response=@app.call(env)
如果环境[典狱长]在场?
放置“用户(#{env['warden'].User.present?}),类:#{@response.Class.name}”
结束
返回[@status、@headers、@response]
结束
结束
#config/application.rb
#...
模块AppName
类应用程序
我注意到warden似乎在每次请求后都会清除其用户,包括资产请求:

bin/rails test:system
Run options: --seed 39763

# Running:

Capybara starting Puma...
* Version 3.9.1 , codename: Private Caller
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:57466
User (true), Uri: ActionDispatch::Response::RackBody
User (false), Uri: Sprockets::Asset
User (false), Uri: Sprockets::Asset
User (false), Uri: Sprockets::Asset
User (false), Uri: ActionDispatch::Response::RackBody
User (false), Uri: ActionDispatch::Response::RackBody
User (false), Uri: Sprockets::Asset
[Screenshot]: tmp/screenshots/failures_test_post_a_new_article.png
E

Error:
Agenda::PostTest#test_post_a_new_article:
Capybara::ElementNotFound: Unable to find field "Name"
    test/system/article/post_test.rb:9:in `block in <class:PostTest>'


bin/rails test test/system/article/post_test.rb:4
bin/rails测试:系统
运行选项:--seed 39763
#运行:
水豚启动美洲狮。。。
*版本3.9.1,代号:私人呼叫方
*最小线程数:0,最大线程数:4
*倾听tcp://127.0.0.1:57466
用户(true),Uri:ActionDispatch::Response::RackBody
用户(false),Uri:Sprockets::Asset
用户(false),Uri:Sprockets::Asset
用户(false),Uri:Sprockets::Asset
用户(false),Uri:ActionDispatch::Response::RackBody
用户(false),Uri:ActionDispatch::Response::RackBody
用户(false),Uri:Sprockets::Asset
[截图]:tmp/截图/失败测试发布新文章.png
E
错误:
议程::PostTest#test(测试)post(新文章)
Capybara::ElementNotFound:找不到字段“Name”
测试/系统/文章/后期测试。rb:9:in‘block in’
bin/rails测试/系统/文章/后期测试。rb:4

作为补充说明,我同时使用链轮和Webpacker。

好吧,我在两者之后(在聊天信息中)偶然发现了答案,并建议我尝试在单独的应用程序中重新创建问题,以便与大家共享

因为这个应用程序是多租户的,并且使用公寓gem,所以我的测试设置有点复杂。不幸的是,我没有包括其中的一些设置,我认为这是不相关的()。直到我尝试重新创建我的应用程序,我才注意到这个缺陷。以下是我使用的测试设置:

# test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'

# support files
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }

# Apartment setup
Apartment::Tenant.drop('sample') rescue nil
Apartment::Tenant.create('sample') rescue nil
Apartment::Tenant.switch! 'sample'

# Capybara setup
Capybara.configure do |config|
  config.default_host = 'http://lvh.me'
  config.always_include_port = true
end

class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
  fixtures :all

  # Add more helper methods to be used by all tests here...
end

class ActionDispatch::IntegrationTest
  include Devise::Test::IntegrationHelpers
  include SubdomainHelper
  include SignInHelper # dependent on SubomainHelper

  setup do
    default_url_options[:host] = 'lvh.me'
    Apartment::Tenant.switch! 'public'
  end
end

#test/system/article/post#u test.rb
需要“应用程序\系统\测试\案例”
类文章::PostTest

现在,会话正在持续。有一件事仍然让我困惑,那就是为什么我能够登录呢?我把它记为延迟的测试数据,但这更像是猜测。

粘贴到文章控制器中。一些想法:(i)在
文章路径
视图中添加
,然后查看是否有当前用户,以及该用户是否已登录?(ii)再次使用
byebug
检查物品控制器中是否点击了
new
操作,并再次检查那里是否有
当前用户。然后逐行检查,看看您是否还有当前用户。希望有帮助。谢谢@BKSpurgeon,我已经用ArticlesController更新了这个问题。在将
插入索引视图时,我发现一个用户已登录。但是,它永远不会进入
新建
操作,因为它在执行操作之前失败了designe的
验证用户。这就是为什么我认为这与测试环境中未持久化的会话有关。请尝试删除monkey修补程序,并在您的登录帮助程序中添加bybug语句,然后测试用户是否成功登录。我不确定如何测试用户是否使用O登录
bin/rails test:system
Run options: --seed 39763

# Running:

Capybara starting Puma...
* Version 3.9.1 , codename: Private Caller
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:57466
User (true), Uri: ActionDispatch::Response::RackBody
User (false), Uri: Sprockets::Asset
User (false), Uri: Sprockets::Asset
User (false), Uri: Sprockets::Asset
User (false), Uri: ActionDispatch::Response::RackBody
User (false), Uri: ActionDispatch::Response::RackBody
User (false), Uri: Sprockets::Asset
[Screenshot]: tmp/screenshots/failures_test_post_a_new_article.png
E

Error:
Agenda::PostTest#test_post_a_new_article:
Capybara::ElementNotFound: Unable to find field "Name"
    test/system/article/post_test.rb:9:in `block in <class:PostTest>'


bin/rails test test/system/article/post_test.rb:4
# test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'

# support files
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }

# Apartment setup
Apartment::Tenant.drop('sample') rescue nil
Apartment::Tenant.create('sample') rescue nil
Apartment::Tenant.switch! 'sample'

# Capybara setup
Capybara.configure do |config|
  config.default_host = 'http://lvh.me'
  config.always_include_port = true
end

class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
  fixtures :all

  # Add more helper methods to be used by all tests here...
end

class ActionDispatch::IntegrationTest
  include Devise::Test::IntegrationHelpers
  include SubdomainHelper
  include SignInHelper # dependent on SubomainHelper

  setup do
    default_url_options[:host] = 'lvh.me'
    Apartment::Tenant.switch! 'public'
  end
end
# test/support/sign_in_helper.rb
module SignInHelper
  def sign_in_as(name)
    # This right here was the problem code
    user = users(name)
    use_account user.account
    sign_in user
  end
end
# test/support/subdomain_helper.rb
module SubdomainHelper
  def use_account(account)
    account.save unless account.persisted?

    default_url_options[:host] = "#{account.subdomain}.lvh.me"
    Capybara.app_host = "http://#{account.subdomain}.lvh.me"
    Apartment::Tenant.switch! account.subdomain
  end
end
# test/system/article/post_test.rb
require "application_system_test_case"

class Article::PostTest < ApplicationSystemTestCase
  test 'post a new document' do
    sign_in_as :will
    visit articles_path

    click_on 'Add New Article' # redirected to login page after clicking this button
    fill_in 'Name', with: 'Hello world!'
    fill_in 'Content', with: 'Yes yes'

    click_on 'Create Article'
    assert_select 'h1', /Hello world!/
  end
end
# test/support/sign_in_helper.rb
module SignInHelper
  def sign_in_as(name, account)
    use_account accounts(account)
    sign_in users(name)
  end
end
# test/system/article/post_test.rb
require "application_system_test_case"

class Article::PostTest < ApplicationSystemTestCase
  test 'post a new document' do
    sign_in_as :will, :sample

    # ...
  end
end