I have setup Rspec2 + Spork + Guard + Devise
My files are as follows
#spec_helper.rb
Spork.prefork do
#code
Dir[Rails.root.join('spec/support/**/*.rb')].each {|f| require f}
RSpec.configure do |config|
config.extend ControllerMacros, :type => :controller
end
end
Spork.each_run do
# This code will be run each time you run your specs.
FactoryGirl.reload
include ControllerMacros
end
#spec/support/controller_macros.rb
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mapping[:user]
user = FactoryGirl.create(:user)
sign_in user
end
end
end
#spec/support/devise.rb
Spec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
in my request spec
#spec/features/documents_spec.rb
require 'spec_helper'
describe "Documents" do
login_user
describe "GET /documents" do
it "should display document name as sameera CV" do
#spec code
end
end
end
and when I run bundle exec guard, I get
1) Documents GET /documents should display document name as sameera CV
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `env' for nil:NilClass
# ./spec/support/controller_macros.rb:4:in `block in login_user'
So far I have done lots of fixes via google and nothing seems to be working, can someone help me :)
I'm on
rails 3.2.9
rspec 2.12.0
devise 2.2.3
any help would be greatly appreciated
Try changing #request.env["devise.mapping"] = Devise.mapping[:user] to request.env["devise.mapping"] = Devise.mapping[:user] in spec/support/controller_macros.rb
Here I'm answering my own question, and I was able to find a workaround for the question I asked.
Following are the steps I did
1) removed the controller_macros.rb and devise.rb from support directory
2) removed the ControllerMacros references from spec_helper.rb
3) Added the following code to
#spec/features/documents_spec.rb
before(:each) do
user = FactoryGirl.create(:user)
visit root_path
fill_in 'user_email', :with => user.email
fill_in 'user_password', :with => user.password
click_button 'Sign in'
end
I'm sure there should be a more elegant way (as describe in devise wiki), but this WORKS :)
Related
The Devise sign_in method is supposed to accept store: false as a second parameter, which it seems to do that fine unless I'm in RSpec and using the Devise::TestHelpers.
When I run this test from sessions_controller_spec.rb:
require 'rails_helper'
describe Api::V1::SessionsController do
before(:each) do
#user = FactoryGirl.create :user
end
...
describe 'DELETE #destroy' do
before(:each) do
sign_in #user, store: false
delete :destroy, id: #user.auth_token
end
it { should respond_with 204 }
end
end
I get this failure:
I have got the same problem. According to Devise website, there is no such method.
Try to remove the "store: false" parameter and run it again. It solved my problem.
...
describe 'DELETE #destroy' do
before(:each) do
sign_in #user
delete :destroy, id: #user.auth_token
end
it { should respond_with 204 }
...
And remember to put the following inside a file named spec/support/devise.rb or in your spec/spec_helper.rb (or spec/rails_helper.rb if you are using rspec-rails
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
end
Take a look on this link
I just started some tests on my Rails application in which I use Devise for authentication. I just generated rspec and only added
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
to my spec/support/devise.rb file.
I also added Capybara to the test group in my gemfile, run the bundle command, etc. But as I do visit in my tests, I get a no method error. Here an example of my user_spec.rb:
require 'spec_helper'
describe "Club" do
before(:each) do
#club ||= FactoryGirl.create(:club)
FactoryGirl.create(:membership)
User.all.each{|x| x.delete}
end
describe "privacy" do
it "shouldn't be shown any tournament if the user is private" do
attributes = FactoryGirl.attributes_for(:user)
user = User.create!({private: true}.merge(attributes))
assert(user.private)
visit "/user/#{user.id}/tournaments"
page.should have_no_selector(".tournament-list")
end
end
end
As I run rspec there comes an error like this:
Failures:
1) Club privacy shouldn't be shown any tournament if the user is private
Failure/Error: visit "/user/#{user.id}/tournaments"
NoMethodError:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_3::Nested_1:0x007ff0ea113108>
# ./spec/user_spec.rb:14:in `block (3 levels) in <top (required)>'
For capybara specs I use:
describe "Club", :type => :feature, :js => true do
include Capybara::DSL
it "..."
end
And instead User.all.each{|x| x.delete}, use DatabaseCleaner
You can easily add the Capybara::DSL to RSpec config spec_helper.rb
RSpec.configure do |config|
.....
.......
config.include(Capybara::DSL)
end
I am using Rspec, FactoryGirl and Spork for my tests.There are 2 things I am a litte unclear on, first is the location of my factories.rb file. At present I have it located in
spec/support/factories.rb
And it looks like this
FactoryGirl.define do
factory :user do
email "example#yahoo.com"
password "password"
password_confirmation "password"
confirmed_at Time.now
end
end
Within my spec_helper I have
config.include FactoryGirl::Syntax::Methods
Secondly I want to login a user before starting my tests for a controller , this particular controller has a before filter :authenticate_user!
I am using devise for my authentication so have added
config.include Devise::TestHelpers, :type => :controller
Reading the devise docs you can add a controller_macros.rb and specify methods like so to use
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
And so i added this also to my spec_helper
config.include ControllerMacros, :type => :controller
So when I add login_user before my controller tests i get undefined method login_user. Am i using two tools here to do the same thing? Do I actually need the devise methods or can it all be done with factoryGirl. If so how do i setup the login process before i can test a controller?
Factories location should be in spec/factories. Check out this example app https://github.com/RailsApps/rails3-devise-rspec-cucumber/tree/master/spec.
For login, generally you seems to doing it right. Check the example app again and here: https://github.com/plataformatec/devise/wiki/How-To:-Controllers-and-Views-tests-with-Rails-3-%28and-rspec%29
For the undefined method login_user error be sure to have
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
and
config.extend ControllerMacros, :type => :controller
in spec_helper. Devise methods should be available wtih subject:
subject.current_user.should_not be_nil
I'm working on a training app which is an Ogame-Like game (https://github.com/arnlen/ogame-like).
I'm using rspec (with Capybara) in order to test my app.
I'm stacked for several hours because rspec is complaining for an error which *I can't reproduce * by myself with my browser.
Here is my rspec code :
describe 'Planet pages' do
let(:user){FactoryGirl.create(:user)}
before {sign_in user}
subject {page}
describe "new planet page" do
before {visit new_planet_path}
describe "with valid information" do
before do
visit new_planet_path
fill_in "Name", with: "MyPlanet"
click_button "Validate"
end
# This test doesn't pass
it {should have_selector('h1', text: "Planet")}
end
end
end
The failure :
1) Planet pages new planet page with valid information
Failure/Error: it {should have_selector('h1', text: "Planet")}
expected css "h1" with text "Planet" to return something
# ./spec/requests/planet_pages_spec.rb:34:in `block (4 levels) in <top (required)>'
Here is the involved code.
My function "sign_in" used by rspec (location : spec/support/utilities.rb)
def sign_in(user)
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
My UsersController
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :show, :edit, :update, :destroy]
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
redirect_to new_planet_path
else
render 'new'
end
[...]
My PlanetsController
class PlanetsController < ApplicationController
before_filter :signed_in_user
def index
#planets = current_user.planets
end
def new
#planet = Planet.new
end
def create
#planet = Planet.new(name: params[:planet][:name],
coordinates: generate_coordinates,
metal_ressource: 1000,
user_id: current_user.id)
if #planet.save
flash[:success] = "Welcome on your first planet!"
redirect_to action: 'index'
else
flash[:error] = "Error naming your planet"
render 'new'
end
end
end
And My Planet Index view
<% #planets.each do |planet| %>
<h1>Planet : <%= planet.name %></h1>
<p><%= "Coordinates : #{planet.coordinates}" %></p>
<% end %>
I tried to user the Capybara method "save_and_open_page", but rspec raised an error "undefined method"
I also tried step by step debugging by iterations on my spec file, and it revealed that the error occurs right after the "click_button 'Validate'". For an unknown reason, rspec seems not to be able to reach the planets_path ("index" action from PlanetsController).
I'm out, if anybody has an idea, I take it !
EDIT : SOLVED - Found the problem!
Using the "save_and_open_page" method from Capybara, I figured out what was going on: the planet created by rspec didn't have any coordinates, which was not allowed by the model.
How to debug with the wonderful "save_and_open_page" method
Add this to your gemfile : "gem 'launchy'"
Install it : bundle install
Put the command "save_and_open_page" wherever you want
Hope it could help. :)
Capybara also has a save_page method, which is easier to use as it does not seem to need the "launchy" gem. The pages are saved in tmp/capybara. In the rspec tests, be sure to use save_page inside before, it, or some other block. It will not work as a separate command. Example:
before { visit signup_path; save_page }
Working through Michael Hartl's RailsTutorial and came across the following error - even though I have followed everything to the 'T'.
1) UsersController GET 'index' for signed-in users should have an element for each user
Failure/Error: response.should have_selector("li", :content => user.name)
undefined method `name' for #<Array:0x000001032c07c8>
Did anyone else get a similar error and know how to fix it?
I am in Chapter 10.
Btw, when I try the page it does what it is supposed to do. It's just that the test fails in RSpec.
FYI, here is the related test code from the users_controller_spec.rb
require 'spec_helper'
describe UsersController do
render_views
describe "GET 'index'" do
describe "for non-signed-in users" do
it "should deny access" do
get :index
response.should redirect_to(signin_path)
flash[:notice].should =~ /sign in/i
end
end
describe "for signed-in users" do
before(:each) do
#user = test_sign_in(Factory(:user))
second = Factory(:user, :email => "another#example.com")
third = Factory(:user, :email => "another#example.net")
#users = [#user, second, third]
end
it "should be successful" do
get :index
response.should be_success
end
it "should have the right title" do
get :index
response.should have_selector("title", :content => "All users")
end
it "should have an element for each user" do
get :index
#users.each do |user|
response.should have_selector("li", :content => user.name)
end
end
end
end
My spec/spec_helper.rb file looks like the following:
require 'rubygems'
require 'spork'
Spork.prefork do
# Loading more in this block will cause your tests to run faster. However,
# if you change any configuration or code from libraries loaded here, you'll
# need to restart spork for it take effect.
ENV["RAILS_ENV"] ||= 'test'
unless defined?(Rails)
require File.dirname(__FILE__) + "/../config/environment"
end
require 'rspec/rails'
# Requires supporting files with custom matchers and macros, etc,
# in ./support/ and its subdirectories.
Dir["#{File.dirname(__FILE__)}/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
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, comment the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
### Part of a Spork hack. See http://bit.ly/arY19y
# Emulate initializer set_clear_dependencies_hook in
# railties/lib/rails/application/bootstrap.rb
ActiveSupport::Dependencies.clear
def test_sign_in(user)
controller.sign_in(user)
end
def integration_sign_in(user)
visit signin_path
fill_in :email, :with => user.email
fill_in :password, :with => user.password
click_button
end
end
end
Spork.each_run do
end
it appears your test_sign_in method is returning an instance of an array rather than a User object. Are you explicitly returning a user object in the test_sign_in method? If not, have a look at the last line that's executed in that method, I have a feeling the result of it is an array.
I solved this issue, and the answer can be found on the railstutorial official forums.