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
Related
Assumptions
We are developing with Ruby on Rails and creating test code with Rspec.
Environment
Ruby 2.6.5
Rails 6.0.3
RSpec 3.11
devise 4.7.1
What I would like to achieve.
In Rspec, I am expecting a 200 code, but it returns a 401 code.
I modified the code below to log in, but it still fails to log in and returns a 401 code.
How can I modify it so that it logs in and returns a 200 code?
Problem/error message you are encountering
Rspec logs
Failure/Error: expect(response.status).to eq 200
expected: 200
got: 401
Source code in question
infos_controller_spec.rb
# frozen_string_literal: true
require "rails_helper"
module Api::V1::Admin
RSpec.describe InfosController, type: :controller do
describe "GET /form_init" do
let!(:user){create :user}
it "should 200" do
login_user(user)
get :form_init
expect(response.status).to eq 200
end
end
end
end
spec/rails_helper.rb
require 'spec_helper'
require "devise"
Dir[File.expand_path("./spec/support/*.rb")].each{|f| require f}
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = :expect
end
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::IntegrationHelpers, type: :request
config.include ControllerMacros, type: :controller
config.include Warden::Test::Helpers
end
spec/support/controller_macros.rb
module ControllerMacros
def login_user(user)
#request.env['devise.mapping'] = Devise.mappings[:user]
sign_in(user, scope: :user)
end
end
I am getting a uninitialized constant ControllerMacros (NameError), perhaps similar to these issues (1, 2, 3). I must be screwing up the syntax while trying to include controller macros so I can login with devise and pass controller tests in rspec. Link to GitHub repo.
Rails 4.1.8 and Ruby 2.1.2
spec/controllers/static_pages_controller_spec.rb
require 'rails_helper'
describe StaticPagesController, :type => :controller do
describe "GET #index" do
it "responds successfully with an HTTP 200 status code" do
login_user
get :index
expect(response).to be_success
expect(response).to have_http_status(200)
end
it "renders the index template" do
login_user
get :root
expect(response).to render_template("index")
end
end
end
spec/support/controller_macros.rb
module ControllerMacros
def login_admin
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:admin]
admin = FactoryGirl.create(:admin)
sign_in :user, admin # sign_in(scope, resource)
end
end
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
added lines to spec/rails_helper
#helps avoid authentication error during rspec:
config.include Devise::TestHelpers, :type => :controller
config.include ControllerMacros, :type => :controller
This worked for me.
spec/support/devise.rb
require 'devise'
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
end
Also make sure this line is uncommented in rails_helper.rb
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
I looks like you may need to add require 'support/controller_macros' to the top of your rails_helper.rb file. This directory would not be included by default with RSpec.
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.
I'm quite new to rails, and trying to follow the railstutorial. Everything goes fine, except for my tests which can't get past the named routes (5.3.3)
My routes.rb :
SampleApp::Application.routes.draw do
resources :users
match '/signup', to: 'users#new'
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'pages#contact'
root to: 'static_pages#home'
#Commented stuff
My firsts tests (spec/controllers/static_pages_controller_spec.rb) :
describe "Static pages" do
subject { page }
shared_examples_for "all static pages" do
it { should have_selector('h1', text: heading) }
it { should have_selector('title', text: full_title(page_title)) }
end
describe "Home page" do
before { visit root_path }
let(:heading) { 'Sample App' }
let(:page_title) { 'Home' }
it_should_behave_like "all static pages"
end
#Other tests
The spec_helper.rb looks like (without all the commented stuff)
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
end
The errors I get from rspec are all like this one :
Static pages Home page it should behave like all static pages
Failure/Error: before { visit root_path }
NameError:
undefined local variable or method `root_path' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_1::Nested_1:0x00000004a12210>
Shared Example Group: "all static pages" called from ./spec/controllers/static_pages_controller_spec.rb:17
# ./spec/controllers/static_pages_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
I already tried using
include Rails.application.routes.url_helpers
in the spec_helper, but it changed my errors to
Static pages Home page it should behave like all static pages
Failure/Error: Unable to find matching line from backtrace
SystemStackError:
stack level too deep
# /usr/lib/ruby/1.9.1/forwardable.rb:185
I also tried different way of renaming my routes, but none of them worked. I'm back to the tutorial version.
If it can be of any help in finding what exactly is a problem, I'm on Ubuntu 11.10, with rails 3.2.1 and ruby 1.9.2p290. Hope you can help, I spend quite a while googling for a solution and didn't find any ^^'
Named routes should work if you put the following in rspec_helper.rb:
RSpec.configure do |config|
config.include Rails.application.routes.url_helpers
...
end
Is that how you set it up?
I don't think you have access to named routes inside of your rspec controller specs. You could however just do visit('/'), which is the equivalent of root_path.
Google brought me here, even my error message doesn't fit 100%.
In my case Capybara command visitis unknown...
Error:
NoMethodError:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0xa49a73c>
Since Capybara 2.0 one has to use folder spec/features capybara commands don't work in folder spec/requests anymore.
That helped me:
http://alindeman.github.com/2012/11/11/rspec-rails-and-capybara-2.0-what-you-need-to-know.html
Hope you find this usefull.
I had the same problem, with the same Tutorial. It turns out that I needed to just restart the Spork service, and all worked fine.
The solution posted by Tom L worked for me, but when I removed that line and restarted Spork, that also fixed the problem.
Hope that helps out any other people who are wary about deviating from the tutorial's code!
You should have used
rails generate rspec:install
instead of
rspec --init
and you wouldn't have had to modify the config file.
Don't do it now though or your application will break and you'll have to waste some more time figuring out why it broke.
Named routes should work if you put the following in rails_helper.rb not the spec_helper.rb:
checkout at my rails_helper.rb code
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
# Prevent database truncation if the environment is production
if Rails.env.production?
abort('The Rails environment is running in production mode!')
end
require 'rspec/rails'
require 'capybara/rails'
RSpec.configure do |config|
config.include Rails.application.routes.url_helpers
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
config.include Warden::Test::Helpers
end
begin
ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
puts e.to_s.strip
exit 1
end
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
# Filter lines from Rails gems in backtraces.
config.filter_rails_from_backtrace!
end
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