Testing controller new action with Rspec2 + Rails3 - ruby-on-rails-3

I have the following rspec2 test case for my controller new action
describe "GET #new" do
it "should assign new project to #project" do
project = Project.new
get :new
assigns(:project).should eq(project)
end
end
and I'm getting the following error
1) ProjectsController GET #new should assign new project to #project
Failure/Error: assigns(:project).should eq(project)
expected: #<Project id: nil, name: nil, company_id: nil, created_at: nil, updated_at: nil>
got: #<Project id: nil, name: nil, company_id: nil, created_at: nil, updated_at: nil>
(compared using ==)
Diff:#<Project:0x007f461c498270>.==(#<Project:0x007f461c801c90>) returned false even though the diff between #<Project:0x007f461c498270> and #<Project:0x007f461c801c90> is empty. Check the implementation of #<Project:0x007f461c498270>.==.
# ./spec/controllers/projects_controller_spec.rb:19:in `block (3 levels) in <top (required)>'
Finished in 1.21 seconds
13 examples, 1 failure, 10 pending
Failed examples:
rspec ./spec/controllers/projects_controller_spec.rb:16 # ProjectsController GET #new should assign new project to #project
and when I use == instead on eq, I'm getting the following error
1) ProjectsController GET #new should assign new project to #project
Failure/Error: assigns(:project).should == project
expected: #<Project id: nil, name: nil, company_id: nil, created_at: nil, updated_at: nil>
got: #<Project id: nil, name: nil, company_id: nil, created_at: nil, updated_at: nil> (using ==)
Diff:#<Project:0x007f461c4f5420>.==(#<Project:0x007f461c63b280>) returned false even though the diff between #<Project:0x007f461c4f5420> and #<Project:0x007f461c63b280> is empty. Check the implementation of #<Project:0x007f461c4f5420>.==.
what am I doing wrong here, thanks in advance
I'm on
Rails3
Rspec2

You are creating a new project before accessing the new action, this is unnecessary. Your controller actually does that work for you already. The problem you are facing is that you have two new projects created (in your case you have created Project:0x007f461c498270 first and then Project:0x007f461c801c90, they have the same attributes but are different projects). This test should pass:
describe "GET #new" do
it "assigns a new Project to #project" do
get :new
assigns(:project).should be_a_new(Project)
end
end

Related

Invite user without email + rails + devise invitable

I want to have a feature where I can invite any user using only their phone_number. I don't have the email address. When a user is being invited, an SMS is sent to the specified number and depending upon the contents of the reply(say, 'Y' or 'N') SMS from user, their account is confirmed/rejected. We plan to provide a link in the sms where in the user can click and enter the required details(email, name etc).
Loading development environment (Rails 5.0.2)
2.3.0 :001 > u = User.invite!(phone_number: '1234567890')
=> #<User id: nil, email: nil, first_name: nil, last_name: nil, phone_number: "1234567890", created_at: nil, updated_at: nil, invitation_token: nil, invitation_created_at: nil, invitation_sent_at: nil, invitation_accepted_at: nil, invitation_limit: nil, invited_by_type: nil, invited_by_id: nil, invitations_count: 0>
2.3.0 :002 > u.errors
=> #<ActiveModel::Errors:0x007fc91fcd4c00 #base=#<User id: nil, email: nil, first_name: nil, last_name: nil, phone_number: "1234567890", created_at: nil, updated_at: nil, invitation_token: nil, invitation_created_at: nil, invitation_sent_at: nil, invitation_accepted_at: nil, invitation_limit: nil, invited_by_type: nil, invited_by_id: nil, invitations_count: 0>, #messages={:email=>["can't be blank"]}, #details={:email=>[{:error=>:blank}]}>
I have same problem and i set example email for it and remove it later...
u = User.invite!(phone_number: '1234567890', email: 'example#abc.com', skip_invitation: true)
u.update(email: '')
Add this to user.rb:
def email_required?
false
end
def email_changed?
false
end

While testing Devise with rspec, it acts like I am not logged in

I'm using Rails 3.2.13, devise 2.2.4, and rspec 2.13.2. I have a multi-tenant app in which the default scope only shows current_user's items. Everything seems to work in development, but my tests are having issues.
Problem: When I create a meal in my test, it shows user_id => nil. In my development environment everything works, though. Also, when I go into debug mode, when I check the #controller.current_user, it shows user_id 1 is logged in. Since in my development environment the user_id is being assigned automatically when I create an object, I can't figure out why it's not doing it during tests. Any ideas?
Here's my abbreviated meals_controller_spec file:
describe MealsController do
include Devise::TestHelpers
describe "When logged in as user," do
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#email = "someone#test.com"
#password = "password"
#user = User.create(email: #email, password: #password)
sign_in #user
end
describe "DELETE destroy" do
it "destroys the requested meal" do
meal = Meal.create!("name" => "", "servings" => "2", "meal_type" => "dinner")
expect { delete 'destroy', {:id => meal.id} }.to change(Meal, :count).by(-1)
end
end
end
end
Here's part of my model:
class Meal < ActiveRecord::Base
belongs_to :user
default_scope { where(user_id: User.current_id) }
Here's part of my controller:
class MealsController < ApplicationController
before_filter :authenticate_user!
def destroy
#meal = Meal.find(params[:id])
#meal.destroy
redirect_to meals_url, :notice => "Successfully deleted #{#meal.name}."
end
end
And I think my application controller could be relevant:
class ApplicationController < ActionController::Base
protect_from_forgery
around_filter :scope_current_tenant
private
def scope_current_tenant
User.current_id = current_user.id
yield
rescue Exception
yield
ensure
User.current_id = nil
end
end
Here's some output when I debug in the middle of that test:
(rdb:1) #controller.current_user.id
1
(rdb:1) Meal.create!(name: "meal", meal_type: "dinner", servings: 2)
#<Meal id: 2, name: "meal", meal_type: "dinner", servings: 2, user_id: nil, created_at: "2013-06-17 06:07:34", updated_at: "2013-06-17 06:07:34">
(rdb:1) Meal.create!(name: "meal", meal_type: "dinner", servings: 2, user_id: 1)
#<Meal id: 3, name: "meal", meal_type: "dinner", servings: 2, user_id: 1, created_at: "2013-06-17 06:12:18", updated_at: "2013-06-17 06:12:18">
(rdb:1) Meal.find(3).destroy
*** NoMethodError Exception: undefined method `destroy' for nil:NilClass
So I guess I'm wondering why the user in my test appears to be nil, even though I am using the Devise test helpers and signing in, and in my dev environment everything works.
Edit:
Here are some more debugger results:
(rdb:1) Meal.find(4)
*** ActiveRecord::RecordNotFound Exception: Couldn't find Meal with id=4 [WHERE "meals"."user_id" IS NULL]
(rdb:1) Meal.find(4).destroy
*** ActiveRecord::RecordNotFound Exception: Couldn't find Meal with id=4 [WHERE "meals"."user_id" IS NULL]
(rdb:1) Meal.where(:user_id => 1).find(3)
#<Meal id: 3, name: "meal", meal_type: "dinner", servings: 2, user_id: 1, created_at: "2013-06-17 06:12:18", updated_at: "2013-06-17 06:12:18">
It appears that the "current user" is in fact user_id => nil, per the sql snippets. So why would that be if I used the Devise test helper sign_in function?

Testing rails controller with rspec: value is same, but object id is different

I try to test a rails controller with rspec like this:
require 'spec_helper'
describe NewsController do
describe "GET 'edit'" do
before(:each) do
#news_1 = FactoryGirl.create(:news_1)
get :edit, { :id => #news_1.id }
end
it { response.should be_success }
it { assigns(:news).should eq(#news_1) }
it { response.should render_template(:edit) }
end
end
But, I got this error.
Failures:
1) NewsController GET 'edit'
Failure/Error: it { assigns(:news).should eq(#news_1) }
expected: #<News id: 1, title: "news_title_1", contents: "news_contents_1", display: nil, created_at: "2012-11-29 07:24:49", updated_at: "2012-11-29 07:24:49", news_date: nil, orion: false, pw: false, op: false, pickup: false, info_1: nil, info_2: nil, info_3: nil, info_4: nil, info_5: nil, del: false, place: nil, contact: false>
got: #<News id: 1, title: "news_title_1", contents: "news_contents_1", display: nil, created_at: "2012-11-29 07:24:49", updated_at: "2012-11-29 07:24:49", news_date: nil, orion: false, pw: false, op: false, pickup: false, info_1: nil, info_2: nil, info_3: nil, info_4: nil, info_5: nil, del: false, place: nil, contact: false>
(compared using ==)
Diff:#<News:0x000001030b55c8>.==(#<News:0x000001033126b8>) returned false even though the diff between #<News:0x000001030b55c8> and #<News:0x000001033126b8> is empty. Check the implementation of #<News:0x000001030b55c8>.==.
# ./spec/controllers/news_controller_spec.rb:73:in `block (3 levels) in <top (required)>'
I think these values are same, but object id is different.
So this test fails...
How do I solve this error?
Had this problem myself. My workaround was comparing the attributes, i.e.
it { assigns(:news).attributes.should eq(News.last.attributes) }
I think the problem here is how the 'eq' does the comparison between two objects. you might want to use == in this scenario. You can see a detailed explanation in this question here
you should do as follow
require 'spec_helper'
describe NewsController do
describe "GET 'edit'" do
before(:each) do
#news_1 = FactoryGirl.create(:news_1)
get :edit, { :id => #news_1.id }
end
it { response.should be_success }
it { assigns(:news).should eq(News.last) }
it { response.should render_template(:edit) }
end
end
== and eq are different. To test your method when it retrieves the object, then use should == or its equivalent a.should eql
I had this problem comparing an array and I solved it with:
expect(assigns(:receipts)).to match_array(receipts)

Rails 3 routing error with namespace and uncountable noun together

Well this is my first time doing this. In routes.rb I have the following:
namespace :admin do
resources :news
end
And I have this after rake routes:
admin_news_index GET /admin/news(.:format) admin/news#index
POST /admin/news(.:format) admin/news#create
new_admin_news GET /admin/news/new(.:format) admin/news#new
edit_admin_news GET /admin/news/:id/edit(.:format) admin/news#edit
admin_news GET /admin/news/:id(.:format) admin/news#show
PUT /admin/news/:id(.:format) admin/news#update
DELETE /admin/news/:id(.:format) admin/news#destroy
As you can see the path to the action "new" is new_admin_news_path, unfortunately, when I visited that path, something pop up as follow:
No route matches {:action=>"show", :controller=>"admin/news", :id=>#<News id: nil, news_type_id: nil, title: nil, content: nil, views: nil, status: nil, start_date: nil, end_date: nil, created_at: nil, updated_at: nil, news_key: nil>}
I was thinking that the "news" is an uncountable noun and this might be the problem. So I change the config/initializers/inflections.rb to:
ActiveSupport::Inflector.inflections do |inflect|
inflect.uncountable %w( fish sheep news )
end
Obviously, it is not working...
What should I do? Any suggestions?

Rspec and Capybara object matching

Using Rails 3.0.5, RSpec 2 and Capybara 0.4.1.2 and I'am trying to write a controller spec for my SessionsController#new action.
it "assigns the empty session to a variable" do
get :new
assigns(:session).should == ActiveRecord::Base::Session.new
end
I'm using the ActiveRecord::Base namespace as it seems to clash with the Capybara Session class when I don't.
Here is the SessionsController:
class SessionsController < ApplicationController
def new
#session = Session.new
end
end
RSpec doesn't seem to understand these are the same objects. Here is what my test returns:
Failure/Error: assigns(:session).should == ActiveRecord::Base::Session.new
expected: #<Session id: nil, session_id: nil, data: nil, created_at: nil, updated_at: nil>
got: #<Session id: nil, session_id: nil, data: nil, created_at: nil, updated_at: nil> (using ==)
Diff:
# ./spec/controllers/sessions_controller_spec.rb:17:in `block (3 levels) in <top (required)>'
Any hints?
The problem is that if you do
ActiveRecord::Base::Session.new == ActiveRecord::Base::Session.new
You would get false, as both these objects have a separate object_id.
Try this:
assigns(:session).should be_an(ActiveRecord::Base::Session)