i have used devise in rspec testing. this is my test
describe BooksController do
before(:all) do
#user = FactoryGirl.create(:user)
end
describe "GET index" do
it "shows list of current user books" do
sign_in #user
book = #user.books.create!(:title => "user")
get :index, {}
assigns(:books).should eq(#user.books)
end
end
describe "GET show" do
it "assigns the requested book as #book" do
sign_in #user
book = #user.books.create!(:title => "user")
visit_count = book.visits.to_i
get :show, {:id => book.to_param}
assigns(:book).should eq(book)
book = Book.find(book.id)
visit_count.should_not eq(book.visits)
end
end
describe "GET new" do
it "assigns a new book as #book" do
sign_in #user
get :new, {}
assigns(:book).should be_a_new(Book)
end
end
end
factory
FactoryGirl.define do
factory :user do
sequence(:email) { |n| "foo#{n}#example.com" }
password '12345678'
password_confirmation '12345678'
confirmed_at Time.now
end
end
book controller
class BooksController < ApplicationController
before_action :authenticate_user!, only: [:index, :edit, :update, :destroy, :new, :my_books, :add_wish_list]
# GET /books
# GET /books.json
def index
#books = current_user.books
end
# GET /books/1
# GET /books/1.json
def show
#book = Book.find(params[:id])
#book.book_visit_count
if(session["warden.user.user.key"].present?)
#book.book_visit_user(session["warden.user.user.key"][0][0])
end
end
# GET /books/new
def new
#book = Book.new
end
end
error
Failure/Error: assigns(:book).should be_a_new(Book)
expected nil to be a new Book(id: integer, title: string, author: string, isbn_10: string, isbn_13: string, edition: integer, print: integer, publication_year: integer, publication_month: string, condition: string, value: integer, status: boolean, stage: integer, description: text, visits: integer, user_id: integer, prefered_place: string, prefered_time: string, created_at: datetime, updated_at: datetime, rating: integer, image: string, publisher: string, goodreads_id: string)
# ./spec/controllers/books_controller_spec.rb:66:in `block (3 levels) in <top (required)>'
the problem is the third test "get new" fails when i run the test as a whole but passes when i run it individually. and also if i remove the before_authenticate! in controller then all test passes.
Again if i commented out the "assigns" in first two describe blocks then all tests pass again.
i am using rails 4.0.2 and rspec 2.14.7 , devise 3.2.2
The only thing I can figure is that your authenticate_user method is failing for users that have previously been authenticated. It's not affecting show because you don't have :show listed in your before_action. You could test this theory by requiring authentication for show as well and seeing if your second example starts failing for before(:all) as well.
Related
1) I have this model Job and the model institution
class Job < ApplicationRecord
belongs_to :institution
# others attibutes
end
2) This is my action create on JobsController - I need a institution to create a job. it is fine.
def create
build_job
save_job || render(:new, status: :unprocessable_entity)
end
3) This is the integration test that I created
I am not getting the success test
In params
-I also tried institution: #institution
-and also tried institution_id: #institution.id
require 'test_helper'
class JobActionsTest < ActionDispatch::IntegrationTest
setup do
#user = users(:standard)
sign_in #user
#institution = institutions(:standard)
end
test "can create a job through institution" do
get new_institution_job_path(#institution)
assert_response :success
assert_difference('Job.count') do
post jobs_path,
params: {job: {title: "Desenvolvedor", description: "Ruby",
requirements: "rspec and capybara",
start_date: Date.today,
end_date: Date.today + 5.days,
institution: #institution.id}}
end
assert_response :redirect
follow_redirect!
assert_response :success
end
end
4) And this is my console error
#Running:
E
Error:
JobActionsTest#test_can_create_a_job_through_institution:
ActiveRecord::RecordNotFound: Couldn't find Institution with 'id'=
app/controllers/jobs_controller.rb:74:in `job_scope'
app/controllers/jobs_controller.rb:52:in `build_job'
app/controllers/jobs_controller.rb:18:in `create'
test/integration/job_actions_test.rb:22:in `block (2 levels) in <class:JobActionsTest>'
test/integration/job_actions_test.rb:21:in `block in <class:JobActionsTest>'
bin/rails test test/integration/job_actions_test.rb:17
Start by nesting the jobs resource properly:
resources :institutions do
resources :jobs, only: [:new, :create]
end
# or to create the full suite
resources :institutions do
resources :jobs, shallow: true
end
This will give these routes:
Prefix Verb URI Pattern Controller#Action
institution_jobs POST /institutions/:institution_id/jobs(.:format) jobs#create
new_institution_job GET /institutions/:institution_id/jobs/new(.:format) jobs#new
...
Note that :institution_id is a now a part of URI pattern for the create route, and it will be available as params[:institution_id].
In your test you want to POST to /institutions/:institution_id/jobs:
require 'test_helper'
class JobActionsTest < ActionDispatch::IntegrationTest
setup do
#user = users(:standard)
sign_in #user
#institution = institutions(:standard)
end
# Use separate examples per route / case
test "can fill in form to create a new job" do
get new_institution_job_path(#institution)
assert_response :success
end
test "can create a job through institution" do
assert_difference ->{ #institution.jobs.count } do
post institution_jobs_path(#institution),
params: {
job: {
title: "Desenvolvedor",
description: "Ruby",
requirements: "rspec and capybara",
start_date: Date.today,
end_date: Date.today + 5.days
}
}
end
assert_redirected_to #institution.jobs.last
follow_redirect!
assert_response :success
end
end
Further you want to test that the job actually was created for the right institution. We do that by passing the lambda ->{ #institution.jobs.count }.
And that the users are redirected to the correct resource - not just somewhere - which is done with assert_redirected_to #institution.jobs.last.
It looks like that when you call at line 22
get new_institution_job_path(#institution)
the #institution object you have built in the setup block is not saved in the database.
The error you are receiving, ActiveRecord::RecordNotFound, says that it cannot be found an Institution with id nil.
You can easily check if I am guessing correctly by adding this assertion:
test "can create a job through institution" do
assert_not_nil(#institution.id) # or assert_not_equal(0, Institution.where(id: #institution.id).size)
get new_institution_job_path(#institution)
assert_response :success
#...
end
Make sure that your institutions(:standard) method looks like Institution.create!() and not like Institution.new or Institution.build
I'm following this tutorial for a rails API but it is a little outdated and some things don't seem to work with newer versions of rails. I'm having a hard time with the user controller specs:
user_controller_spec.rb
require 'rails_helper'
RSpec.describe Api::V1::UsersController, type: :controller do
describe "GET #show" do
before(:each) do
#user = FactoryGirl.create :user
get :show, params: {id: #user.id}
end
it "returns the information about a reporter on a hash" do
user_response = JSON.parse(response.body, symbolize_name: true)
expect(user_response[:email]).to eql #user.email
end
it { expect(response).to have_http_status(200) }
end
end
user_controller.rb
class Api::V1::UsersController < ApplicationController
def show
render json: User.find(params[:id])
end
end
user.rb factory
FactoryGirl.define do
factory :user do
email { FFaker::Internet.email }
password "12345678"
password_confirmation "12345678"
end
end
But, this isn't working, the email doesn't seem to match. Any ideas what could be wrong?
Failures:
1) Api::V1::UsersController GET #show returns the information about a reporter on a hash
Failure/Error: expect(user_response[:email]).to eql #user.email
expected: "mitzie_nikolaus#rice.com"
got: nil
(compared using eql?)
# ./spec/controllers/api/v1/users_controller_spec.rb:12:in `block (3 levels) in <top (required)>'
The code is correct, but you've made a typo in using the symbolize_names option for JSON.parse.
I assume, that because you do not copy-paste examples, but type it by your own, which is great, because it's better for learning.
To fix the test just correct this line (change symbolize_name to symbolize_names):
user_response = JSON.parse(response.body, symbolize_names: true)
Hello Programmers & Developers!!!, I'm a beginner in RoR and creating a simple project in rails to learn its working, so in that project I'm facing a problem in writing a spec for the create method of controller. When I'm trying to pass the associate attributes of the object in spec file, in controller it isn't get all the attributes.
In the create method of subjects_controller.rb file.I've created a variable called attr in this variable I'm storing all the values sent from subjects_controller_spec.rb file.
attr=(params.require(:subject).permit(:name)).merge(:classroom_ids=>params[:subject][:classroom_ids],:school_ids=>params[:subject][:school_ids])
Now, If I print the value of the attr using p attr in console it's output is the exact output that I want, which is
{"name"=>"Computer", "classroom_ids"=>["1", "2"], "school_ids"=>["1"]}
But, now I'm doing #subject = Subject.new(attr) and printing value of #subject gives the following output
#<Subject id: nil, name: "Computer", created_at: nil, updated_at: nil>
and after running the test I'm getting my test failed and then I printed the error p #subject.errors it gave me the below output
#<ActiveModel::Errors:0x007fc35444a218 #base=#<Subject id: nil, name: "Computer", created_at: nil, updated_at: nil>, #messages={:school_ids=>["is not a number"], :classroom_ids=>["is not a number"]}>
So, here is my actual question is why #subject in subjects_controller.rb is not having values of classroom_ids and school_ids? If any solution or suggestion is there then please help me to sort out this problem.
Below I'm providing you all the necessary details to understand the actual problem.
Ruby Version 2.2.4
Rails Version 4.2.0
Database MySQL
Model file subject.rb
class Subject < ActiveRecord::Base
has_and_belongs_to_many :schools
has_and_belongs_to_many :teachers
has_and_belongs_to_many :classrooms
has_and_belongs_to_many :students
validates_presence_of :name, :school_ids, :classroom_ids
validates_numericality_of :school_ids, :classroom_ids
end
Controller file subjects_controller_spec.rb
require 'rails_helper'
RSpec.describe SubjectsController, type: :controller do
before(:each) do
#school1 = FactoryGirl.create(:school)
#classroom1 = FactoryGirl.create(:classroom, :school_id=>#school1.id)
#classroom2 = FactoryGirl.create(:classroom, :school_id=>#school1.id)
#subject = FactoryGirl.build(:subject)
#subject.classrooms<<#classroom1
#subject.classrooms<<#classroom2
#subject.schools<<#school1
end
context "POST create" do
it "should be success" do
# p #subject
# p #subject.classrooms
# p #subject.classroom_ids
attributes=#subject.attributes.merge(:classroom_ids=>#subject.classroom_ids,:school_ids=>#subject.school_ids)
# In below line, I'm sending all the values to the controller to create a new subject.
post :create, :subject=>attributes
response.status.should eq 201
end
end
end
Controller file subjects_controller.rb
class SubjectsController < ApplicationController
before_action :set_subject, only: [:show, :edit, :update, :destroy]
# GET /subjects
def index
#subjects = Subject.all
end
# GET /subjects/1
def show
end
# GET /subjects/new
def new
#subject = Subject.new
end
# GET /subjects/1/edit
def edit
end
# POST /subjects
def create
attr=(params.require(:subject).permit(:name)).merge(:classroom_ids=>params[:subject][:classroom_ids],:school_ids=>params[:subject][:school_ids])
p attr ### here it prints all the values which I want to create subject.###
#subject = Subject.new(attr)
p #subject ### here is the actual problem, It's not printing all the values that need to create a new subject.###
if #subject.save
redirect_to #subject, notice: 'Subject was successfully created.', status: :created
else
p #subject.errors
render :new, status: :unprocessable_entity
end
end
# PATCH/PUT /subjects/1
def update
if #subject.update(subject_params)
redirect_to #subject, notice: 'Subject was successfully updated.', status: :ok
else
render :edit, :status => :unprocessable_entity
end
end
# DELETE /subjects/1
def destroy
#subject.destroy
redirect_to subjects_url, notice: 'Subject was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_subject
#subject = Subject.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def subject_params
params.require(:subject).permit(:name, :school_ids, :classroom_ids)
end
end
Factory file subjects.rb
FactoryGirl.define do
factory :subject do
name "Computer"
end
end
RSpec Test Report
rspec spec/controllers/subjects_controller_spec.rb
{"name"=>"Computer", "classroom_ids"=>["1", "2"], "school_ids"=>["1"]}
#<Subject id: nil, name: "Computer", created_at: nil, updated_at: nil>
#<ActiveModel::Errors:0x007fcdfe8f1a28 #base=#<Subject id: nil, name: "Computer", created_at: nil, updated_at: nil>, #messages={:school_ids=>["is not a number"], :classroom_ids=>["is not a number"]}>
F
Failures:
1) SubjectsController POST create should be success
Failure/Error: response.status.should eq 201
expected: 201
got: 422
(compared using ==)
# ./spec/controllers/subjects_controller_spec.rb:21:in `block (3 levels) in <top (required)>'
Deprecation Warnings:
Using `should` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax is deprecated. Use the new `:expect` syntax or explicitly enable `:should` with `config.expect_with(:rspec) { |c| c.syntax = :should }` instead. Called from /Users/vishal/project/school_system/spec/controllers/subjects_controller_spec.rb:21:in `block (3 levels) in <top (required)>'.
If you need more of the backtrace for any of these deprecations to
identify where to make the necessary changes, you can configure
`config.raise_errors_for_deprecations!`, and it will turn the
deprecation warnings into errors, giving you the full backtrace.
1 deprecation warning total
Finished in 0.40113 seconds (files took 3.03 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/controllers/subjects_controller_spec.rb:14 # SubjectsController POST create should be success
Coverage report generated for RSpec to /Users/vishal/project/school_system/coverage. 49 / 332 LOC (14.76%) covered.
For more details you can refer this Github link.
Thanks For Help In Advance.
[ "1", "2" ] is not array of integer but String! #subject has classroom_ids and school_ids, but params always treat input values as String, so validation error occurs in your Subject model. So try below to transform String to Integer:
params[:subject][:classroom_ids].map(&:to_i)
params[:subject][:school_ids].map(&:to_i)
How about this?
restore below without map method in the controller:
params[:subject][:classroom_ids]
params[:subject][:school_ids]
In my PC, by modifing the Subject model as below from your github link and passed the test.
Could you try this?
Class Subject < ActiveRecord::Base
has_and_belongs_to_many :schools
has_and_belongs_to_many :teachers
has_and_belongs_to_many :classrooms
has_and_belongs_to_many :students
validates_presence_of :name, :school_ids, :classroom_ids
validate :validate_classroom_ids
validate :validate_school_ids
private
def validate_classroom_ids
if classroom_ids.any?{ |id| !id.is_a?(Integer) }
errors.add(:classroom_ids, 'is not a number')
return false
end
end
def validate_school_ids
if school_ids.any?{ |id| !id.is_a?(Integer) }
errors.add(:school_ids, 'is not a number')
return false
end
end
end
I'm trying to write a simple RSpec test for "UsersController" that tests the index method.
The code for the controller index method looks as follows:
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
I am trying to test that the "all" method is called and that the index view is rendered. Here is my Rspec code for that:
require 'spec_helper'
describe UsersController do
describe 'get index', :type => :controller do
before :each do
#fake_users = [double('user1'), double('user2')]
end
it 'should call the model method that retrieves all Users' do
User.should_receive(:all).once.and_return(#fake_users)
get :index
end
describe 'after valid search' do
before :each do
User.stub(:all).and_return(#fake_users)
get :index
end
it 'should select the index template for rendering' do
response.should render_template('index')
end
it 'should make the users results available to that template' do
assigns(:users).should == #fake_users
end
end
end
end
However, this fails the "get index" test with the following message:
Failure/Error: User.should_receive(:all).once.and_return(#fake_users)
(<User(id: integer, firstname: string, lastname: string, username: string, email: string, password_digest: string, created_at: datetime, updated_at: datetime) (class)>).all(any args)
expected: 1 time with any arguments
received: 0 times with any arguments
# ./spec/controllers/users_controller_spec.rb:9:in `block (3 levels) in <top (required)>'
Can anyone shed any light on what I'm doing wrong?
The problem was caused by the UsersController requiring a log in first. So the controller looked like:
class UsersController < AuthenticatedController
So the path wasn't accessible to RSpec.
I am following Michael Hartl's Ruby on Rails tutorial and I am not sure why I am getting this Error when according to the tutorial everything should pass:
1) Error:
UsersControllerTest#test_should_get_show:
ActiveRecord::RecordNotFound: Couldn't find User with 'id'=
app/controllers/users_controller.rb:7:in `show'
test/controllers/users_controller_test.rb:10:in `block in <class:UsersControllerTest>'
My minitest:
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
# add invalid information and test that the User.count never changes
# also test that the sign up path is visited after invalid sign up
test "invalid signup information" do
# visit the signup path using get
get signup_path
assert_no_difference "User.count" do
post users_path, user: { name: "", email: "user#invalid", password: "foo", password_confirmation: "bar"}
end
assert_template "users/new"
end
end
I compared my users_controller to the official github tutorial and it looks the same
Users controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
# strong parameters
#user = User.new(user_params)
if #user.save
# handle save
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
I dont really understand why id is being searched for as well. My database is empty with no users. I am currently testing that inputing invalid parameters for sign up will not add another user.
my UserControllerTest:
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
test "should get new" do
get :new
assert_response :success
end
test "should get show" do
get :show
assert_response :success
end
end
Show renders a page for specific user, so you need to pass it the id param. Change the test to:
test "should get show" do
user = User.create
get :show, id: user.id
assert_response :success
end
FYI, A small breakdown of the error message:
1) Error:
Error
UsersControllerTest#test_should_get_show:
In test test_should_get_show in class UserControllerTest
ActiveRecord::RecordNotFound: Couldn't find User with 'id'=
Database doesn't contain User object with empty id
app/controllers/users_controller.rb:7:in `show'
File and line that directly caused the error
test/controllers/users_controller_test.rb:10:in `block in <class:UsersControllerTest>'
File and line where the action originated from.