Rspec cannot find custom module - ruby-on-rails

I try to test devise user authentication, the problem I've done everything according to samples, however the code still doesn't work.
spec/support/devise/devise_support.rb
module ValidUserRequestHelper
def sign_in_as_a_valid_user
#user ||= Fabricate(:simple_user)
post_via_redirect user_session_path, 'user[email]' => #user.email, 'user[password]' => #user.password
end
end
RSpec.configure do |config|
config.include ValidUserRequestHelper, :type => :request
end
spec/spec_helper.rb
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
However when I run test, it fails on the calling to `sign_in_as_a_valid_user'
undefined local variable or method `sign_in_as_a_valid_user' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0xc57a0c4>
I don't have idea how to debug this.
The test code is
require 'spec_helper'
describe User do
before do
sign_in_as_a_valid_user
end
...

when you write this in your rspec configuration
RSpec.configure do |config|
config.include ValidUserRequestHelper, :type => :request
end
you tell rspec to only include this helper for request spec. those are typically located in spec/request. deriving from the example of your spec that has describe User in it, i assume that you are writing a model spec, typically located in spec/model. so when running the spec, rspec won't include it for that spec!
if you just remove the :type => :request it will get included everywhere. keep in mind, that there is usually a good reason for this kind of restrictions. for example a helper that only works with a fake browser, like it is done in request specs.

Related

Adding helper module to Rspec

I would like to add a module that includes a method to help me log in as a user. Here it is:
module TestHelper
require 'spec_helper'
ALL_USERS = ["administrator", "instructor", "regular_user"]
def self.login_as(user_type)
user = User.find_by(global_role_id: GlobalRole.send(user_type))
#request.env["devise.mapping"] = Devise.mappings[:user]
sign_in user
end
end
The spec that's calling it is
require 'spec_helper'
RSpec.describe QuestionsController, :type => :controller do
include Devise::TestHelpers
include TestHelper
describe "a test" do
it "works!" do
TestHelper.login_as("administrator")
end
end
end
And here is the spec_helper
RSpec.configure do |config|
config.include TestHelper, :type => :controller
The error I get is: undefined method 'env' for nil:NilClass It looks like my module doesn't have access to #request.
My question is: how do I access and #request in the external Module?
In addition to the other answers, you should consider only including this module for relevant spec types using the following code:
config.include TestHelper, type: :controller # Or whatever spec type(s) you're using
You could pass #request in to TestHelper.login_as from the tests. Eg
module TestHelper
def self.login_as(user_type, request)
...
request.env['devise.mapping'] = Devise.mappings[:user]
...
end
end
...
describe 'log in' do
it 'works!' do
TestHelper.login_as('administrator', #request)
end
end
But probably better to follow the macro pattern from the devise wiki if other devise mappings in play.

Rspec not loading ControllerMacros module in Linux (but fine on OS X)

I have written some controller tests in a Rails app that uses Devise and Rspec. Following this guide, I've created a controller_macros.rb in the /spec/support/ directory. There is also a devise.rb file in the same directory, with:
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.extend ControllerMacros, :type => :controller
end
Both files are being required in the spec_helper.rb file, with this line:
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
Now here is what is weird: this approach works fine on an OS X laptop, but fails in my Linux desktop. They both use the same RVM settings, same gemsets, same everything.
The error I get when running the tests in Linux is:
uninitialized constant ControllerMacros (NameError)
Obviously the controller_macros.rb module is failing to load in Linux. I've seen SO answers suggesting that config.extend could be changed to config.include, but that doesn't fix the problem.
Any ideas where I can look or what I can test to help isolate the issue?
I'm using Rails 4.1.8 and Rspec 3.1.7.
I struggled with this as well. Answers just weren't working for me. This is what I did (Ubuntu, Rails 4, Rspec 3):
spec/rails_helper.rb
# <snip> env stuff
require 'spec_helper'
require 'rspec/rails'
require 'devise'
require 'support/controller_macros'
# <snip> some non-devise stuff
RSpec.configure do |config|
# <snip> some more non-devise stuff
config.include Devise::TestHelpers, type: :controller
config.include ControllerMacros, type: :controller
end
spec/support/controller_macros.rb
module ControllerMacros
def login_user
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
sign_in user
end
end
students_controller.rb
require "rails_helper"
describe StudentsController, type: :controller do
before do
login_user
end
describe "GET index" do
it "has a 200 status code" do
get :index
response.code.should eq("200")
end
end
end
I solved this by adding
require Rails.root.join("spec/support/macros/controller_macros.rb")
to the top of my spec/support/devise.rb file

Getting Rspec to Recognize Macros for Capybara's Specials

When adding macros to Rspec's config, you have to specify the type of test it'll be accessed by. For instance, you might type:
config.extend ControllerMacros, :type => :controller
How do you get this to work with Capybara, whose type (:feature) is seemingly not recognized by Rspec's config. Trying something like this does not work:
config.extend FeatureMacros, :type => :feature
I don't know why you type extend, all my settings are include and they works.
RSpec.configure do |config|
# ... others
# Session helpers - For Capybara
config.include Features::SessionHelpers, type: :feature
# Controller helpers
config.include ControllerMacros, type: :controller
end
And the module files are in spec/support. If sub module, they are in sub folder like `spec/support/features/
Example of Capybara helpers
# spec/support/features/session_helpers.rb
require 'spec_helper'
module Features
module SessionHelpers
def user_sign_in
end
end
end

should this code work for including in a helper file to rspec?

I have the following sample code that is using a vanilla spec_helper. I'm trying to use the sign_in_as but am getting an error saying it doesn't exist. I hadn't really seen this config syntax before so I'm not sure if this is being used right. Any help would be appreciated? thx
in helpers/sign_in_helpers.rb
module SignInHelpers
def say_hello
puts 'hello'
end
def sign_in
sign_in_as 'person#example.com'
end
def sign_in_as email
visit root_path
fill_in 'Email address', with: email
click_button 'Sign In'
end
end
RSpec.configure do |config|
config.include SignInHelpers
end
Some errors in your code.
you should have this code on top of the file
require 'spec_helper'
The place to put the file is spec/support, not spec/helpers
Also, for the following code, better to keep them all inside spec/spec_helper.rb inside the configure block, though your way should work as well.
RSpec.configure do |config|
config.include SignInHelpers
end
By the way, better to define the type as your helper are for features only, and not going to work in controller tests.
config.include SignInHelpers type: :feature
In theory, yes. Your call looks like a valid use of the include syntax
https://www.relishapp.com/rspec/rspec-core/docs/helper-methods/define-helper-methods-in-a-module

rspec & devise test helpers

According to this from the devise wiki I should be able to use a login_user helper method in my controller tests. Accordingly I have the following within the spec directory:
#spec_helper.rb
...
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
...
and
#support/controller_macros.rb
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#user = Factory.create(:user)
sign_in #user
end
end
end
however calling the helper doesn't work:
#requests/some_spec.rb
require 'spec_helper'
describe "GET /guides/edit" do
login_user
end
Can someone point toward where I'm going wrong. The test suite works about from this. I get a undefined local variable or method message so I guess the module isn't being included.
Rails 3.0.7
rspec 2.6.0
devise 1.3.4
backtrace
I imagine there are a couple of problems with this approach. First is that you're using request specs, not controller specs, so the login_user method is not made available by config.extend ControllerMacros, :type => :controller. Second, even if you are able to include the method it most likely won't work anyway, since the Devise test helpers are specifically written for controller/view tests, not integration tests.
Take a look at David Chelimsky's answer to this SO question, which may be of help.
I can't answer for sure... but the code smell for me is the "before(:each)" defined inside the helper. why don't you try:
#support/controller_macros.rb
module ControllerMacros
def login_user
#request.env["devise.mapping"] = Devise.mappings[:user]
#user = Factory.create(:user)
sign_in #user
end
end
and
#requests/some_spec.rb
require 'spec_helper'
describe "GET /guides/edit" do
before(:each) do
login_user
end
end
and if that fails - maybe it just can't find #request - in which case, pass it as a variable to login_user
Edit:
Looks like you might need to include the devise test helpers.
The rdoc says you should have this file:
# spec/support/devise.rb
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
Not sure if that differs from how you've already got it in spec_helper.rb
... looks pretty similar to me.
I have same issue with Rails 3.0.10 rspec 2.6.0 devise 1.3.4 spork-0.9.0.rc9 on my controller specs, i have changed config. extend to config.include and its work !
Forget to confirm if your app is not confirmable. Your code should look like
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
#user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the confirmable module
sign_in user
end
end
end

Resources