This is my current testing setup:
# spec/factories.rb
require 'factory_girl'
FactoryGirl.define do
# Roles
factory :user_role, :class => Role do
name 'User'
end
# Users
factory :user, :class => User do
sequence(:email) {|n| "email#{n}#example.com" }
password 'password'
password_confirmation 'password'
name 'Yuri Userington'
roles { |a| [a.association(:user_role)] }
end
# Instruments
factory :instrument, :class => Instrument do
title "Doobie Doo Instrument Title"
is_valid true
association :user, :factory => :user
end
# Sequences
sequence :email do
"email#{n}#factory.com"
end
end
# spec/controllers/instruments_controller_spec.rb
require 'spec_helper'
describe InstrumentsController do
before (:each) do
#instrument = FactoryGirl.create(:instrument)
#attr = FactoryGirl.attributes_for(:instrument)
#user = FactoryGirl.create(:user)
end
describe "GET index" do
it "assigns all instruments as #instruments" do
instrument = Instrument.new(#attr)
instrument.user = #user
instrument.save!
get :index
assigns(:instruments).should eq([instrument])
end
end
end
The result is that when i run my tests, i get the following errors in my output:
Failures:
1) InstrumentsController GET index assigns all instruments as #instruments
Failure/Error: #instrument = FactoryGirl.create(:instrument)
ActiveRecord::RecordNotFound:
Couldn't find Role with id=2
# ./app/models/user.rb:21:in `assign_role_after_sign_up'
# ./spec/controllers/instruments_controller_spec.rb:24:in `block (2 levels) in <top (required)>'
Based on that it seems like the roles association call in my :user factory is NOT being called -- what am i doing wrong here? Am i using this in a completely wrong way?
thank you!!
There is much to say here. Compare your code with the following to see how many lines or words were removed.
FactoryGirl.define do
# Sequences
sequence :email do |n|
"email#{n}#factory.com"
end
# Roles
factory :user_role, :class => Role do
name 'User'
end
# Users
factory :user do
email
password 'password'
password_confirmation 'password'
name 'Yuri Userington'
roles { |user| [Factory(:user_role)] } #many to many
end
# Instruments
factory :instrument, :class => Instrument do
title "Doobie Doo Instrument Title"
is_valid true
association :user #one-to-one or one-to-many
end
end
And in your tests:
describe InstrumentsController do
before (:each) do
#user = Factory(:user)
end
describe "GET index" do
it "assigns all instruments as #instruments" do
instrument = Factory(:instrument, :user => #user)
get :index
assigns(:instruments).should eq([instrument])
end
end
end
Moreover:
I personally prefer testing controller with mocks and stubs
I use let instead of instance variables and before_filter
I had a similar issues and I used a callback to assign roles like this:
Factory.define :user_with_admin_role, :parent => :user do |user|
user.after_create {|instance| instance.roles << Factory(:admin_role) }
end
So I think you should be able to do something akin to that:
# Users
factory :user, :class => User do
sequence(:email) {|n| "email#{n}#example.com" }
password 'password'
password_confirmation 'password'
name 'Yuri Userington'
after_create {|user| user.roles << Factory(:user_role) }
end
That is completely untested, so you may need to tweak things around.
Related
I am suffering for the third day, I can not understand why I do not pass the next test:
4) Error:
ArticlesControllerTest#test_should_get_index_if_admin:
CanCan::AccessDenied: You are not authorized to access this page.
test/controllers/articles_controller_test.rb:22:in `block in <class:ArticlesControllerTest>'
What am I doing wrong? help me please!
I have got old application (rails 4.2), with many fixtures data.
I try migrate my test environment from fixtures to factory_girl. So I'm new to this.
Now I'm using:
cancancan + devise
factory_girl + TestCase
My articles controller:
class ArticlesController < ApplicationController
load_and_authorize_resource
before_filter :authenticate_user!, except: [:show]
def index
#articles = Article.paginate(page: params[:page], per_page: 10).includes(:translations)
end
end
Ability.rb:
Class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
# Everybody
can :show, [Article]
if user.admin?
can :manage, Article
end
end
end
My factory article.rb is very simple:
FactoryGirl.define do
factory :article do
content "MyText"
factory :one_article
factory :two_article
end
end
My factory user.rb is simple too:
FactoryGirl.define do
factory :user do
sequence(:email) { |n| "user#{n}#mail.ru" }
password "password"
password_confirmation "password"
after(:create) {|u| u.roles_mask = 4}
profile
factory :valid_admin do
first_name "Administrator"
last_name "Administrator"
association :profile, factory: :admin_profile
after(:create) {|u| u.roles_mask = 2}
end
end
end
My articles controller test:
require 'test_helper'
class ArticlesControllerTest < ActionController::TestCase
include Devise::Test::ControllerHelpers
setup do
#article = create(:one_article)
#admin = create(:valid_admin)
end
test 'should get index if admin' do
sign_in #admin
ability = Ability.new(#admin)
assert ability.can? :index, Article
get :index
assert_response :success
assert_not_nil assigns(:articles)
end
end
Info by pry:
[1] pry(#<ArticlesControllerTest>)> sign_in #admin
=> [[20709], "9BET5RWNuJPrGHUFi86d"]
[2] pry(#<ArticlesControllerTest>)> ability = Ability.new(#admin)
=> #<Ability:0x0000000c3c5ff8
#rules=
[#<CanCan::Rule:0x0000000c3c5f80
#actions=[:show],
#base_behavior=true,
#block=nil,
.............<<Many lines>> ..............
[3] pry(#<ArticlesControllerTest>)> assert ability.can? :index, Article
=> true
[4] pry(#<ArticlesControllerTest>)> get :index
CanCan::AccessDenied: You are not authorized to access this page.
from /home/da/.rvm/gems/ruby-2.2.6#wenya/gems/cancancan-1.16.0/lib/cancan/ability.rb:217:in `authorize!'
Thanks in advance for your help!
This are the devise guideline, you need to create a method to log in the user as admin. This is the login_method you need to create
Controller tests (Test::Unit)
To sign in as admin for a given test case, just do:
class SomeControllerTest < ActionController::TestCase
# For Devise >= 4.1.1
include Devise::Test::ControllerHelpers
# Use the following instead if you are on Devise <= 4.1.0
# include Devise::TestHelpers
def setup
#request.env["devise.mapping"] = Devise.mappings[:admin]
sign_in FactoryGirl.create(:admin)
end
end
Note: If you are using the confirmable module, you should set a confirmed_at date inside the Factory or call confirm! before sign_in.
Here is the basics to prepare inside your Factory:
FactoryGirl.define do
factory :account do
email { Faker::Internet.email }
password "password"
password_confirmation "password"
confirmed_at Date.today
end
end
I'm trying to update a record in a request spec, but it's not updating. Doing it in real life works. Here is the spec:
describe "sessions" do
before do
#user = FactoryGirl.create(:user)
#api_key = FactoryGirl.create(:api_key)
end
it "is updated properly" do
put "/api/v1/users/#{#user.id}?user_email=#{#user.email}&auth_token=#{#user.authentication_token}", {user: {name: "New Name"}},{ "HTTP_AUTHORIZATION"=>"Token token=\"#{#api_key.access_token}\"" }
#user.name.should eq("New Name")
response.status.should be(201)
end
end
The above test fails with the error:
Failure/Error: #user.name.should eq("New Name")
expected: "New Name"
got: "nil"
(compared using ==)
Name is an optional parameter, so I just don't set it in the Factory. If I do set it the line says got: "Bill" for example.
and, for completeness, here are the factories:
FactoryGirl.define do
sequence :email do |n|
"test#{n}#vitogo.com"
end
factory :user do
email
password '12345678'
password_confirmation '12345678'
goal_id 1
experience_level_id 1
gender 'Female'
factory :admin do
after(:create) { |user| user.role = 'admin'; user.save }
end
end
end
FactoryGirl.define do
factory :api_key do
access_token "MyString"
end
end
You just need to reload #user after your PUT call, e.g. #user.reload.
In my user model, all users are assigned the role of user in a before_create callback. So I'm having a lot of trouble creating an admin user to use in some tests. Here is what I've tried, which is not working:
require 'spec_helper'
describe "Exercises" do
describe "GET /Exercises" do
it "gives the expected status code." do
sign_in_as_valid_user
#user.role = 'admin'
get exercises_path
response.status.should be(200)
end
for completeness, here is the method that is called:
module ValidUserRequestHelper
def sign_in_as_valid_user
FactoryGirl.create :program
#user ||= FactoryGirl.create :user
post_via_redirect user_session_path, 'user[email]' => #user.email, 'user[password]' => #user.password
end
end
and the factory:
FactoryGirl.define do
sequence :email do |n|
"test#{n}#vitogo.com"
end
factory :user do
email
password '12345678'
password_confirmation '12345678'
goal_id 1
experience_level_id 1
gender 'Female'
end
end
I'm just trying to change the role in the specific tests where it matters.
Any ideas how to do this? It's been driving me crazy. Thanks in advance!
I then edited my users Factory to create an Admin Factory that inherited from my User Factory, then assigned the admin role in an after(:create) callback like this:
factory :user do
email
password '12345678'
password_confirmation '12345678'
gender 'Male'
factory :admin do
after(:create) { |user| user.role = 'admin'; user.save }
end
end
Try wrapping the #user in a method, something like this in the ValidUserRequestHelper
def current_user
#user
end
Then calling current_user.role = 'admin' in your specs
Using FactoryBot, I'm having trouble creating a admin Factory in my specs because every user is assigned a default role of user in a before_create callback. This means that any role I assign a factory will be changed to user when the callback happens.
What I really want to do is something like this:
Inside my spec
admin = FactoryBot.create(:user)
admin.role = 'admin'
The second line, admin.role = 'admin' doesn't do anything. Any ideas?
I'm open to better ways of doing this as well.
There might be a way of reassigning the value to a FactoryBot (formerly FactoryGirl) instantiation, but RSpec negates the need:
describe User do
let(:user) { FactoryBot.create(:user) }
context 'when admin' do
let(:user) { FactoryBot.create(:user, admin: true) }
# ...
end
end
Try using a trait:
factory :user do
sequence(:username) { |n| "User ##{n}"}
role 'user'
trait :is_admin do
role 'admin'
end
end
Usage:
FactoryBot.create(:user, :is_admin)
Or eventually an after(:create):
factory :user do
sequence(:username) { |n| "user ##{n}"}
role 'user'
end
factory :user_admin, class: User do
after(:create) { |user| user.role = 'admin'; user.save } # don't know if the .save is necessary here
sequence(:username) { |n| "User Admin ##{n}"}
end
Just another way
# Steal some code from MrYoshiji at first.
factory :user do
sequence(:username) { |n| "User ##{n}"}
role 'user'
# Then a separate factory inside
factory :admin do
role 'admin'
end
end
# Use
FactoryBot.create(:admin)
I am using Ruby on Rails 3.0.10, RSpec 2 and FactoryGirl. I have the following scenario:
In the models/user_spec.rb file I have
describe User do
let(:user) { Factory(:user) }
it "should have a 'registered' authorization do
user.authorization.should == "registered"
end
end
In the factories/user.rb file I have
FactoryGirl.define do
factory :user, :class => User do |user|
user.authorization 'registered'
end
end
In the user.rb file I have:
class User < ActiveRecord::Base
DEFAULT_AUTHORIZATION = 'registered'
validates :authorization,
:inclusion => {
:in => Authorization.all.map(&:name),
:message => "authorization is not allowed"
},
:presence => true
before_validation :fill_user_create, :on => :create
private
def fill_user_create
self.authorization = Authorization::DEFAULT_AUTHORIZATION
end
end
When I run the rspec command I get the following error:
User should have a default 'registered' Authorization
Failure/Error: let(:user) { Factory(:user) }
ActiveRecord::RecordInvalid:
Validation failed: Users authorization is not allowed
What is exactly the problem and how can I solve that?
BTW: In the models/user_spec.rb file I can use something like the following
let(:user) { User.create }
and it will work, but I prefer to use the FactoryGirl gem. What do you advice about?
Could you try modifying your spec as below and check what the results are:
it "should have a 'registered' authorization" do
system_names = Authorization.all.map(&:system_name)
system_names.should have_at_least(1).item
system_names.should include('registered')
user.authorization.should == "registered"
end