首页 > 解决方案 > Rspec login_user 问题

问题描述

我在使用 Devise/Rspec 登录用户以进行测试时遇到问题。我使用了support/controller_macros设计概述的模块,但是每当我尝试 login_user在测试的任何部分使用时,都会出现错误:before is not available from within an example (e.g. an it block) or from constructs that run in the scope of an example (e.g. before, let, etc). It is only available on an example group (e.g. a describe or context block).

我已经尝试过移动东西,确保我的所有要求都正确设置,等等。

我的测试:

require "rails_helper"

RSpec.describe BallotsController, type: :controller do
  describe "index" do
    it "renders" do
      login_user
      ballots_path
      expect(response).to be_success
      expect(response).to render_template("index")
    end
  end
end

(我尝试在 describe 块中添加 login_user 以及上部块)

我的控制器宏:

  def login_user
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:user_confirmed]
      user = FactoryBot.create(:user_confirmed)
      sign_in user
    end
  end

  def login_admin
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:admin]
      user = FactoryBot.create(:admin)
      sign_in user
    end
  end
end

我的规范助手:

require "rails_helper"
require_relative "support/controller_macros"
RSpec.configure do |config|
  # rspec-expectations config goes here. You can use an alternate
  # assertion/expectation library such as wrong or the stdlib/minitest
  # assertions if you prefer.
  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
  end

  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end

  config.shared_context_metadata_behavior = :apply_to_host_groups
  config.include ControllerMacros, :type => :controller
  config.include Devise::Test::ControllerHelpers, :type => :controller

  config.example_status_persistence_file_path = "spec/examples.txt"

  config.disable_monkey_patching!

  if config.files_to_run.one?
    config.default_formatter = "doc"
  end

  config.profile_examples = 10

  config.order = :random

  Kernel.srand config.seed
end

我希望它能让用户登录,并让控制器正确地点击索引路由。谢谢!

标签: ruby-on-railsrspecdevise

解决方案


代码中的唯一问题(解决错误,无需深入讨论是否应使用此方法)是您在it块内有登录用户,这不可能是因为它正在调用before(:each).

如果您查看设备文档,您还会看到它在 it 块中没有此调用,而是在 it 块之外的一个 describe 块中。它将此调用应用于该描述块中的所有 it 块。

您的代码将变为:

RSpec.describe BallotsController, type: :controller do
  describe "index" do
    login_user
    it "renders" do
      ballots_path
      expect(response).to be_success
      expect(response).to render_template("index")
    end
  end
end

我喜欢的方式:

在您的控制器宏中,将 login_user 替换为:

def login_user(user)
  @request.env["devise.mapping"] = Devise.mappings[:user_confirmed]
  sign_in user
end

现在,无论您想在哪里登录用户,都可以执行以下操作:

RSpec.describe BallotsController, type: :controller do
  describe "index" do
    let(:user) { FactoryBot.create(:user) }

    it "renders" do
      login_user(user)
      ballots_path
      expect(response).to be_success
      expect(response).to render_template("index")
    end
  end

  # OR

  describe "index" do
    let(:user) { FactoryBot.create(:user) }

    before(:each) do
      login_user(user)
    end

    it "renders" do
      ballots_path
      expect(response).to be_success
      expect(response).to render_template("index")
    end
  end
end

推荐阅读