24

I'm building a rails 4 app. I created a support file to simulate a login. Here are the files

spec/support/spec_test_helper.rb

module SpecTestHelper
  def login(user)
    request.session[:user_id] = user.id
  end

  def current_user
    User.find(request.session[:user_id])
  end
end

spec_helper.rb

config.include SpecTestHelper, :type => :controller

controller spec

describe BooksController, "user role" do

  user = Fabricate(:user) do
    role { Role.find_by_account_type("user") }
  end

  login(user)
end

The support file gives an undefined method error. This is part of the error message:

spec/controllers/books_controller_spec.rb:27:in `block in <top (required)>': undefined method `login' for #<Class:0x007f9f83193438> (NoMethodError)

I'm testing CanCan. I know the correct way to test CanCan is testing the Ability but that's already done.

sawa
  • 165,429
  • 45
  • 277
  • 381
Ricbermo
  • 815
  • 1
  • 6
  • 28

5 Answers5

32

I added this line in spec_helper.rb and it works in 3rd Rails

Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

Maybe another (more pretty) solution exists

gotva
  • 5,919
  • 2
  • 25
  • 35
  • 1
    so pay attention on @Ash's answer - you really should build records and call methods inside it/before/let... – gotva Dec 16 '13 at 16:05
16

There can be two files under rspec dir: rails_helper.rb and spec_helper.rb. If you want to provide support for rails-dependent classes, you should use rails_helper to tell rails to load the modules under the 'spec/support' dir.

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

To declare the shared module, you want to use it inside the config block.

RSpec.configure do |config|
  ...
  config.include <YourModuleName>::<YourClassName>, :type => :controller
  ...
end

But, if your class doesn't require rails at all, you can load it under spec_helper, which will not load rails to run the tests. Refer to this answer and to this reference to learn more about it.

sawa
  • 165,429
  • 45
  • 277
  • 381
Saulo Aguiar
  • 509
  • 6
  • 12
7

Alternative to the answer provided by @gotva. It's slightly more verbose, but will work in both Rails 3 and 4:

Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f} 
alexs333
  • 12,143
  • 11
  • 51
  • 89
0

Put the login(user) call within a before or an it block, instead of directly within the describe:

let(:user) do
  Fabricate(:user) do
    role { Role.find_by_account_type("user") }
  end
end

before do
  login(user)
end
Ash Wilson
  • 22,820
  • 3
  • 34
  • 45
0

in your spec only add such class or module like following

both files in the path: spec/

# frozen_string_literal: true

require "rails_helper"

class SharedHelper   
  def defined_action
    ...
  end
end

# frozen_string_literal: true

require "rails_helper"
require_relative "shared_helper"

RSpec.describe "Test request", type: :request do
  before(:all) do
    SharedHelper.new.defined_action
  end
end
Dharman
  • 30,962
  • 25
  • 85
  • 135
axlfire1
  • 191
  • 2
  • 4