I'm newbie on rails and testing rails applications. I try to test an existing rails application with rspec. I've just finished model tests and i have to complete controller tests too.But i have a problem with sign_in method on rspec. I've tried all solution methods on the internet but still i can't sign in like a user with rspec.
here is the my controller code, it's too simple;
class AboutController < ApplicationController
def index
end
def how_it_works
end
def what_is
end
def creative_tips
end
def brand_tips
end
def we_are
end
def faq
end
end
and here is the my spec code;
require 'spec_helper'
describe AboutController do
before(:all) do
#customer=Factory.create(:customer)
sign_in #customer
end
context 'index page :' do
it 'should be loaded successfully' do
response.should be_success
end
end
end
Here is the my factory code;
Factory.define :unconfirmed_user, :class => User do |u|
u.sequence(:user_name) {|n| "user_#{n}"}
u.sequence(:email){|n| "user__#{n}#example.com"}
u.sequence(:confirmation_token){|n| "confirm_#{n}"}
u.sequence(:reset_password_token){|n| "password_#{n}"}
u.password '123456'
u.password_confirmation '123456'
u.user_type :nil
end
Factory.define :user, :parent => :unconfirmed_user do |u|
u.confirmed_at '1-1-2010'
u.confirmation_sent_at '1-1-2010'
end
Factory.define :customer, :parent => :user do |u|
u.user_type :customer
end
Finally here is the my spec_helper code
ENV["RAILS_ENV"] ||= 'test'
require File.dirname(__FILE__) + "/../config/environment" unless defined?(Rails)
require 'rspec/rails'
require "paperclip/matchers"
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
RSpec.configure do |config|
config.include Paperclip::Shoulda::Matchers
end
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
RSpec.configure do |config|
config.mock_with :rspec
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
end
gem file;
gem 'rails', '3.0.3'
gem 'mysql2', '< 0.3'
.
.
.
gem "devise" , "1.1.5"
.
.
.
group :test do
gem 'shoulda'
gem "rspec-rails", "~> 2.11.0"
gem "factory_girl_rails"
end
and here is the error;
Failures:
1) AboutController index page : should be loaded successfully
Failure/Error: sign_in #customer
NoMethodError:
undefined method `env' for nil:NilClass
# ./spec/controllers/about_controller_spec.rb:7:in `block (2 levels) in <top (required)>'
solution must be too easy but I'm newbie on rails and i can't find it :(
You have to make the sign-in step inside the it block in order for rspec to be able to access the response, e.g.:
it 'should be loaded successfully' do
sign_in #customer
response.should be_success
end
You have no subject.
require 'spec_helper'
describe AboutController do
before(:all) do
#customer=Factory.create(:customer)
sign_in #customer
end
context 'index page :' do
subject { Page }
it 'should be loaded successfully' do
response.should be_success
end
end
end
You might need to visit customers_path.
Related
Im writing some tests for my controller, but im getting the error below when i'm running rspec ./spec/controllers, when i just run the spec direct in the file i'm getting everything green.
1) VersionOne::UsersController GET #actives should return all actives
Failure/Error: get :actives
ActionController::UrlGenerationError:
No route matches {:action=>"actives", :controller=>"version_one/users"}
# ./spec/controllers/version_one/users_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
2) VersionOne::UsersController GET #archived should return all archives
Failure/Error: get :archives
ActionController::UrlGenerationError:
No route matches {:action=>"archives", :controller=>"version_one/users"}
# ./spec/controllers/version_one/users_controller_spec.rb:23:in `block (3 levels) in <top (required)>'
3) VersionOne::UsersController POST #create should create a new collaborator with success
Failure/Error: post :create, params: params
This is my controller
class UsersController < ApiControler
def actives
users = User.actives
render json: users
end
def archives
users = User.archiveds
render json: users
end
def create
user = User.build(user_params)
render json: user
end
end
This are my routes
scope 'api' do
scope 'v1', module: 'version_one' do
resources 'users' do
collection do
get 'actives'
get 'archives'
end
member do
match 'active'
match 'archive'
end
end
end
end
This are my tests
RSpec.describe VersionOne::UsersController, type: :controller do
before(:all) do
7.times { Collaborator.build(attributes_for(:user)) }
8.times { Admin.build(attributes_for(:user)) }
5.times { Collaborator.build(attributes_for(:user)).archived! }
end
describe "GET #actives" do
it "should return all actives" do
get :actives
body = JSON.parse(response.body)
expect(response).to have_http_status(:success)
expect(body["pagination"]["per_page"]).to eq(20)
expect(body["pagination"]["total_objects"]).to eq(15)
end
end
describe "GET #archived" do
it "should return all archives" do
get :archives
body = JSON.parse(response.body)
expect(response).to have_http_status(:success)
expect(body["pagination"]["per_page"]).to eq(20)
expect(body["pagination"]["total_objects"]).to eq(5)
end
end
describe "POST #create" do
it "should create a new collaborator with success" do
params = { kind: "Collaborator", user: { name: "User", email: "user#email.net", password: "123456", cpf: "36156291830" } }
post :create, params: params
body = JSON.parse(response.body)
expect(response).to have_http_status(:success)
expect(body).to include(
"name" => "User",
"cpf" => "36156291830",
"email" => "user#email.net",
)
end
end
end
this is my .rspec
--color
--format documentation
--require rails_helper
this is my rails_helper
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'shoulda-matchers'
require 'rack/test'
require 'faker'
require 'rake'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.include Shoulda::Matchers::ActiveModel, type: :model
config.include Shoulda::Matchers::ActiveRecord, type: :model
config.fixture_path = "#{::Rails.root}/spec/factories"
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean_with(:truncation)
end
config.use_transactional_fixtures = false
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
end
am'i forgetting something?
You do not have namespaces for UsersController
try:
module Api
module VersionOne
class UsersController < ApiController
# your code
end
end
end
You may also need to change ApiController to Api::VersionOne::ApiController
I keep getting Factory not registered: user (ArgumentError)
when I try to run my test files with factory_girl_rails. I read several post about that and tried to follow each of them without any success. In my gemfile I have the gem 'factory_girl_rails':
group :development, :test do
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'annotate'
gem 'better_errors'
gem 'binding_of_caller'
gem 'letter_opener'
gem 'pry-byebug'
gem 'pry-rails'
gem 'quiet_assets'
gem 'spring'
end
I have a spec folder in my project with different folders inside :
controllers, factories, models, lib and support.
In my spec folder I have a spec_helper.rb :
require 'factory_girl_rails'
FactoryGirl.find_definitions
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.include FactoryGirl::Syntax::Methods
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end
end
and a rails_helper.rb :
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'devise'
require_relative 'support/controller_macros'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
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
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
end
Inside my factories' folder, I have files for each one of my models for instance tournaments.rb :
require 'factory_girl_rails'
FactoryGirl.define do
factory :tournament do |f|
f.user FactoryGirl.create(:user)
f.accepted [true, false].sample
f.amount { Faker::Number.number(2) }
f.starts_on { Faker::Date.between(2.days.ago, Date.today) }
f.ends_on { Faker::Date.forward(23) }
f.address {Faker::Address.street_address}
f.city { Faker::Address.city }
f.name { Faker::Lorem.sentence }
f.club_organisateur { Faker::Company.name }
f.homologation_number {Faker::Company.swedish_organisation_number}
f.postcode { Faker::Address.postcode }
f.young_fare { Faker::Number.number(2) }
f.iban "jjddjjdjdjdjddj"
f.bic "djdjdjdjdjdjdjdjd"
f.club_email { Faker::Internet.email }
f.region "Ile de France"
end
end
Inside controllers folder, I have for instance tournaments_controller_spec.rb that looks like this :
require 'rails_helper'
require 'factory_girl_rails'
require 'spec_helper'
describe TournamentsController do
render_views
login_user
describe "index" do
it "returns a valid html_body" do
get :index
expect(response.body).to include("Il n'y a pas encore de tournoi référencé sur WeTennis")
end
end
describe "show" do
it "returns a valid tournament si le tournament n'est pas fini" do
get :show
expect(response.body).to include("s'inscrire")
end
end
end
and inside models folder for instance tournament_spec.rb :
require 'rails_helper'
require 'factory_girl_rails'
require 'spec_helper'
describe Tournament do
it "has a valid factory" do
FactoryGirl.create(:tournament).should be_valid
end
it "is invalid without a start date" do
FactoryGirl.build(:tournament, start_date: nil).should_not be_valid
end
it "is invalid without a end date" do
FactoryGirl.build(:tournament, end_date: nil).should_not be_valid
end
it "is invalid without a user" do
FactoryGirl.build(:tournament, user: nil).should_not be_valid
end
end
My users factory looks exactly like the others in folder factories (users.rb)
require 'factory_girl_rails'
FactoryGirl.define do
factory :user do |f|
f.first_name { Faker::Name.first_name}
f.last_name { Faker::Name.last_name }
f.password { Faker::Internet.password}
f.licence_number { Faker::Lorem.sentence }
f.email { Faker::Internet.email }
end
end
same for my user_spec.rb inside my models folder :
require 'rails_helper'
require 'factory_girl_rails'
require 'spec_helper'
describe User do
it "has a valid factory" do
FactoryGirl.create(:user).should be_valid
end
it "is invalid without an email" do
FactoryGirl.build(:user, email: nil).should_not be_valid
end
it "is invalid without a password" do
FactoryGirl.build(:user, password: nil).should_not be_valid
end
end
Why am I getting this error ?
I suspect the problem is your use of the user factory in the tournament factory (and maybe others):
factory :tournament do |f|
f.user FactoryGirl.create(:user)
FactoryGirl allows you to created associated objects quite simply (see the relevant section their documentation). To add an associated object which is created by a factory you can just do:
f.user
This will cause FactoryGirl to create a user object using the equivalent of FactoryGirl.create(:user) when a tournament is created.
Note also that you don't need the f. prefix. It should work find without.
The reason that it is causing an error is that the code FactoryGirl.create(:user) is being executed when your tournament factory loads and the user factory hasn't been loaded at that point. For stuff like: region 'Ile de France it doesn't matter because the string can be evaluated fine but for another factory call it does matter because the factory has to be defined already.
My controller specs are passing when I run them one by one but are all failing when I run them together as controllers.
$rspec spec/controllers
22) SubjectsController GET index assigns all subjects as #subjects
Failure/Error: get :index, {}
ActionController::RoutingError:
No route matches {:controller=>"subjects"}
# ./spec/controllers/subjects_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
My guess is it must be something to do with database cleaner but I'm not sure best way to troubleshoot routing errors in controller specs.
Gemfile
gem 'rails', '3.2.13'
gem 'mysql2', '0.3.13'
gem 'devise', '2.2.3'
...
...
group :development, :test do
gem 'rspec-rails', '~> 2.99'
gem 'webrick', '~> 1.3'
gem 'rails-erd', '~> 1.1'
gem 'bullet', '~> 4.6'
gem 'pry-rails', '~> 0.3'
gem 'factory_girl_rails', '~> 4.4'
gem 'faker', '~> 1.2'
end
group :test do
gem 'cucumber-rails', :require => false
gem 'capybara', '~> 2.2.1'
gem 'database_cleaner', '~> 1.3.0'
gem 'launchy', '~> 2.4.2'
gem 'shoulda-matchers', '~> 2.6.1'
gem 'vcr', '~> 2.9.2'
gem 'webmock', '~> 1.13.0'
gem 'zeus', '~> 0.13.3'
end
spec/spec_helper.rb
# 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 'rake'
require 'sidekiq/testing'
Sidekiq::Logging.logger = nil
# 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
config.mock_with :rspec
# Only run tests that have this filter, if it exists
# config.filter_run :debug => true
# Run all the tests when all the tests are filtered
# config.run_all_when_everything_filtered = true
config.treat_symbols_as_metadata_keys_with_true_values = true
# 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 = false
# 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
config.include FactoryGirl::Syntax::Methods
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new( {
provider: 'facebook',
uid: '123545',
info: {
first_name: 'John',
last_name: 'Doe',
email: 'johndoe#gmail.com'
},
credentials: {
token: "123456",
expires_at: Time.now + 1.week
},
extra: {
raw_info: {
gender: 'male'
}
}
})
# silence rspec 3 deprecation warnings
config.expose_current_running_example_as :example
config.infer_spec_type_from_file_location!
def login(user)
#request.env["devise.mapping"] = Devise.mappings[:user]
#user = user
#user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the confirmable module
allow(controller).to receive(:current_user).and_return(#user)
sign_in #user
end
def logged_user
#user
end
end
spec/support/database_cleaner.rb
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
load "#{Rails.root}/db/seeds.rb"
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
spec/controllers/subjects_controller_spec.rb
require 'spec_helper'
describe SubjectsController, :type => :controller do
before(:each) do
login create(:admin)
end
describe "GET index" do
it "assigns all subjects as #subjects" do
subject = create(:subject)
get :index, {}
expect(assigns(:subjects)).to include(subject)
end
end
describe "GET show" do
it "assigns the requested subject as #subject" do
subject = create(:subject)
get :show, {:id => subject.to_param}
expect(assigns(:subject)).to eq(subject)
end
end
describe "GET new" do
it "assigns a new subject as #subject" do
get :new, {}
expect(assigns(:subject)).to be_a_new(Subject)
end
end
describe "GET edit" do
it "assigns the requested subject as #subject" do
subject = create(:subject)
get :edit, {:id => subject.to_param}
expect(assigns(:subject)).to eq(subject)
end
end
describe "POST create" do
describe "with valid params" do
it "creates a new Subject" do
expect {
post :create, {:subject => attributes_for(:subject) }
}.to change(Subject, :count).by(1)
end
it "assigns a newly created subject as #subject" do
post :create, { :subject => attributes_for(:subject) }
expect(assigns(:subject)).to be_a(Subject)
expect(assigns(:subject)).to be_persisted
end
it "redirects to the created subject" do
post :create, {:subject => attributes_for(:subject) }
expect(response).to redirect_to(subjects_path)
end
end
describe "with invalid params" do
it "assigns a newly created but unsaved subject as #subject" do
allow_any_instance_of(Subject).to receive(:save).and_return(false)
post :create, {:subject => {}}
expect(assigns(:subject)).to be_a_new(Subject)
end
it "re-renders the 'new' template" do
allow_any_instance_of(Subject).to receive(:save).and_return(false)
post :create, { :subject => {} }
expect(response).to render_template("new")
end
end
end
describe "PUT update" do
describe "with valid params" do
it "updates the requested subject" do
#subject = create(:subject, name: "Alice")
put :update, id: #subject, subject: attributes_for(:subject, name: "Bob")
#subject.reload
#subject.name.should eq("Bob")
end
it "assigns the requested subject as #subject" do
#subject = create(:subject)
put :update, {:id => #subject, :subject => attributes_for(:subject) }
expect(assigns(:subject)).to eq(#subject)
end
it "redirects to the subject" do
#subject = create(:subject)
put :update, {:id => #subject, :subject => attributes_for(:subject) }
expect(response).to redirect_to(edit_subject_path)
end
end
describe "with invalid params" do
it "assigns the subject as #subject" do
#subject = create(:subject)
allow_any_instance_of(Subject).to receive(:save).and_return(false)
put :update, {:id => #subject, :subject => {}}
expect(assigns(:subject)).to eq(#subject)
end
it "re-renders the 'edit' template" do
#subject = create(:subject)
allow_any_instance_of(Subject).to receive(:save).and_return(false)
put :update, {:id => #subject, :subject => {}}
expect(response).to render_template("edit")
end
end
end
describe "DELETE destroy" do
it "destroys the requested subject" do
subject = create(:subject)
expect {
delete :destroy, {:id => subject.id}
}.to change(Subject, :count).by(-1)
end
it "redirects to the subjects list" do
subject = create(:subject)
delete :destroy, {:id => subject.id }
expect(response).to redirect_to(subjects_url)
end
end
end
rake routes
suggested_subjects GET /suggested_subjects(.:format) suggested_subjects#index
make_preferred_subject PUT /subjects/:id/make_preferred(.:format) subjects#make_preferred
subjects GET /subjects(.:format) subjects#index
POST /subjects(.:format) subjects#create
new_subject GET /subjects/new(.:format) subjects#new
edit_subject GET /subjects/:id/edit(.:format) subjects#edit
subject GET /subjects/:id(.:format) subjects#show
PUT /subjects/:id(.:format) subjects#update
app/controllers/subjects_controller.rb
class SubjectsController < ApplicationController
load_and_authorize_resource
def index
#subjects = Subject.filter(params)
respond_to do |format|
format.html
format.json { render json: {total: #subjects.count, subjects: #subjects}.to_json }
end
end
....
....
end
Figured it out.
The ActionController::RoutingError was a result of another controller spec which was calling:
routes.draw
This call wiped out the routes for subsequent specs. The solution for now (thanks to:
http://pivotallabs.com/adding-routes-for-tests-specs-with-rails-3/ ) was to add:
after do
# be sure to reload routes after the tests run, otherwise all your
# other controller specs will fail
Rails.application.reload_routes!
end
Also helpful were:
https://github.com/rspec/rspec-rails/issues/817
https://github.com/rspec/rspec-rails/issues/636
Hope this helps and good luck!
gemfile:
source 'https://rubygems.org'
gem 'rails', '4.1.1'
gem 'mysql2
spec/spec_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment",__FILE__)
require 'rspec/rails'
require "capybara/rspec"
include Capybara::DSL
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
end
spec/support/controller_macros.rb
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
def load_key
session[:master_key] = SecureRandom.hex(24)
end
end
spec/factories/factory.rb
FactoryGirl.define do
factory :user do
email "test#test.com"
password "12345678"
end
end
categories_controller.rb
class CategoriesController < ApplicationController
before_filter :authenticate_user!, :load_key!
def index
#categories = Category.where("user_id is null or user_id = ?", current_user).order(updated_at: :desc)
end
private
def category_params
params.require(:category).permit(:title)
end
end
spec/controllers/categories_controller_spec.rb
require 'rails_helper'
describe CategoriesController do
login_user
load_key
it "get list of categories" do
get :index
expect(response).to render_template("index")
end
end
application_controller.rb
class ApplicationController < ActionController::Base
def load_key!
redirect_to(key_path) unless session[:master_key]
end
end
I would like to bypass a load_key! before_filer in CategoriesController. I added method load_key to controller_macros.rb. But it gives me the error:
undefined local variable or method 'session' for RSpec::ExampleGroups::CategoriesController:Class (NameError) from d:/sites/key_manager/spec/support/controller_macros.rb:19:in `load_key'
Looks like session variable is unavailable under rspec.
The answer was a quite simple.
I should use request.session rather than session.
In this case I should transfer a session variable assign from controller_macros.rb to categories_controller_spec.rb:
categories_controller_spec.rb
require 'rails_helper'
require 'spec_helper'
describe CategoriesController, :type => :controller do
login_user
it "redirect to key form when key was't loaded" do
get :index
expect(response).to redirect_to(key_path)
end
it "view password list #index" do
request.session[:master_key] = SecureRandom.hex(24) # <======================
get :index
expect(response).to render_template(:index)
end
end
controller_macros.rb
module ControllerMacros
def login_admin
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:admin]
sign_in FactoryGirl.create(:admin) # Using factory girl as an example
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
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