Rails testing with rspec - ruby-on-rails

I have a problem with my testing in rails with rspec. All in all I have a structure between 4 models, but for the moment I try to solve my testing for two of them. I'm using faker and FactoryGirl and have the following factories:
require 'faker'
FactoryGirl.define do
factory :user do |f|
f.name { Faker::Name}
f.email { Faker::Internet.email}
f.password {Faker::Internet.password}
f.role {"Kindergarten"}
end
end
require 'faker'
FactoryGirl.define do
factory :child do |f|
f.name { Faker::Name}
f.city { Faker::Address.city}
f.postalcode {Faker::Number.between(30000,35000)}
f.streed {Faker::Address.street_name}
f.add_number {Faker::Address.secondary_address}
f.disability { Faker::Boolean.boolean}
f.halal { Faker::Boolean.boolean}
f.koscha {Faker::Boolean.boolean}
f.vegetarian {Faker::Boolean.boolean}
f.vegan {Faker::Boolean.boolean}
f.allday { Faker::Boolean.boolean}
f.gender { Faker::Number.between(0,1)}
f.user_id {Faker::Number.between(1,10)}
end
end
and my controller test looks like that
require 'rails_helper'
require 'factory_girl_rails'
describe UsersController do
before do
3.times { FactoryGirl.create(:child)}
end
describe "GET #show" do
let(:user) { FactoryGirl.create(:user) }
before { get :show, id: user.id}
it "assigns the requested user to #user" do
assigns(:user).should eq user
end
it "renders the :show template"
end
describe "GET #new" do
let(:user) { FactoryGirl.create(:user) }
it "assigns a new User to #user" do
get :new, id: user.id
assigns(:user).should be_a_new(User)
end
it "renders the :new template"
end
end
When I try to run the test, I got this error message
UsersController GET #new assigns a new User to #user
Failure/Error: 3.times { FactoryGirl.create(:child)}
ActiveRecord::RecordInvalid:
Validation failed: User can't be blank
My relations and validations in the models are as follow
class Child < ApplicationRecord
has_many :relations, :dependent => :destroy
accepts_nested_attributes_for :relations
belongs_to :user
validates :user, presence: true
validates :name, presence: true, length: { maximum: 50 }
validates :city, presence: true, :on => :create
validates :postalcode, presence: true, numericality: true
validates :streed, presence: true
validates :add_number, presence: true
validates :disability, inclusion: { in: [true, false] }
validates :halal, inclusion: { in: [true, false] }
validates :koscha, inclusion: { in: [true, false] }
validates :vegetarian, inclusion: { in: [true, false] }
validates :vegan, inclusion: { in: [true, false] }
validates :allday, inclusion: { in: [true, false] }
validates :gender, presence: true
end
class User < ApplicationRecord
attr_accessor :remember_token, :activation_token, :reset_token
has_many :children, dependent: :destroy
has_many :kindergartens, dependent: :destroy
has_many :relations, dependent: :destroy
before_save :downcase_email
before_create :create_activation_digest
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :role, presence: true
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
end
My problem is, that I'm not sure if there is a fault in my rspec code or if I have made a mistake in my validations and relations in my normal models. Can someone help me?

I think that it would be better to post the whole factory for you. And I think you don't need to require faker if you have it in Gemfile.
FactoryGirl.define do
factory :child do
name { Faker::Name}
city { Faker::Address.city}
postalcode {Faker::Number.between(30000,35000)}
streed {Faker::Address.street_name}
add_number {Faker::Address.secondary_address}
disability { Faker::Boolean.boolean}
halal { Faker::Boolean.boolean}
koscha {Faker::Boolean.boolean}
vegetarian {Faker::Boolean.boolean}
vegan {Faker::Boolean.boolean}
allday { Faker::Boolean.boolean}
gender { Faker::Number.between(0,1)}
user
end
end
Inside specs when you need to create a child for the particular user:
let(:current_user) { create :user }
let(:child) { create :child, user: current_user }
Try to change your controller spec:
describe UsersController do
let(:user) { create(:user) }
describe "GET #show" do
before { get :show, params: { id: user.id } }
it "assigns the requested user to #user" do
assigns(:user).should eq user
end
it "renders the :show template"
it { expect(response).to have_http_status 200 }
end
describe "GET #new" do
before { get :new }
it "assigns a new User to #user" do
assigns(:user).should be_a_new(User)
end
it "renders the :new template"
end
end

Related

Minitest fails on user update test

My user#update method appears to be working as anticipated. When performing this method as requested from my front-end, a successful update occurs. The test for the method, however, fails.
For my test, I'm logging the user in, then attaching the returned auth_token in the request headers.
Here is the test:
test "should successfully update valid email" do
old = #user.auth_token
post api_login_url, params: { session: #credentials }
#user.reload
assert_not_equal old, #user.auth_token
old_user = #user
#request.headers["Authorization"] = #user.auth_token
patch "/api/users/" + #user.id.to_s, params: { email: "new#me.com", password: "testtest" }, headers: #request.headers
assert_response 201
assert_equal "new#me.com", User.find(#user.id).email
end
The error:
Expected: "new#me.com"
Actual: "test#woohoo.com"
In my controller (#user is already set):
before_action :authenticate_with_token!, only: [:update, :destroy]
before_action :set_user, only: [:show, :update, :destroy, :confirm, :posts, :comments]
wrap_parameters :user, include: [:username, :email, :password, :password_confirmation]
def update
if #user.update(user_params)
render json: #user
else
render json: #user.errors, status: :unprocessable_entity
end
end
def user_params
params.require(:user).permit(:username, :email, :password, :password_confirmation, :confirmation_code, :confirmed)
end
The user model:
require 'json_web_token'
class User < ApplicationRecord
before_save { email.downcase! }
before_create :generate_authentication_token!
before_update :reset_confirmed!, :if => :email_changed?
has_secure_password
has_many :posts
has_many :comments
has_many :votes
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :username, presence: true, length: { maximum: 24 }, uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 8 }
validates :auth_token, uniqueness: true
def generate_authentication_token!
begin
self.auth_token = JsonWebToken.encode('id' => self.id, 'username' => self.username)
end while self.class.exists?(auth_token: auth_token)
end
def destroy_token!
self.auth_token = nil
end
def reset_confirmed!
self.confirmed = false
end
end
In case anyone will ask, I've tried removing the before_update :reset_confirmed! call.
I've tried rewriting the tests many different ways. The assert_response 201 does not fail.
Rails version: 5.0.0.beta2
Ruby version: 2.2.3 (x86_64-darwin15)
You need to wrap your params:
patch "/api/users/" + #user.id.to_s,
params: { user: { email: "new#me.com", password: "testtest" }},
headers: #request.headers
I am however quite surprised you are not getting an exception (require(:user) should raise one when params[:user] is missing), so let me know if it is working.

User validations email uniqueness Rspec FactoryGirl

i have been even trying pending on this but it still gives error.
Userfactory
FactoryGirl.define do
sequence :email do |n|
"email#{n}#evercam.io"
end
factory :user, class: :EvercamUser do
sequence(:firstname) { |n| "firstname#{n}" }
sequence(:lastname) { |n| "lastname#{n}" }
sequence(:username) { |n| "username#{n}" }
sequence(:password) { |n| "password#{n}" }
email
sequence(:api_id) {|n| SecureRandom.hex(10)}
sequence(:api_key) {|n| SecureRandom.hex(16)}
# is_admin false
country do
country = Country.where(iso3166_a2: 'ie').first
country || create(:ireland)
end
end
end
UserSpec
require 'rails_helper'
RSpec.describe User, type: :model do
describe 'validations' do
it { should validate_presence_of :email }
it { should validate_presence_of :firstname }
it { should validate_presence_of :lastname }
it { should validate_presence_of :username }
it { should validate_presence_of :encrypted_password }
describe 'email uniqueness' do
before { create :user, email: 'foo#bar.com' }
let(:user) { build :user, email: 'foo#bar.com' }
it do
user.valid?
expect(user.errors[:email]).to be == ['has already been taken']
end
end
end
describe 'associations' do
it { should belong_to(:country) }
# it { should have_many(:camera_shares) }
end
it 'has a valid factory' do
expect(build(:user)).to be_valid
end
end
and here is my UserModel which is Devise
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :country
validates :firstname, presence: true
validates :lastname, presence: true
validates :username, presence: true
validates :encrypted_password, presence: true
def fullname
"#{firstname} #{lastname}"
end
def self.created_months_ago(number)
given_date = number.months.ago
User.where(created_at: given_date.beginning_of_month..given_date.end_of_month)
end
end
I have even tried to give "pending" to all blocks but it still giving me error i dont know where i am wrong on this
Any help will be appreciated thanks
it { should validate_presence_of :email }
If it fails on the line above, it is because the model does not in fact have a validation for :email:
validates :firstname, presence: true
validates :lastname, presence: true
validates :username, presence: true
validates :encrypted_password, presence: true
# validates :email, presence: true # <---- missing in action

Failing user validation with nested attributes and polymorphic association

This simple validation test is failing:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "Example User",
email: "user#example.com",
character_attributes: {callsign: "example"},
password: "foobar",
password_confirmation: "foobar"
)
end
test "should be valid" do
assert #user.valid?, "#{#user.errors.messages}"
end
end
...with this message: character.sociable_id"=>["can't be blank"]
I don't understand why the user creation in UserTest is failing to make a valid User.
Each User has_one :character and each Character belongs_to a User.
The User model:
User.rb:
class User < ActiveRecord::Base
attr_accessor :remember_token, :activation_token, :reset_token
has_one :character, as: :sociable, dependent: :destroy
accepts_nested_attributes_for :character
has_secure_password
before_validation do
self.create_character unless character
end
before_save do
self.email.downcase!
end
before_create :create_activation_digest
validates :name, presence: true,
length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }, allow_blank: true
validates :character, presence: true
.
.
end
The Character model:
Character.rb:
class Character < ActiveRecord::Base
belongs_to :sociable, polymorphic: true
has_many :posts, dependent: :destroy
before_save do
self.callsign.downcase!
end
validates :sociable_id, presence: true
VALID_CALLSIGN_REGEX = /\A[a-z\d\-.\_]+\z/i
validates :callsign, presence: true,
length: { maximum: 20 },
format: { with: VALID_CALLSIGN_REGEX },
uniqueness: { case_sensitive: false }
end
It should be:-
test "should be valid" do
assert #user.valid? , "#{#user.errors.messages}"
end

Active Record Rspec Query Interface Errors

I'm working through an API for Rails and have been fumbling how to set up the associations, the spec, and the controller for my Get route. The goal - As a user I want to get all the notes closest to my location that have not been viewed. I know the viewed? logic is off, as is the Query Interface in the Recipients Model and Nearests Controller.
Here's the Error Rspec is giving me:
Failure/Error: note1 = create(:note)
NoMethodError:
undefined method `recipient_id=' for #<Note:0x007fd2a40e1400>
Here's the spec:
describe 'GET /v1/notes/nearests?lat=&lon=&radius=' do
it 'returns the notes within the given radius' do
near_note1 = create(:note, lat: 37.760322, lon: -122.429667)
near_note2 = create(:note, lat: 37.760322, lon: -122.429667)
lat = 37.771098
lon = -122.430782
radius = 10
get "/v1/notes/nearests?lat=#{lat}&lon=#{lon}&radius=#{radius}"
expect(response_json).to eq([
{
'id' => [near_note1.id, near.note2.id],
# 'lat' => near_note1.lat,
# 'lon' => near_note1.lon,
'note_text' => [near_note1.note_text, near_note2.note_text],
'photo_uri' => [near_note1.photo_uri, near_note2.photo.uri],
# 'expiration' => near_note.expiration.as_json,
'viewed' => [near_note1.viewed?, near_note2.viewed?]
},
])
end
end
Here is the controller code:
def index
#notes = Note.near([
params[:recipient_id],
params[:lat],
params[:lon]],
radius: :APP_CONFIG['radius'],
units: :APP_CONFIG['units']
)
end
Here are the Factories - Notes
FactoryGirl.define do
factory :note do |u|
sender_id {FactoryGirl.create(:user).id}
recipient_id {FactoryGirl.create(:user).id}
lat 1.5
lon 1.5
note_text "MyString"
photo_uri "MyString"
expiration Time.zone.now.utc
end
end
My Models:
User Model
class User < ActiveRecord::Base
has_many :notes
validates :first_name, :last_name, :pw, presence: true
validates :email, :username, :devicetoken, presence: true, uniqueness: true
validates :email, length: { minimum: 8 }
end
Note Model
class Note < ActiveRecord::Base
belongs_to :user, foreign_key: 'sender_id', class_name: 'User'
has_many :recipients, foreign_key: 'recipient_id', class_name: 'User'
validates :sender_id, presence: true
validates :lat, presence: true
validates :lon, presence: true
validates :note_text, presence:true
validates :expiration, presence: true
reverse_geocoded_by :lat, :lon
end
Recipients Model
class Recipient < ActiveRecord::Base
belongs_to :note, foreign_key: 'recipient_id', class_name: 'Note'
def get_recipient
Note.find(:all, params[:note_id])
end
def viewed?
end
end

Rails 3.1, Factory girl bug

Fixed. There was a bug in Rails. See https://github.com/rails/rails/issues/2333
I have a problem with Factory Girl Rails and Rails 3.1.0.rc5
When I do more than once user = FactoryGirl.create(:user) I have an error.
Failure/Error: user = FactoryGirl.create(:user)
NameError:
uninitialized constant User::User
# ./app/models/user.rb:17:in `generate_token'
# ./app/models/user.rb:4:in `block in <class:User>'
# ./spec/requests/users_spec.rb:20:in `block (3 levels) in <top (required)>'
I can create as many user as I want using Factory but only in rails console.
Tests:
require 'spec_helper'
describe "Users" do
describe "signin" do
it "should sign in a user" do
visit root_path
user = FactoryGirl.create(:user)
within("div#sign_in_form") do
fill_in "Name", with: user.name
fill_in "Password", with: user.password
end
click_button "Sign in"
current_path.should eq(user_path(user))
page.should have_content("signed in")
end
it "should not show new user form on /" do
user = FactoryGirl.create(:user)
visit root_path
page.should_not have_css("div#new_user_form")
end
end
end
factories.rb
FactoryGirl.define do
factory :user do |f|
f.sequence(:name) { |n| "john#{n}" }
f.fullname 'Doe'
f.sequence(:email) { |n| "test#{n}#example.com" }
f.password 'foobar'
end
end
model/user.rb
class User < ActiveRecord::Base
has_secure_password
attr_accessible :name, :fullname, :email, :password
before_create { generate_token(:auth_token) }
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, presence: true, length: { maximum: 20 },
uniqueness: { case_sensitive: false }
validates :fullname, presence: true, length: { maximum: 30 }
validates :email, format: { with: email_regex },
uniqueness: { case_sensitive: false }, length: { maximum: 30 }
validates :password, length: { in: 5..25 }
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
end
User.exists?(column => self[column]) causes the problem.
Somehow the class is not properly looked up, and I am not sure how this is happenning but could you try accessing it differently:
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while self.class.exists?(column => self[column])
end
You've got an extra line i your factories.rb, it should read like this:
FactoryGirl.define :user do |f|
f.sequence(:name) { |n| "john#{n}" }
f.fullname 'Doe'
f.sequence(:email) { |n| "test#{n}#example.com" }
f.password 'foobar'
end
This should work:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "john#{n}" }
fullname 'Doe'
sequence(:email) { |n| "test#{n}#example.com" }
password 'foobar'
end
end

Resources