"Не удалось найти правильное сопоставление для #"только на втором и последующих тестах - PullRequest
28 голосов
/ 15 июня 2011

Я пытаюсь написать тест запроса, который утверждает, что в макете приложения отображаются правильные ссылки в зависимости от того, вошел ли пользователь в систему или нет.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

Первый тест пройден, но последние три не пройдены с ошибкой

Failure/Error: @user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123")
  RuntimeError:
    Could not find a valid mapping for #<User id: xxx, ...>

Я искал в вики Devise, группе 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 => "foo@bar.co", 
    #   :email_confirmation => "foo@bar.co", 
    #   :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(Я начал получать эти ошибки после настройки этого драгоценного камня в моем приложении, но у меня также был только один другой тест запроса, который работал нормально, но теперь получаю эту ошибку AssociationTypeMismatch; корреляция ≠ причинность ...) или проблему RSpec или какую-то другуюстранный конфликт с драгоценными камнями.

Ответы [ 9 ]

21 голосов
/ 09 апреля 2015

Добавьте эту строку в ваш rout.rb

# Devise routes
devise_for :users # Or the name of your custom model
9 голосов
/ 10 мая 2013

Для будущих читателей: я получил ту же ошибку, но по другой причине.

Наше приложение имело несколько пользовательских моделей, одна из которых была получена от другой

Для аргументов:

class SimpleUser

class User < SimpleUser

В моем контроллере я использовал ссылку на SimpleUser (родительский класс), но Devise был настроен на использование User (дочерний класс).

Во время вызова Devise :: Mapping.find_scope! это делает .is_a? сравнение со ссылкой на объект и настроенным классом.

Поскольку моя ссылка была SimpleUser, а настроенным классом был User, .is_a? не удается, потому что сравнение спрашивает, является ли родительский класс is_a Дочерний класс, который всегда ложный.

Надеюсь, это поможет кому-то еще.

9 голосов
/ 14 сентября 2011

Благодаря: http://blog.thefrontiergroup.com.au/2011/03/reloading-factory-girl-factories-in-the-rails-3-console/

"Devise использует сопоставление между классами и маршрутами, поэтому, когда объект, созданный на заводе, попадает в Devise после перезагрузки консоли или переопределения класса, произойдет сбой."

Поместите это в инициализатор или приложение. 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
3 голосов
/ 23 сентября 2013

У меня была эта ошибка в моем файле маршрутов, потому что у меня была конечная точка 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
1 голос
/ 02 января 2017

В моем случае это была проблема с методом confirm! Девиса.Поэтому вместо этого (Minitest::Test код):

setup do
  @admin = create(:admin).confirm!
end

Я сделал это:

setup do
  @admin = create(:admin)
  @admin.confirm!
end

И это сработало:)

1 голос
/ 25 сентября 2014

На тот случай, если кто-то еще столкнется с этим по той же причине, что и я - у меня была такая же проблема практически во всех моих тестах после изменения некоторых конфигурационных файлов - оказалось, что это было связано с тем, что для RAILS_ENV было установлено значениеdevelopment когда я запустил тесты случайно.Стоит проверить перед добавлением инициализатора рельсов для конкретного теста :-)

1 голос
/ 23 декабря 2011

Решение Halfnelson тоже сработало для меня, но, поскольку я использую Fabrication gem вместо FactoryGirl, мне нужно было внести некоторые коррективы. Вот код, который я поместил в инициализатор:

if Rails.env.development? || Rails.env.test?
  ActionDispatch::Callbacks.after do
    Fabrication.clear_definitions
    Rails.logger.debug 'Reloading fabricators'
  end
end
1 голос
/ 02 сентября 2011

я знаю, что это старая ветка, но я хотел получить ответ тому, кто еще столкнется с этим. Не знаю, где я это прочитал, но мне нужно знать, кто писал об этом на другом форуме.

Короче говоря, помощники разработчиков не очень хорошо работают с интеграционными тестами.

Поэтому удалите все ссылки на Devise :: TestHelpers (некоторые используют это, другие используют требуют devise / testhelpers) изнутри самих спецификаций.

затем в файле spec_helper добавьте:

RSpec.configure do |config|
  config.include Devise::TestHelpers, :type => :controller
end
0 голосов
/ 12 марта 2018

Это случалось со мной раньше, когда я вошел в систему в качестве тестового пользователя в одном из моих приложений и сделал несколько тестовых загрузок и тестовых сообщений.Затем я удалил этого тестового пользователя, и когда я попытался снова зарегистрироваться с тем же тестовым пользователем, мне было показано сообщение «Не удалось найти действительное сопоставление для nil».Чтобы решить эту проблему, я удалил все тестовые загрузки и тестовое сообщение, которое я сделал как этот тестовый пользователь.Затем я попытался зарегистрироваться снова, и это сработало.Таким образом, более быстрый и простой способ удалить материал - использовать браузер db для sqlite .

...