Using rails, devise, rspec & factorygirl:
Trying to create some tests for my site. I'm using the confirmable model for devise so when I create a user using FactoryGirl, the user isn't confirmed.
This is my factories.rb:
FactoryGirl.define do
factory :user do
full_name "Aren Admin"
email "aren#example.com"
password "arenaren"
password_confirmation "arenaren"
role_id ADMIN
end
end
And this is my rspec test file:
require 'spec_helper'
describe "Admin pages" do
subject { page }
describe "home page" do
let(:user) { FactoryGirl.create(:user) }
before { visit admin_home_path }
it { should have_content("#{ROLE_TYPES[user.role_id]}") }
end
end
I'm getting an error because the user is not confirmed. By searching around I'm pretty sure I need to use the method 'confirm!' and that it belongs in the factories.rb file, but I'm not sure where to put it.
You could also set the confirmed_at attribute as follows. Works for me:
FactoryGirl.define do
factory :user do
full_name "Aren Admin"
email "aren#example.com"
password "arenaren"
password_confirmation "arenaren"
role_id ADMIN
confirmed_at Time.now
end
end
Better yet, do the following (then you don't need to create a before filter for every test suite)
Factory.define :confirmed_user, :parent => :user do |f|
f.after_create { |user| user.confirm! }
end
found here:
https://stackoverflow.com/a/4770075/1153149
Edit to add non-deprecated syntax
FactoryGirl.define do |f|
#Other factory definitions
factory :confirmed_user, :parent => :user do
after_create { |user| user.confirm! }
end
end
Edit 01/27 To Update Syntax Again
FactoryGirl.define do
#Other factory definitions
factory :confirmed_user, :parent => :user do
after(:create) { |user| user.confirm! }
end
end
Try user.confirm! in your before block
found here
This is the factory that worked for me
FactoryGirl.define do
factory :user do
sequence :email do |n|
"address#{n}#example.com"
end
sequence :password do |n|
"password#{n}"
end
factory :confirmed_user do
before(:create) {|user| user.skip_confirmation! }
end
end
end
Put the Devise confirmable logic in the after(:build) callback...
FactoryGirl.define do
factory :user do
after(:build) do |u|
u.confirm!
u.skip_confirmation_notification!
end
...
end
For me, putting confirm! or skip_confirmation! in the after(:create) block caused validation errors on the email parameter and did not work.
Add this line to your User factory definition:
before(:create) { |user| user.skip_confirmation! }
You should call skip_confirmation! before create so this is persisted on the user.
before(:create) do |user|
user.skip_confirmation!
end
2023
Does not work:
before(:create, &:skip_confirmation!)
Works:
after(:build, &:skip_confirmation!)
Related
I m new to factory bot, I try to create a sample data using factory bot but I got this error
How to resolve this error?
features/support/factories.rb:
require 'factory_bot'
FactoryBot.define do
factory :user do
email "xxx123#xyz.co"
password "asdf123"
password_confirmation "asdf123"
end
end
FactoryBot.define do
factory :post do
user = FactoryBot.create(:user)
end
end
require 'factory_bot'
FactoryBot.define do
factory :user do
email "xxx123#xyz.co"
password "asdf123"
password_confirmation "asdf123"
end
end
FactoryBot.define do
factory :post do
user
end
end
as described in FactoryBot documentation
Associations
It's possible to set up associations within factories. If the factory name is the same as the association name, the factory name can be left out.
factory :post do
# ...
author
end
You can also specify a different factory or override attributes:
factory :post do
# ...
association :author, factory: :user, last_name: "Writely"
end
I have 2 classes Users and Authentications, then Authentications has_many Users:
User class:
FactoryGirl.define do
factory :user do
first_name "Juan"
last_name "Iturralde"
sequence(:email) { |n| "person-#{n}#example.org" }
password "1234567890"
password_confirmation "1234567890"
is_admin false
factory :admin do
is_admin true
end
after(:create) do |user|
create(:authentication, user: user)
end
end
end
Authentication class:
FactoryGirl.define do
factory :authentication do
user {User.first || create(:user)}
provider "Apple"
uid "uid"
end
end
And i dont now. How create an user in authentication?
To build associations in specs I use the following:
# spec/factories/posts.rb
FactoryGirl.define do
factory :post do
title 'The best post'
trait :with_comments do
create_list :comment, 3
end
end
end
# spec/factories/comments.rb
FactoryGirl.define do
factory :comment do
post
content 'Really awesome post'
end
end
# in specs
. . .
let(:post_with_commments) { create :post, :with_comments }
. . .
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.has_role? :student
can :create, Atendimento
end
if user.has_role? :professor
can :create, Atendimento
end
if user.has_role? :administrative
can [:read, :create], [Atendimento]
can [:edit, :update], Atendimento
can :manage, [Type, Place]
end
if user.has_role? :admin
can :manage, :all
end
end
end
and my factory
FactoryGirl.define do
factory :user do |f|
f.name "Alessandro"
f.username "alessandrocb"
f.matricula "123456789"
f.password "123456789"
f.password_confirmation "123456789"
f.after(:create) {|user| user.add_role(:student)}
end
I need those mocks receive all roles , but now I can only student role
my test with rspec
subject(:ability){ Ability.new(user) }
let(:user){ nil }
context "when is an User" do
let(:user) { FactoryGirl.create(:user) }
what is happening is this: I can only test with rspec with only 1 paper, but would like to test with all the cancan, I need to create the factory with all these possibilities for different roles
First solution
FactoryGirl.define do
factory :user do
name "Alessandro"
username "alessandrocb"
(...)
trait :student do
after(:create) {|user| user.add_role(:student)}
end
trait :professor do
after(:create) {|user| user.add_role(:professor)}
end
trait :administrative do
after(:create) {|user| user.add_role(:administrative)}
end
trait :admin do
after(:create) {|user| user.add_role(:admin)}
end
end
end
You can then use and combine these traits like this:
# Create a student
create :user, :student
# Create a user who is both professor and admin
create :user, :professor, :admin
Second solution
FactoryGirl.define do
factory :user do
name "Alessandro"
username "alessandrocb"
(...)
ignore do
role
end
after(:create) do |user, params|
user.add_role(params.role) if params.role
end
end
end
And then:
# Create a student
create :user, role: :student
Note that the second solution does not allow you to combine roles as it is. But you could use an array to achieve this.
I recently ran into a similar issue. Here's my users factory:
FactoryGirl.define do
sequence :email do |n|
"user#{n}#example.com"
end
factory :user do
email
password 'password'
factory :admin_user do
role 'administrator'
end
factory :support_user do
role 'support'
end
factory :editor_user do
role 'editor'
end
factory :sales_user do
role 'sales'
end
factory :author_user do
role 'author'
end
factory :guest_user do
role 'guest'
end
end
end
From there I can just call the relevant factory for a spec:
create(:editor_user)
Or, depending on your User model and it's attendant properties, you could also build factories like:
create(:user, role: 'guest') # my User model has a properly called 'role'
I have 3 different users in my project: default, merchant, admin.
I have one file that handles the conditions. Note: this is FactoryBot and specifically factory bot rails. I am also using the gem Faker.
edit: the numbered roles are using enum, which converts the number in a string according to an array I defined. More on enums: https://naturaily.com/blog/ruby-on-rails-enum
factories/user.rb
// factories/user.rb
FactoryBot.define do
factory :user do
name { Faker::Name.first_name }
street_address { Faker::Address.street_address }
city { Faker::Address.city }
state { Faker::Address.state }
zip { Faker::Address.zip }
email { Faker::Internet.email }
password { Faker::Internet.password }
trait :default_user do
role { 0 }
end
trait :admin_user do
role { 1 }
end
trait :merchant_user do
role { 2 }
end
end
end
spec file
// a spec file
RSpec.describe 'User logging in' do
let(:user) { create(:user, :default_user) }
let(:admin) { create(:user, :admin_user) }
[...]
end
I am following Michael Hartl's online tutorial and in Listing 9.42, I am having trouble comprehending the code.
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
factory :admin do
admin true
end
end
end
Then admin is created in listing 9.43
describe "as an admin user" do
let(:admin) { FactoryGirl.create(:admin) }
What I don't understand is how that is possible to create an admin without any
code of
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
inside the admin block?
It seems :admin block is nested inside :user block and so the :user block code is executed during FactoryGirl.create(:admin) creating an admin with users name, email, password inside the :user block?
Is that right?
Thank you!
Assuming you already know how FactoryGirl library works, the explanation to your question is that the :admin factory is defined inside the :user factory
FactoryGirl.define do
factory :user do
...
factory :admin do
admin true
end
end
end
In this case, :admin will inherit all the properties of the user, plus the specific admin: true setting.
FactoryGirl.create(:admin)
Yes, that is correct. When you create a nested FactoryGirl object, that object inherits all attributes of its parent.
I am facing the same problem as the question here. The post is quite outdated. I was wondering how to do the same thing. My factory is:
FactoryGirl.define do
factory :user do
sequence(:email) {|n| "email#{n}#factory.com" }
password "foobar"
password_confirmation { |u| u.password }
profile
end
end
But FactoryGirl.create(:user) fails because of a validation error in the profile model with the user being blank.
What I would do is to use the after_create. This ensures it only creates profile after it creates user.
factory :user do
sequence(:email) {|n| "email#{n}#factory.com" }
password "foobar"
password_confirmation { |u| u.password }
after_create do |user|
FactoryGirl.create(:profile, :user => user)
end
end
You can call Factory(:user) afterward.