I'm doing exactly what is says in the documentation, but still getting a validation error:
Validation failed: Email has already been taken
FactoryGirl.define do
sequence :email do |n|
"test#{n}#factory.com"
end
factory :user do
email
password '12345678'
password_confirmation '12345678'
goal_id 1
experience_level_id 1
gender 'Female'
end
end
Anyone know what I'm doing wrong here?
EDIT:
Here is the failing spec. It works fine if you uncomment subject block and comment out the FactoryGirl stuff. I'm trying to switch to using FactoryGirl.
require 'spec_helper'
require 'cancan/matchers'
describe User do
# subject(:user) do
# Program.create!(name: 'test', gender: 'Female', goal_id: '1', experience_id: '1')
# User.create!(email: 'test#test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female')
# end
FactoryGirl.create(:program)
puts FactoryGirl.create(:user).inspect
it "should be assigned a program when it's created" do
user.programs.should exist
end
it "should be valid with a name, goal, password, password_confirmation, experience_level, and gender" do
user.should be_valid
end
it { should respond_to(:programs) }
its('programs.last.name') {should == 'Test'}
it "should be assigned imperial as the default measurement_units" do
user.measurement_units.should eq("imperial")
end
it 'validates presence of gender, goal_id, and experience_level_id' do
user = User.new(gender: nil)
user.should validate_presence_of(:gender)
user.should validate_presence_of(:goal_id)
user.should validate_presence_of(:experience_level_id)
end
end
Edit 2:
I've updated my spec following the suggestion of one of the answers, so now my spec runs, but I get a failing test with a validation error. Here is the updated code:
describe User do
subject(:user) do
# Program.create!(name: 'test', gender: 'Female', goal_id: '1', experience_id: '1')
# User.create!(email: 'test#test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female')
FactoryGirl.create(:program)
FactoryGirl.create(:user)
end
it "should be assigned a program when it's created" do
user.programs.should exist
end
And the message from the failing test:
Failures:
1) User should be assigned a program when it's created
Failure/Error: FactoryGirl.create(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/models/user_spec.rb:9:in `block (2 levels) in <top (required)>'
# ./spec/models/user_spec.rb:13:in `block (2 levels) in <top (required)>'
Any ideas?
You can't just create Factory instances in the middle of a test class like that. FactoryGirl is a replacement for the instantiation you had in the code before - leave the subject block, and simply replace the two create lines with the FactoryGirl calls.
(even better, they should be let blocks not a subject block, but that's a different story)
If you are not doing things in a context Rspec knows about, it has no way of cleaning up afterwards.
What do you have in your Gemfile? I have better success using this
gem 'factory_girl_rails', :group => :test
and not listing it in the "group :development, :test do" section.
Related
I'm trying to test user model, for which I've devise authentication.
The problem I'm facing is,
1. Having 'password'/'password_confirmation' fields in fixtures is giving me invalid column 'password'/'password_confirmation' error.
If I remove these columns from fixture and add in user_test.rb
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "example user",
email: "example#example.com",
password: "Test123",
work_number: '1234567890',
cell_number: '1234567890')
end
test "should be valid" do
assert #user.valid?
end
test "name should be present" do
#user.name = "Example Name "
assert #user.valid?
end
end
The error I'm getting is:
test_0001_should be valid FAIL (0.74s)
Minitest::Assertion: Failed assertion, no message given.
test/models/user_test.rb:49:in `block in <class:UserTest>'
test_0002_name should be present FAIL (0.01s)
Minitest::Assertion: Failed assertion, no message given.
test/models/user_test.rb:54:in `block in <class:UserTest>'
Fabulous run in 0.75901s
2 tests, 2 assertions, 2 failures, 0 errors, 0 skips
I'm wondering why my user object is not valid?
Thanks
I got a work around after some investigation like below:
Add a helper method for fixture:
# test/helpers/fixture_file_helpers.rb
module FixtureFileHelpers
def encrypted_password(password = 'password123')
User.new.send(:password_digest, password)
end
end
# test/test_helper.rb
require './helpers/fixture_file_helpers.rb'
ActiveRecord::FixtureSet.context_class.send :include, FixtureFileHelpers
And make fixture like this:
default:
email: 'default#example.com'
name: "User name"
encrypted_password: <%= encrypted_password %>
work_number: '(911) 235-9871'
cell_number: '(911) 235-9871'
And use this fixture as user object in user test.
def setup
#user = users(:default)
end
I wanted to remove the FactoryGirl.build(:user) everytime I want to create a user and so I added these lines:
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
to the spec_helper.rb. But this creates the following error:
`method_missing': `build` is not available on an example group (e.g. a `describe` or `context` block). It is only available from within individual examples (e.g. `it` blocks) or from constructs that run in the scope of an example (e.g. `before`, `let`, etc). (RSpec::Core::ExampleGroup::WrongScopeError)
Then I removed all the context/describe blocks, but that didn't change anything. Have any of you had the same problem with this and how may I fix it?
Currently my tests look like so:
require 'rails_helper'
RSpec.describe User, type: :model do
user = build(:user)
project = build(:project)
it "is valid with a firstname, lastname, email and password" do
expect(user).to be_valid
end
it "is invalid without a firstname" do
user = build(:user, name: nil)
expect(user.valid?).to be_falsey
expect(user.errors[:name].size).to eq(1)
end
it "is invalid without a lastname" do
user = build(:user, surname: nil)
expect(user.valid?).to be_falsey
expect(user.errors[:surname].size).to eq(1)
end
it "destroys dependent projects" do
user = User.create!(name: 'john', surname: 'doe', email: 't#example.com', password: 'password', password_confirmation: 'password')
user.projects << project
expect{user.destroy}.to change {Project.count}.by(-1)
end
end
Instead of:
user = build(:user)
project = build(:project)
Do:
let(:user) { build(:user) }
let(:project) { build(:project) }
In general it is not a good idea to define external variables to use them in a test, as this might make your tests order-dependent and extremely hard to debug. Always use the let syntax, so the values are reinitialized for every test.
In my RSpec user_spec.rb one of my FactoryGirl factories seems valid and I can call should be_valid on it, and this test will pass (and will break if I put an empty string in the factory user_name).
describe User do
it "has a valid factory" do
# should be_valid works fine
FactoryGirl.create(:user).should be_valid
end
it "is invalid without a name" do
# should_not_be_valid throws a NoMethodError
FactoryGirl.build(:user, :user_name => nil).should_not_be_valid
end
end
However when I call the above should_not_be_valid on FactoryGirl.build, the test fails:
1) User is invalid without a name
Failure/Error: FactoryGirl.build(:user, :user_name => nil).should_not_be_valid
NoMethodError:
undefined method `should_not_be_valid' for #<User id: nil, user_name: nil, created_at: nil, updated_at: nil>
# ./spec/models/use
When it should instead pass, since a blank user_name is invalid. Here is what I have in my factories.rb:
FactoryGirl.define do
factory :user do
user_name "Foo Bar"
end
end
And my User model:
class User < ActiveRecord::Base
has_one :musician
validates :user_name, presence: true
end
How could should be_valid be working, but should_not_be_valid throws a NoMethodError?
I would really appreciate any help! I am running Rails 4, gem "rspec-rails", "~> 2.14.1", and gem 'factory_girl_rails', '4.3.0'
Been trying to puzzle this one out for awhile with no success...
Use space between should_not and be_valid:
FactoryGirl.build(:user, :user_name => nil).should_not be_valid
I'm trying to write a request spec for my user_login API, but can't figure out how to get a valid user that doesn't return a wrong username or password 401 invalid error.
Here is my spec:
require 'spec_helper'
describe User do
subject(:user) do
Program.create!(name: 'test', gender: 'Female', goal_id: '1', experience_id: '1')
User.create!(email: 'test#test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female')
end
it "is logged in" do
post "/api/v1/login", user_login: {email: 'test#test.com', password: '12345678' }
response.status.should be(201)
end
My understanding was that creating a User in the subject line would mean that my test would run against that user. Any idea what I'm doing wrong here?
And Here is the answer
require 'spec_helper'
describe "sessions" do
before do
FactoryGirl.create(:program)
#user = FactoryGirl.create(:user)
end
describe "user" do
it "is logged in" do
post "/api/v1/login", user_login: {email: #user.email, password: #user.password }
response.status.should be(201)
end
end
end
I'm not totally sure what's different than what I was doing in the question. I replaced the subject block with a before block and moved the creation of the program and user into Factories.
I just added the Rolify gem, and am running some rspec tests.
2 tests are as follows:
describe "roles" do
before(:each) do
#user = FactoryGirl.create(:user)
end
it "should not approve incorrect roles" do
#user.add_role :moderator
#user.has_role? :admin
should be_false
end
it "should approve correct roles" do
#user.add_role :moderator
#user.has_role? :moderator
should be_true
end
end
The test result is:
1) User roles should not approve incorrect roles
Failure/Error: should be_false
expected: false value
got: #<User id: nil, email: "", encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, name: nil, position: nil, location: nil, admin: false, archived: false, public_email: false, created_at: nil, updated_at: nil>
# ./spec/models/user_spec.rb:70:in `block (3 levels) in <top (required)>'
Finished in 1.37 seconds
7 examples, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:67 # User roles should not approve incorrect roles
Randomized with seed 13074
factories.rb
FactoryGirl.define do
factory :user do
sequence(:name) {|n| "Example User #{n}"}
sequence(:email) {|n| "email#{n}#program.com" }
position "Regular"
location "Anywhere, USA"
public_email false
password "foobar"
password_confirmation "foobar"
confirmed_at Time.now
end
end
How is the first test is failing with a nil object, but the second is passing?
EDIT
Upon further inspection, any test for should be_true passes, and any test for should be_false fails, regardless of whether the added role matches the checked role.
When your tests do should be_true what is happening is the should call is being delegated to the subject object (see RSpec docs for implicit receiver). In this case, your subject object is a User instance that has not yet been saved to the database. If your user_spec.rb file starts with describe User do, RSpec is automatically providing this default subject of User.new (see RSpec docs for implicit subject).
What this means is that your tests are essentially doing User.new.should be_true and User.new.should be_false. Since a User object will always evaluate to true, the should be_true test will always pass (although probably not for the reason you wanted it to) and the should be_false will always fail.
Based on the way your tests are written, maybe you meant something more like this:
describe "roles" do
before(:each) do
#user = FactoryGirl.create(:user)
end
it "should not approve incorrect roles" do
#user.add_role :moderator
#user.has_role?(:admin).should be_false
end
it "should approve correct roles" do
#user.add_role :moderator
#user.has_role?(:moderator).should be_true
end
end
I'm assuming that the example group is actually nested in a group declared with describe User do, yes?
The problem is that the last line of each example reads should xxx, but should has no receiver, so RSpec is substituting an instance of User for you.
What you want is:
describe User do
describe "roles" do
before(:each) do
#user = FactoryGirl.create(:user)
end
it "should not approve incorrect roles" do
#user.add_role :moderator
#user.has_role?(:admin).should be_false
end
it "should approve correct roles" do
#user.add_role :moderator
#user.has_role?(:moderator).should be_true
end
end
end
HTH,
David