Hello so i keep getting this error, although i tried some of the solutions posted around here
spec/support/devise.rb
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
end
accounts_spec.rb
require "rails_helper"
RSpec.describe Api::V1::AccountsController, :type => :controller do
describe "GET index no account" do
it "has a 403 status code" do
get :index
expect(response.status).to eq(403)
end
end
describe "GET index with account" do
it "has a 200 status code" do
sign_in #user
get :index
expect(response.status).to eq(200)
end
end
end
accounts_controller.rb
class Api::V1::AccountsController < ApplicationController
skip_before_action :verify_authenticity_token
def index
#show user details
raise if not current_user
render json: { :user => current_user.as_json(:except=>[:created_at, :updated_at, :authorization_token, :provider, :uid, :id])}
rescue
render nothing: true, status: 403
end
Any ideas ? i'm blocked, the first test for 403 works, but then i just can't use the sign_in of devise ...
The problem was the devise.rb files. The correct config lines were
config.include Devise::TestHelpers, type: :controller
config.include Devise::TestHelpers, type: :view
Looks like the config is not being run.
Make sure you have your spec/support/devise.rb included by something like
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
in rails_helper.rb
Or move these config.includes into rails_helper itself
You can directly use This in your rails helper
config.include Devise::TestHelpers, :type => :controller
To use sign_in method.
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
Devise: 4.20
Rails: 5.0.1
Rspec: 3.5
I had used this link https://github.com/plataformatec/devise/wiki/How-To:-Use-HTTP-Basic-Authentication, but I havproblems to test the http basic auth for my api using rspec for requests tests. Below is the example the error:
app/controllers/api/base_controller.rb
module Api
class BaseController < ApplicationController
before_action :authenticate_user!
protected
def authenticate_user!
authenticate_or_request_with_http_basic do |username, password|
resource = User.find_by_username(username)
if resource
sign_in :user, resource if resource.valid_password?(password)
else
request_http_basic_authentication
end
end
end
end
end
app/controllers/api/v1/car_controller.rb
module Api
module V1
class CarController < Api::BaseController
respond_to :json
def index
#cars = Car.all
render :json => {:content => #cars}, :status => 200
end
end
end
end
spec/requests/api/v1/car_controller_spec.rb
require 'rails_helper'
RSpec.describe "Servers API", :type => :request do
it 'sends a list of servers' do
admin = FactoryGirl.create(:admin)
#env = {}
#env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(admin.username, admin.password)
get "/api/cars", :params => {}, :headers => #env
# test for the 200 status-code
expect(response.status).to eq(200)
end
end
When I run the spec, I have the below error:
# --- Caused by: ---
# NoMethodError:
# undefined method `sign_in' for #<Api::V1::CarController:0x0000000609ef12>
# ./app/controllers/api/base_controller.rb:10 in block in authenticate_user!
Anyone can help me? Thanks.
I have similar setup where my specs are passing, would you also show your spec_helper content, looks like you are not including Devise::TestHelpers.
spec_helper
RSpec.configure do |config|
config.include Devise::TestHelpers
config.include Warden::Test::Helpers
config.before { Warden.test_mode! }
config.after { Warden.test_reset! }
config.before(:each) do
#headers = { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' }
end
end
and my test looks something like this:
RSpec.describe 'Users' do
context 'when client is authorized' do
let(:user) { FactoryGirl.create(:user) }
it 'gets user' do
#headers['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.
encode_credentials(
user.authentication_token,
email: user.email
)
get api_v1_user_url(id: user.id), {}, #headers
expect(response.status).to eq(200)
end
end
end
I'm using Rails 5, and Devise 3.5.1.
Going through a nice (older) book about creating/testing an API, which uses Devise authentication. It was written before Rails 5, so I chose not to use the new api-only version.
Here's my test...
#/spec/controllers/api/v1/users_controller_spec.rb
require 'rails_helper'
describe Api::V1::UsersController, :type => :controller do
before(:each) { request.headers['Accept'] = "application/vnd.marketplace.v1" }
describe "GET #show" do
before(:each) do
#user = FactoryGirl.create :user
get :show, params: {id: #user.id}, format: :json
end
it "returns the information about a reporter on a hash" do
user_response = JSON.parse(response.body, symbolize_names: true)
expect(user_response[:email]).to eql #user.email
end
it { should respond_with 200 }
end
end
And here's a completely unexpected RSpec error
Devise::MissingWarden:
Devise could not find the `Warden::Proxy` instance on your request environment.
Make sure that your application is loading Devise and Warden as expected and that the `Warden::Manager` middleware is present in your middleware stack.
If you are seeing this on one of your tests, ensure that your tests are either executing the Rails middleware stack or that your tests are using the `Devise::Test::ControllerHelpers` module to inject the `request.env['warden']` object for you.
So I go here - http://www.rubydoc.info/gems/devise/Devise/Test/ControllerHelpers
and tried this -> include Devise::Test::ControllerHelpers
which didn't help because the file controller_helpers.rb is nowhere in my project
What did I miss here?
Thanks
You could add the following to your rails_helper:
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
end
This will include Devise::Test::ControllerHelpers module in all :controller specs.
In the spec_helper.rb add:
config.include Devise::Test::ControllerHelpers, :type => :controller
MiniTest, Rails 4
This works for vanilla Rails 4 MiniTest
test\controllers\users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
include Warden::Test::Helpers
include Devise::Test::ControllerHelpers
setup do
# https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara
# #user = users(:admin)
# sign_in #user
end
teardown do
Warden.test_reset!
end
test "login as admin" do
#user = users :admin
sign_in #user
get :dashboard
assert_redirected_to admin_dashboard_path
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 have a Rails app and I am trying to test it. I use devise to log in. However, I faced a problem that occurs when I want to test:
Users/ender/Projects/ratingw/spec/controllers/widgets_controller_spec.rb:4:in `block in <top (required)>': undefined local variable or method `login_user' for #<Class:0x007fe909bd5070> (NameError)
First, I want to say that I read this devise formal tutorial.
My spec_helper.rb is:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:twitter] = {
:provider => 'twitter',
:uid => '123545'
# etc.
}
OmniAuth.config.mock_auth[:twitter] = :invalid_credentials
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
config.include RequestMacros, :type => :request
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
end
module ::RSpec::Core
class ExampleGroup
include Capybara::DSL
include Capybara::RSpecMatchers
end
end
and also I have a controller_macros.rb, which is located in support file:
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
user = Factory(: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
and finally, my controller_spec file is:
require 'spec_helper'
describe WidgetsController do
login_user
describe "User" do
before(:each) do
#current_user = mock_model(User, :id => 1)
#widget = mock_model(Widget, :user_id => 1)
Widget.stub!(:current_user).and_return(#current_user)
Widget.stub!(:widgets).and_return(#widget)
end
it "should have a current_user" do
subject.current_user.should_not be_nil
redirect_to widgets_path
end
it "should not have a current_user" do
redirect_to widgets_path new_user_session_path
end
end
def mock_widget(stubs={})
#mock_widget ||= mock_model(Widget, stubs).as_null_object
end
describe "Get index" do
it "should get all widgets " do
Widget.stub(:all) { [mock_widget] }
get :index
assigns(:widgets) == #widgets
end
end
describe "Post widget" do
it "creates a new widget" do
Widget.stub(:new).with({'these' => 'params'}) { mock_widget(:save => true) }
post :create, :widget => {'these' => 'params'}
assigns(:widget) == #widgets
response.should redirect_to (edit_widget_path(#mock_widget))
end
it "can not create a new widget" do
Widget.stub(:new).with({'these' => 'params'}) { mock_widget(:save => false) }
post :create, :widget => {'these' => 'params'}
assigns(:widget) == #widgets
redirect_to new_widget_path
end
end
describe "Get widget" do
it "shows exact widget via its uuid" do
Widget.stub(:find).with("10") { mock_widget(:save => true) }
get :show
assigns(:widget) == #widget
end
end
describe "Put widget" do
it "updates the widget attributes" do
Widget.stub(:find_by_uuid).with("6").and_return(mock_widget(:update_attributes => true))
mock_widget.should_receive(:update_attributes).with({'these' => 'params'})
put :update, :uuid => "6", :widget => {'these' => 'params'}
response.should redirect_to (edit_widget_path(#mock_widget))
end
it "can not update the widget attributes" do
Widget.stub(:find_by_uuid).with("6").and_return(mock_widget(:update_attributes => false))
mock_widget.should_receive(:update_attributes).with({'these' => 'params'})
put :update, :uuid => "6", :widget => {'these' => 'params'}
end
end
describe "delete destroy" do
it "destroys the requested widget" do
Widget.stub(:find_by_uuid).with("10").and_return(mock_widget)
mock_widget.should_receive(:destroy)
get :destroy, :uuid => "10"
end
end
end
How can I fix this? What is the problem?
I guess the error stems from:
config.extend ControllerMacros, :type => :controller
You should have:
config.include ControllerMacros, :type => :controller