Im having difficulties with writing a spec for an index action of a controller im trying to test. The controller looks like this:
class MyGamesResultsController < ApplicationController
def index
#contest = Contest.find(params[:contest_id])
#my_entry = current_user.entries.where(contest_id: params[:contest_id])
#points_per_player = #my_entry[0].points_per_player
#total_points = #my_entry[0].total_points
end
end
and my spec looks like this:
require 'rails_helper'
RSpec.describe MyGamesResultsController, type: :controller do
describe 'GET /index' do
let!(:user) { create(:user) }
before :each do
sign_in user
get :index
end
it 'renders the index template' do
expect(subject).to render_template(:index)
end
end
end
The error that the spec returns says this:
Failure/Error: get :index
ActiveRecord::RecordNotFound:
Couldn't find Contest with 'id'=
Can anyone figure out what is wrong?
Solved it! had to do this:
require 'rails_helper'
RSpec.describe MyGamesResultsController, type: :controller do
describe "GET index" do
let!(:user) { create(:user) }
let!(:contest) { create(:contest) }
let!(:my_entry) { create(:entry, user_id: user.id, contest_id: contest.id) }
before :each do
sign_in user
get :index, contest_id: contest.id
end
it "renders the index template" do
(expect (response.status)).to eql(200)
end
end
end
Related
How can I double #user var, if I do not double it, the test will throw error of
call update_attributes of nil:NilClass
class TestController
def foo!
#user = current_user
#user.update_attribute(user_params)
end
end
RSpec.describe TestController, type: :controller do
describe "#foo" do
it "should be passed" do
#specific_user = FactoryGirl.create(:user)
allow_any_instance_of(TestController).to receive(:foo!).and_return(true)
allow_any_instance_of(TestController).to receive(#user).and_return(#specific_user)
end
end
end
The problem with your test is that it doesn't test anything. The controller test should make a request to test the method get :foo!
About stubbing, in your case current_user method can be stubbed instead:
RSpec.describe TestController, type: :controller do
describe "#foo" do
it "should be passed" do
#specific_user = FactoryGirl.create(:user)
allow(controller).to receive(:foo!).and_return(true)
allow(controller).to receive(:current_user).and_return(#specific_user)
end
end
end
And yeah, in the controller test the controller instance can be accessed by calling controller method.
What also allows to set an instance variable in this controller:
RSpec.describe TestController, type: :controller do
describe "#foo" do
it "should be passed" do
#specific_user = FactoryGirl.create(:user)
allow(controller).to receive(:foo!).and_return(true)
controller.instance_variable_set(:#user, #specific_user)
end
end
end
My controller and my test file are bellow.
controllers/reports_controller.rb:
def index
#reports = Report.all
end
specs/controllers/reports_controller_spec.rb:
RSpec.describe ReportsController, type: :controller do
let(:test_report) {
2.times.map {
create(:report, student: create(:student), report_options_attributes: [
{option: create(:option), note: "ole" }
])
}
}
describe "GET #index" do
before(:each) do
get :index
end
it "should be success" do
expect(response).to be_success
end
it "should render index template" do
expect(response).to render_template(:index)
end
it "should load all reports" do
expect(assigns(:report)).to match_array test_report
end
end
The last test is not working, but it should work. What is wrong with it?
index test is empty..you need to assert something to pass.
can you add.. assert_response :success in index function.
Your var is different from the controller. Use reports instead of report like this:
it "should load all reports" do
expect(assigns(:reports)).to match_array test_report
end
It should work.
I tried to write some tests for the "show" action in Rails API
require 'rails_helper'
RSpec.describe AirlinesController, type: :controller do
describe "GET #show" do
before(:each) do
#airline = FactoryGirl.create(:airline)
get :show, id: #airline.id
end
it "should return the airline information" do
airline_response = json_response
expect(airline_response[:name]).to eql #airline.name
end
it {should respond_with :ok}
end
end
The test passed. However, when I try to use let and subject like this
require 'rails_helper'
RSpec.describe AirlinesController, type: :controller do
describe "GET #show" do
let(:airline) {FactoryGirl.create(:airline)}
subject {airline}
before(:each) do
get :show, id: airline.id
end
it "should return the airline information" do
airline_response = json_response
expect(airline_response[:name]).to eql airline.name
end
it {should respond_with :ok}
end
end
It showed "NoMethodError undefined method `response' for ..."
This makes me confused!
Don't set the subject. The subject of a controller spec is the controller, not a model object. Just remove the line that sets subject and you shouldn't get that error any more.
it {should respond_with :ok}
I assume this line takes the subject and makes a response call.
The recommended syntax is:
it "returns 200" do
expect(response).to be_success
end
Or maybe your json_response helper method is using subject.response instead of response.
I'm using devise + rspec + factory + shoulda and having trouble with my controller specs. I've read a bunch of articles and docs but couldn't figure out what the best way is to log_in the user and use that user instance.
Task is nested under user so index route is /users/:user_id/tasks and task belongs_to :assigner, class_name: "User" and belongs_to :executor, class_name: "User"
At the moment with following code both tests fail. What is the best approach for properly sign_in the user and use it in the controller tests?
The error message for the first one:
Failure/Error: expect(assigns(:tasks)).to eq([assigned_task, executed_task])
expected: [#<Task id: 1, assigner_id: 1, executor_id: 2, .....>, #<Task id: 2, assigner_id: 3, executor_id: 1, ......>]
got: nil
(compared using ==)
The error for the second one:
Failure/Error: it { is_expected.to respond_with :ok }
Expected response to be a 200, but was 302
tasks_controller_spec.rb
require "rails_helper"
describe TasksController do
describe "when user is signed in" do
describe "collections" do
login_user
let(:assigned_task) { create(:task, assigner: #user) }
let(:executed_task) { create(:task, executor: #user) }
let(:other_task) { create(:task) }
context "GET index" do
before do
get :index, user_id: #user.id
end
it "assigns user's tasks" do
expect(assigns(:tasks)).to eq([assigned_task, executed_task])
end
it { is_expected.to respond_with :ok }
end
context "GET incoming_tasks"
end
end
end
controller_macros.rb
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#user = create(:user)
sign_in #user
end
end
end
tasks controller
def index
#tasks = Task.alltasks(current_user).uncompleted.includes(:executor, :assigner).order("deadline DESC").paginate(page: params[:page], per_page: Task.pagination_per_page)
end
Add following line in rails_helper.
config.include ControllerMacros, :type => :controller
SEE this thread.
I am assuming this only fails in rspec. When you test in browser it works fine.
I seem to be stuck. I am trying to shore up some rspec testing and want to make sure the the correct before_filter methods are getting called for controllers. However, I am getting feedback saying the method never gets called.
The error:
Failure/Error: expect(controller).to receive(:authorize)
(#<UsersController:0x007fca2fd27110>).authorize(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
The spec:
require "rails_helper"
RSpec.describe UsersController, :type => :controller do
let(:school){ FactoryGirl.create :school }
let(:user){ FactoryGirl.create :teacher}
before(:each){
allow(controller).to receive(:current_user).and_return(user)
school.teachers << user
}
context "Get #show" do
before(:each){ get :show, school_id: school.id, id: user.id }
it "responds successfully with an HTTP 200 status code" do
expect(controller).to receive(:authorize)
expect(response).to have_http_status(200)
end
it "renders the show template" do
expect(response).to render_template("show")
end
end
end
The controller:
class UsersController < ApplicationController
before_filter :authorize
def show
#user = User.find_by_id params[:id]
#school = #user.school
#coordinators = #school.coordinators
#teachers = #school.teachers
#speducators = #school.speducators
#students = #school.students
end
end
Manual testing shows that before is being called, and when I put a p in the authorize method it is called when I run the test, any thoughts on where the test is going wrong?
You must set method expectation before actual call, so your test should look like:
context "Get #show" do
subject { get :show, school_id: school.id, id: user.id }
it "calls +authorize+ befor action" do
expect(controller).to receive(:authorize)
subject
end
end
Check the documentation https://github.com/rspec/rspec-mocks#message-expectations