ユーザーがログインしているかログアウトしているかに応じて、アプリケーションのレイアウトに適切なリンクが表示されることを表明するリクエストテストを作成しようとしています。 FWIW、認証部分にDeviseを使用しています。
これが私の仕様です:
require 'spec_helper'
require 'devise/test_helpers'
describe "Layout Links" do
context "the home page" do
context "session controls" do
context "for an authenticated user" do
before do
# I know these should all operate in isolation, but I
# want to make sure the user is explicitly logged out
visit destroy_user_session_path
@user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123")
@user.confirm!
# I tried adding this per the Devise wiki, but no change
@request.env["devise.mapping"] = Devise.mappings[:user]
# Now log a new user in
visit new_user_session_path
fill_in "Email", :with => @user.email
fill_in "Password", :with => "Asd123"
click_button "Sign in"
get '/'
end
it "should not have a link to the sign in page" do
response.should_not have_selector(
'#session a',
:href => new_user_session_path
)
end
it "should not have a link to registration page" do
response.should_not have_selector(
'#session a',
:href => new_user_registration_path
)
end
it "should have a link to the edit profile page" do
response.should have_selector(
'#session a',
:content => "My Profile",
:href => edit_user_registration_path
)
end
it "should have a link to sign out page" do
response.should have_selector(
'#session a',
:content => "Logout",
:href => destroy_user_session_path
)
end
end # context "for an authenticated user"
end # context "session controls"
end
end
最初のテストは合格ですが、最後の3つはすべてエラーで失敗します
Failure/Error: @user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123")
RuntimeError:
Could not find a valid mapping for #<User id: xxx, ...>
Devise wiki、Googleグループ、検索結果で原因を検索しましたが、config.include Devise::TestHelpers, :type => :controller
を設定するための未回答の質問または提案だけが見つかりましたが、これはコントローラーテストにのみ適用され、リクエストテストには適用されません。
更新
もう少しトラブルシューティングを行いましたが、最終的に問題を引き起こしているものの頭または尾を作ることができません。次のコードを見てください。
まず、いくつかのコンテキストのために、ここにユーザーファクトリ宣言があります。単体テストでは正常に機能します。
# spec/factories.rb
Factory.define :user do |f|
f.email { Faker::Internet.email }
f.email_confirmation { |f| f.email }
f.password "AbcD3fG"
f.password_confirmation "AbcD3fG"
f.remember_me { (Random.new.Rand(0..1) == 1) ? true : false }
end
ここで、次の統合テストについて考えてみましょう。
# spec/requests/user_links_spec.rb
require "spec_helper"
describe "User Links" do
before(:each) do
# This doesn't trigger the problem
# @user = nil
# This doesn't trigger the problem
# @user = User.new
# This doesn't trigger the problem
# @user = User.create(
# :email => "[email protected]",
# :email_confirmation => "[email protected]",
# :password => "asdf1234",
# :password_confirmation => "asdf1234"
# )
# This doesn't trigger the problem
# @user = User.new
# @user.email = Faker::Internet.email
# @user.email_confirmation = @user.email
# @user.password = "AbcD3fG"
# @user.password_confirmation = "AbcD3fG"
# @user.remember_me = (Random.new.Rand(0..1) == 1) ? true : false
# @user.save!
# This triggers the problem!
@user = Factory(:user)
# This doesn't trigger the same problem, but it raises a ActiveRecord::AssociationTypeMismatch error instead. Still no idea why. It was working fine before in other request tests.
# @user = Factory(:brand)
end
context "when using `@user = Factory(:user)` in the setup: " do
2.times do |i|
it "this should pass on the 1st iteration, but not the 2nd (iteration ##{i+1})" do
# This doesn't trigger an error
true.should_not eql(false)
end
it "this should pass on the 1st iteration, but trigger the error that causes all successive test cases to fail (iteration ##{i+1})" do
# Every test case after this will be borken!
get '/'
end
it "this will fail on all iterations (iteration ##{i+1})" do
# This will now trigger an error
true.should_not eql(false)
end
end
end
end
コメントアウトするか、get '/'
ビットを他のもの(またはまったく何もない)に置き換えると、テストはすべて正常に実行されます。
したがって、これがfactory_girlの問題(問題なしで他の場所でユーザーファクトリを使用できるため、疑う傾向があります)なのか、Deviseの問題(アプリケーションでそのgemを設定した後にこれらのエラーが発生し始めた)なのかはわかりません。しかし、他に1つのリクエストテストしかありませんでしたが、正常に機能しましたが、AssociationTypeMismatchエラー(相関≠原因...)、RSpecの問題、またはその他の奇妙なエッジケースのgemの競合が発生しています。
おかげで: http://blog.thefrontiergroup.com.au/2011/03/reloading-factory-girl-factories-in-the-Rails-3-console/
「Deviseはクラスとルート間のマッピングを使用するため、コンソールのリロード後、またはクラスの再定義後に、工場で構築されたオブジェクトがDeviseに到達すると、失敗します。」
これを初期化子またはapplication.rbに入れます
ActionDispatch::Callbacks.after do
# Reload the factories
return unless (Rails.env.development? || Rails.env.test?)
unless FactoryGirl.factories.blank? # first init will load factories, this should only run on subsequent reloads
FactoryGirl.factories.clear
FactoryGirl.find_definitions
end
end
この行をroutes.rbに追加します
# Devise routes
devise_for :users # Or the name of your custom model
将来の読者のために:私は同じエラーを受け取りましたが、理由は異なります。
私たちのアプリには複数のユーザーモデルがあり、一方が他方から派生しています
議論のために:
class SimpleUser
class User < SimpleUser
私のコントローラーでは、SimpleUser(親クラス)への参照を使用しましたが、DeviseはUser(子クラス)を使用するように構成されていました。
Devise :: Mapping.find_scopeの呼び出し中! .is_aですか?オブジェクト参照および構成済みクラスとの比較。
私の参照はSimpleUserであり、構成されたクラスはUserだったので、.is_a?親クラスがis_aかどうかを比較が尋ねていたため、失敗しましたか?子クラス。これは常にfalseです。
それが他の誰かを助けることを願っています。
ユーザーがパスワードをリセットできるようにするAPIエンドポイントがあったため、ルートファイルでこのエラーが発生しましたが、_/api
_
これは私がそれを機能させるためにルートを修正した方法です:
_CoolApp::Application.routes.draw do
namespace :api, defaults: { format: :json } do
devise_scope :users do
post 'users/passwords', to: 'passwords#create'
end
resources :users, only: [:create, :update]
end
devise_for :users
root to: 'high_voltage/pages#show', id: 'home'
end
_
Halfnelsonのソリューションもうまくいきましたが、FactoryGirlの代わりに Fabrication gem を使用しているため、いくつかの調整を行う必要がありました。イニシャライザにドロップしたコードは次のとおりです。
if Rails.env.development? || Rails.env.test?
ActionDispatch::Callbacks.after do
Fabrication.clear_definitions
Rails.logger.debug 'Reloading fabricators'
end
end
他の誰かがこれに遭遇した場合に備えて、私と同じ理由で-いくつかの構成ファイルを変更した後、基本的にすべてのテストで同じ問題が発生しました-Rails_ENV
がdevelopment
に設定されていることが原因であることが判明しました誤ってテストを実行したとき。テスト固有のRails初期化子:-)を追加する前に確認する価値があるかもしれません
私はこれが古いスレッドであることを知っていますが、他の誰かがこれに遭遇したときの答えが欲しかったのです。私がこれをどこで読んだかはわかりませんが、これについて別のフォーラムに投稿した人に小道具を提供します。
長短は、デバイステストヘルパーが統合テストでうまく機能しないことです。
したがって、仕様自体の中からDevise :: TestHelpers(includeを使用する人もいれば、require'devise/testhelpers 'を使用する人もいます)のすべての参照を削除します。
次に、spec_helperファイルに次を追加します。
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
私の場合、これはDevisのconfirm!
メソッドの問題でした。したがって、これを行う代わりに(Minitest::Test
コード):
setup do
@admin = create(:admin).confirm!
end
私はこれをしました:
setup do
@admin = create(:admin)
@admin.confirm!
end
そしてそれはうまくいきました:)
以前、自分のアプリの1つでテストユーザーとしてサインインし、テストのアップロードと投稿を行ったときに、これが発生しました。次に、そのテストユーザーを削除し、同じテストユーザーで再度サインアップしようとすると、「nilの有効なマッピングが見つかりませんでした」というメッセージが表示されました。それを解決するために私がしたことは、そのテストユーザーとして作成したすべてのテストアップロードとテスト投稿を削除することでした。その後、再度サインアップしようとしましたが、うまくいきました。その方法で、ものを削除するためのより速くて簡単な方法は sqliteのdbブラウザ を使用することです。