У меня есть мультитенантное приложение, которое использует Apartment для схем postgreSQL и Devise для аутентификации пользователей.Все идет гладко, пока я не попытаюсь написать некоторые интеграционные тесты.
Вот урезанная версия того, что у меня есть (не стесняйтесь спрашивать дополнительную информацию):
# test/support/sign_in_helper.rb
module SignInHelper
def sign_in_as(name)
sign_in users(name)
end
end
# test/test_helper.rb
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
#...
class ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
include SignInHelper
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
articles_path
требует аутентифицированного пользователя, так что я знаю, что вход в помощник работает.Тем не менее всякий раз, когда я пытаюсь перейти по другой ссылке, внезапно пользователь не проходит проверку подлинности.
Я обезьяна исправил метод authenticate_user!
Devise следующим образом:
def authenticate_user!(*args)
byebug
super
end
и подтвердил, что warden.authenticated?
вернул true
для articles_path
, но false
при последующей попытке перейти к new_article_path
.
Я заметил это поведение как в типах интеграционных тестов, так и в контроллере и системе.Тем не менее, это не проблема при использовании этого приложения в среде разработки.
Наиболее расстраивающим моментом является то, что у меня есть другое приложение, которое, похоже, имеет настройку, идентичную этому приложению, но эта проблема аутентификации делаетне происходит во время тестирования.
Как можно отладить эту проблему?
Система
- Rails: 5.2.2
- Разработка: 4.5.0
- Капибара: 3.13.2
Обновление 1 (04 февраля 2019 г.)
Вот контроллер статей, запрошенный @ 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
Обновление 2 (04 февраля 2019 г.)
Я написал простое промежуточное ПО и поместил его перед 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
И я заметил, что 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
В качестве примечания, я использую оба Sprocketsи Webpacker.