Rails 3 + Rspec 2: Validation failed: Email has already been taken - ruby-on-rails-3

I have 2 models, User and Bucket. User has_many Buckets and a Bucket belongs_to a User.
In factories.rb, I have:
Factory.define :user do |user|
user.email "teste#test.com"
user.password "foobar"
user.password_confirmation "foobar"
end
Factory.sequence :email do |n|
"person-#{n}#example.com"
end
Factory.define :bucket do |bucket|
bucket.email "user#example.com"
bucket.confirmation false
bucket.association :user
end
and I have a login_user module as follows:
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#user = Factory.create(:user)
##user.confirm!
sign_in #user
end
end
I am using Spork and Watch and my Buckets_controller_spec.rb is as simple as:
describe "User authenticated: " do
login_user
#bucket = Factory(:bucket)
it "should get index" do
get 'index'
response.should be_success
end
...
end
The error is always the same:
Failures:
1) BucketsController User authenticated: should get index
Failure/Error: Unable to find matching line from backtrace
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./lib/controller_macros.rb:12:in `block in login_user'
And it only happens when I have the Factory(:bucket). The login works fine when I don't add the Factory(:bucket).
It's always the same error. I have tried adding :email => Factory.next(:email) to the user, but no success.
Edit:
In rails c test:
ruby-1.9.2-p180 :019 > bucket = Factory(:bucket, :email => "hello#hello.com")
ActiveRecord::RecordInvalid: Validation failed: Email has already been taken
ruby-1.9.2-p180 :018 > Bucket.create(:email => "hello#hello.com")
=> #<Bucket id: 2, email: "hello#hello.com", confirmation: nil, created_at: "2011-04-08 21:59:12", updated_at: "2011-04-08 21:59:12", user_id: nil>
Edit 2:
I found out that the error is in the association, however, I don't know how to fix it.
bucket.association :user

When you define a factory with an association you need to give the factory an object to associate with whenever you use the factory.
This should work:
describe "User authenticated: " do
login_user
#bucket = Factory(:bucket, :user => #user)
it "should get index" do
get 'index'
response.should be_success
end
end
That way factorygirl knows to make a bucket which is associated with #user.

Try this in your user factory:
Factory.define :user do |f|
f.sequence(:email) { |n| "test#{n}#example.com" }
...
end
I think that's probably your problem. When you use f.email = "anyvalue" it's going to use that value every time. I see you were trying to create a sequence in the next block, but I'm not sure that sequence is getting used.
ALSO - be aware that if you get tests interrupted by a crash or something, sometimes bogus test data can get left in your test DB instead of being rolled back.
Very first thing I try if something worked once and then quit working is to reset the test db.
rake db:test:prepare
That will clean everything out.
If this doesn't work let me know and I'll take a second look!

If someone is getting this recently with your views. Try using Database Cleaner.
For more info: RailsTutorial - chapter 8.4.3 - Test database not clearing after adding user in integration test

Related

rspec vs 'url_validation' gem

I'm struggling with rspec as a new Rails person and I have a need to validate a url passed into Active Record. This is probably due to my ignorance so pls point me in the right direction. The video_url is a string field which I'd like to validate as being a valid URL. Looking around, I chose this gem because it appeared to be fully tested in rspec. For my test I didn't see how I could incorporate his validation test into my model test.
In rails console, I created a Post object and ensured that if I put a bogus URL that I knew would not be found, I would get an error. The curious thing is that attempting to replicate this in a test with the gem installed fails the test because it finds no errors. I expected an error of some kind as I got in console. My question is what am I doing wrong in that it gets no errors? I've made several attempts to triangulate what might be causing it but the gem doesn't seem to work in rspec? I would have thought that if I could get it to work in console, I can get it to work in rspec?
post.rb
class Post < ActiveRecord::Base
attr_accessible :body, :title, :image, :video_title, :video_url
validates_presence_of :title, :body, :author
validates :video_url, :presence => true, :if => :video_title_present?, :url => {
:check_path => [ 300..399, 400..499, 500..599 ], :allow_nil => true,
:url_not_accessible_message => "must be valid.",
:invalid_url_message => "must be valid.",
:url_invalid_response_message => "must be valid."}
def video_title_present?
!self.video_title.blank?
end
belongs_to :author, class_name: "User"
end
post_spec.rb
before do
#post = Post.new(title: "foo", body: "my body here")
end
describe "validates with video links" do
it "validates with video url and video title" do
#post.video_url = "http://heckitoqi.com"
#post.video_title = "my title"
#post.should have_at_least(1).error_on(:video_url)
end
end
Output in console:
Failure/Error: #post.should have_at_least(1).error_on(:video_url)
expected at least 1 error on :video_url, got 0
In some of my errors, I attempted a more open-ended error, but it fails by not catching any errors.
Here is a short version of my smoke test of the model using Rails console:
u = User.first
p = Post.new(title: "title", body: "body", video_title: "vtitle", video_url: "http://heckitoqi.com")
p.author = u
p.save!
>> HTTPI GET request to heckitoqi.com (net_http)
>> ActiveRecord::RecordInvalid: Validation failed: Video url must be valid.
If I can get it to validate in the console, then my implementation of the test is at fault, right? I just don't see what I'm doing wrong. thanx, sam

Rails FactoryGirl Duplicated Factory

I have the following factories defined in my factories.rb file:
require 'factory_girl'
FactoryGirl.define do
sequence(:email) {|n| "person-#{n}#example.com" }
factory :country do
...
end
factory :state do
country
...
end
factory :school do
name "Test School"
country
state
end
factory :user do
school
email
...
end
end
When testing in rspec calling FactoryGirl.create(:school) in one of my descriptors causes two schools with the name "Test School" to be created.
I thought the factories defined in factories.rb were just a bunch of unsaved instance objects, can somebody clarify as to why I'm having this issue?
Here's the exact rspec:
require 'spec_helper'
describe "school login" do
it "displays a success message upon successful login to school",do
school = FactoryGirl.create(:school)
user = FactoryGirl.create(:user, :username => "jdoe")
School.all.each do |school|
puts school.name #2x => "Test School"
end
visit school_path(user.school)
click_link('login')
fill_in "username", :with => "jdoe"
fill_in "password", :with => "secret"
click_button "Sign in"
expect(page).to have_selector(".alert-success")
end
end
This line creates the first school
school = FactoryGirl.create(:school)
and this one the second:
user = FactoryGirl.create(:user, :username => "jdoe")
This happens because in your user factory you defined that every user should have a school, so FactoryGirl is creating it for you. If you want your user associated with the first school, you can do something like this:
user = FactoryGirl.create(:user, :username => "jdoe", :school => school)
what's the context code? and how did you find there are 2 schools created?
the code written in ruby files ( factories ) is neither saved to database nor created as object until you declare create(:object) or build(:object).
# Returns a User instance that's not saved
user = FactoryGirl.build(:user)
# Returns a saved User instance
user = FactoryGirl.create(:user)
for more details, refer to : https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#using-factories

"Expected css... to return something" : rspec fail while test by hand works (can't reproduce the fail myself)

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 }

why controller var isn't available within a test?

I'm trying to follow Michael Hartl's Ruby on Rails Tutorial in http://ruby.railstutorial.org/chapters/sign-in-sign-out, but with some changes to practice, above all, some variations and the Test::Unit framework. In the tutorial, RSpec is used, while I'm trying to stick to Test::Unit + Shoulda-context.
In chapter 9 I'm suposed to pass some functional tests that use a var called 'controller', but my tests don't work as they find out that 'controller' doesn't exist. This is what I get:
marcel#pua:~/Desenvolupament/Rails3Examples/ror_tutorial$ rake
test:recent Loaded suite
/home/marcel/.rvm/gems/ruby-1.9.2-p290/gems/rake-0.9.2.2/lib/rake/rake_test_loader
Started F
=============================================================================== Failure: test: POST 'create' with valid signin (email and password)
should redirect to the user show page. (SessionsControllerTest)
[test/functional/sessions_controller_test.rb:58]: Expected at least 1
element matching "title", found 0. is not true.
=============================================================================== E
=============================================================================== Error: test: POST 'create' with valid signin (email and password)
should sign in the user. (SessionsControllerTest): NameError:
undefined local variable or method `controller' for
test/functional/sessions_controller_test.rb:53:in `block (3 levels) in <class:SessionsControllerTest>'
=============================================================================== Finished in 0.957865676 seconds. 7 tests, 6 assertions, 1 failures, 1
errors, 0 pendings, 0 omissions, 0 notifications 0% passed
7.31 tests/s, 6.26 assertions/s rake aborted! Command failed with status (1): [/home/marcel/.rvm/rubies/ruby-1.9.2-p290/b...] Tasks: TOP
=> test:recent (See full trace by running task with --trace)
This is the original (RSpec) test:
describe SessionsController do
...
describe "POST 'create'" do
...
describe "with valid email and password" do
before(:each) do
#user = Factory(:user)
#attr = { :email => #user.email, :password => #user.password }
end
it "should sign the user in" do
post :create, :session => #attr
controller.current_user.should == #user
controller.should be_signed_in
end
it "should redirect to the user show page" do
post :create, :session => #attr
response.should redirect_to(user_path(#user))
end
end
end
end
and this is my translated (into Test::Unit + Sholuda-context) test:
class SessionsControllerTest < ActionController::TestCase
context "POST 'create'" do
context "with valid signin (email and password)" do
setup do
#attr = {email: "test#email.tst", password: "testpwd"}
#user=User.create! #attr.merge!({name: "test_user", password_confirmation: "testpwd"})
end
should "sign in the user" do
post :create, :session => #attr
assert_equal #user, controller.current_user
end
should "redirect to the user show page" do
post :create, :session => #attr
assert_select "title", /Show/
end
end
end
end
Has anybody any idea how to make my test work?
Looking at the official Rails testing guide at http://guides.rubyonrails.org/testing.html, I've seen that an instance variable called #controller is enabled in functional tests. so, the Test::Unit version should be:
should "sign in the user" do
post :create, :session => #attr
assert_equal #user, #controller.current_user
end

Failing test in ruby tutorial (Michael Hartl)

I'm studying Michael Hartl's tutorial. I'm using RSPEC to run the test.
So far so good but it seems that I've hit the wall with the following example.
Here is the test that fails (it should pass):
describe "authenticate method" do
it "should return the user on email/password match" do
matching_user = User.authenticate(#attr[:email], #attr[:password])
matching_user.should == #user
end
end
Just in case.
#user defined as:
before(:each) do
#user = User.create!(#attr)
end
#attr defined as:
before(:each) do
#attr = {
:name => "Example user",
:email => "user#example.com",
:password => "foobar",
:password_confirmation => "foobar"
}
end
Entries in user.rb
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
private
def encrypt_password
self.salt = make_salt unless has_password?(password)
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
Error message displayed when the test is failing
c:\RailsInstaller\work\apptwit>rspec spec/models/user_spec.rb
.................F
Failures:
1) User password validations password encryption authenticate method should return the user on email/password
Failure/Error: matching_user.should == #user
expected: #<User id: 1, name: "Example user", email: "user#example.com", created_at: "2011-12-07 19:08:23
ed_at: "2011-12-07 19:08:23", encrypted_password: "fbdbaf712fa1b6c925c4ab2192e73ac9f9d1bedf67630610d68...">
got: nil (using ==)
# ./spec/models/user_spec.rb:204:in `block (5 levels) in <top (required)>'
Finished in 221.37 seconds
18 examples, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:202 # User password validations password encryption authenticate method should
he user on email/password match
I would appreciate any pointers,
Thanks a lot.
If matching_user is nil, then you might want to put some puts email and puts user.inspect statements in self.authenticate to debug it.
It seems as though it's either not able to find the user by email or your password is incorrect for some reason in the authenticate method.